+void InsetText::forOutliner(docstring & os, size_t const maxlen,
+ bool const shorten) const
+{
+ if (!getLayout().isInToc())
+ return;
+ text().forOutliner(os, maxlen, shorten);
+}
+
+
+void InsetText::addToToc(DocIterator const & cdit, bool output_active,
+ UpdateType utype, TocBackend & backend) const
+{
+ DocIterator dit = cdit;
+ dit.push_back(CursorSlice(const_cast<InsetText &>(*this)));
+ iterateForToc(dit, output_active, utype, backend);
+}
+
+
+void InsetText::iterateForToc(DocIterator const & cdit, bool output_active,
+ UpdateType utype, TocBackend & backend) const
+{
+ DocIterator dit = cdit;
+ // This also ensures that any document has a table of contents
+ shared_ptr<Toc> toc = backend.toc("tableofcontents");
+
+ BufferParams const & bufparams = buffer_->params();
+ int const min_toclevel = bufparams.documentClass().min_toclevel();
+ // we really should have done this before we got here, but it
+ // can't hurt too much to do it again
+ bool const doing_output = output_active && producesOutput();
+
+ // For each paragraph,
+ // * Add a toc item for the paragraph if it is AddToToc--merging adjacent
+ // paragraphs as needed.
+ // * Traverse its insets and let them add their toc items
+ // * Compute the main table of contents (this is hardcoded)
+ // * Add the list of changes
+ ParagraphList const & pars = paragraphs();
+ pit_type pend = paragraphs().size();
+ // Record pairs {start,end} of where a toc item was opened for a paragraph
+ // and where it must be closed
+ stack<pair<pit_type, pit_type>> addtotoc_stack;
+
+ for (pit_type pit = 0; pit != pend; ++pit) {
+ Paragraph const & par = pars[pit];
+ dit.pit() = pit;
+ dit.pos() = 0;
+
+ // Custom AddToToc in paragraph layouts (i.e. theorems)
+ if (par.layout().addToToc() && text().isFirstInSequence(pit)) {
+ pit_type end =
+ openAddToTocForParagraph(pit, dit, output_active, backend);
+ addtotoc_stack.push({pit, end});
+ }
+
+ // if we find an optarg, we'll save it for use later.
+ InsetArgument const * arginset = nullptr;
+ for (auto const & table : par.insetList()) {
+ dit.pos() = table.pos;
+ table.inset->addToToc(dit, doing_output, utype, backend);
+ if (InsetArgument const * x = table.inset->asInsetArgument())
+ arginset = x;
+ }
+
+ // End custom AddToToc in paragraph layouts
+ while (!addtotoc_stack.empty() && addtotoc_stack.top().second == pit) {
+ // execute the closing function
+ closeAddToTocForParagraph(addtotoc_stack.top().first,
+ addtotoc_stack.top().second, backend);
+ addtotoc_stack.pop();
+ }
+
+ // now the toc entry for the paragraph in the main table of contents
+ int const toclevel = text().getTocLevel(pit);
+ if (toclevel != Layout::NOT_IN_TOC && toclevel >= min_toclevel) {
+ // insert this into the table of contents
+ docstring tocstring;
+ int const length = (doing_output && utype == OutputUpdate) ?
+ INT_MAX : TOC_ENTRY_LENGTH;
+ if (arginset) {
+ tocstring = par.labelString();
+ if (!tocstring.empty())
+ tocstring += ' ';
+ arginset->text().forOutliner(tocstring, length);
+ } else
+ par.forOutliner(tocstring, length);
+ dit.pos() = 0;
+ toc->push_back(TocItem(dit, toclevel - min_toclevel,
+ tocstring, doing_output));
+ }
+
+ // And now the list of changes.
+ par.addChangesToToc(dit, buffer(), doing_output, backend);
+ }
+}
+
+
+pit_type InsetText::openAddToTocForParagraph(pit_type pit,
+ DocIterator const & dit,
+ bool output_active,
+ TocBackend & backend) const
+{
+ Paragraph const & par = paragraphs()[pit];
+ TocBuilder & b = backend.builder(par.layout().tocType());
+ docstring const label = par.labelString();
+ b.pushItem(dit, label + (label.empty() ? "" : " "), output_active);
+ return text().lastInSequence(pit);
+}
+
+
+void InsetText::closeAddToTocForParagraph(pit_type start, pit_type end,
+ TocBackend & backend) const
+{
+ Paragraph const & par = paragraphs()[start];
+ TocBuilder & b = backend.builder(par.layout().tocType());
+ if (par.layout().isTocCaption()) {
+ docstring str;
+ text().forOutliner(str, TOC_ENTRY_LENGTH, start, end);
+ b.argumentItem(str);
+ }
+ b.pop();
+}
+
+
+bool InsetText::notifyCursorLeaves(Cursor const & old, Cursor & cur)
+{
+ if (buffer().isClean())
+ return Inset::notifyCursorLeaves(old, cur);
+
+ // find text inset in old cursor
+ Cursor insetCur = old;
+ int scriptSlice = insetCur.find(this);
+ // we can try to continue here. returning true means
+ // the cursor is "now" invalid. which it was.
+ LASSERT(scriptSlice != -1, return true);
+ insetCur.cutOff(scriptSlice);
+ LASSERT(&insetCur.inset() == this, return true);
+
+ // update the old paragraph's words
+ insetCur.paragraph().updateWords();
+
+ return Inset::notifyCursorLeaves(old, cur);
+}
+
+
+bool InsetText::completionSupported(Cursor const & cur) const
+{
+ //LASSERT(&cur.bv().cursor().inset() == this, return false);
+ return text_.completionSupported(cur);
+}
+
+
+bool InsetText::inlineCompletionSupported(Cursor const & cur) const
+{
+ return completionSupported(cur);
+}
+
+
+bool InsetText::automaticInlineCompletion() const
+{
+ return lyxrc.completion_inline_text;
+}
+
+
+bool InsetText::automaticPopupCompletion() const
+{
+ return lyxrc.completion_popup_text;
+}
+
+
+bool InsetText::showCompletionCursor() const
+{
+ return lyxrc.completion_cursor_text;
+}
+
+
+CompletionList const * InsetText::createCompletionList(Cursor const & cur) const
+{
+ return completionSupported(cur) ? text_.createCompletionList(cur) : 0;
+}
+
+
+docstring InsetText::completionPrefix(Cursor const & cur) const
+{
+ if (!completionSupported(cur))
+ return docstring();
+ return text_.completionPrefix(cur);
+}
+
+
+bool InsetText::insertCompletion(Cursor & cur, docstring const & s,
+ bool finished)
+{
+ if (!completionSupported(cur))
+ return false;
+
+ return text_.insertCompletion(cur, s, finished);
+}
+
+
+void InsetText::completionPosAndDim(Cursor const & cur, int & x, int & y,
+ Dimension & dim) const
+{
+ TextMetrics const & tm = cur.bv().textMetrics(&text_);
+ tm.completionPosAndDim(cur, x, y, dim);
+}
+
+
+string InsetText::contextMenu(BufferView const &, int, int) const
+{
+ string context_menu = contextMenuName();
+ if (context_menu != InsetText::contextMenuName())
+ context_menu += ";" + InsetText::contextMenuName();
+ return context_menu;
+}
+
+
+string InsetText::contextMenuName() const
+{
+ return "context-edit";
+}
+
+
+docstring InsetText::toolTipText(docstring prefix, size_t const len) const
+{
+ OutputParams rp(&buffer().params().encoding());
+ rp.for_tooltip = true;
+ odocstringstream oss;
+ oss << prefix;
+
+ ParagraphList::const_iterator beg = paragraphs().begin();
+ ParagraphList::const_iterator end = paragraphs().end();
+ ParagraphList::const_iterator it = beg;
+ bool ref_printed = false;
+
+ for (; it != end; ++it) {
+ if (it != beg)
+ oss << '\n';
+ writePlaintextParagraph(buffer(), *it, oss, rp, ref_printed, len);
+ if (oss.tellp() >= 0 && size_t(oss.tellp()) > len)
+ break;
+ }
+ docstring str = oss.str();
+ support::truncateWithEllipsis(str, len);
+ return str;
+}
+
+
+InsetText::XHTMLOptions operator|(InsetText::XHTMLOptions a1, InsetText::XHTMLOptions a2)
+{
+ return static_cast<InsetText::XHTMLOptions>((int)a1 | (int)a2);
+}
+