+///////////////////////////////////////////////////////////////////////////
+//
+// TocBuilder implementation
+//
+///////////////////////////////////////////////////////////////////////////
+
+TocBuilder::TocBuilder(shared_ptr<Toc> toc)
+ : toc_(toc ? toc : make_shared<Toc>()),
+ stack_()
+{
+ LATTEST(toc);
+}
+
+void TocBuilder::pushItem(DocIterator const & dit, docstring const & s,
+ bool output_active, bool is_captioned)
+{
+ toc_->push_back(TocItem(dit, stack_.size(), s, output_active));
+ frame f = {
+ toc_->size() - 1, //pos
+ is_captioned, //is_captioned
+ };
+ stack_.push(f);
+}
+
+void TocBuilder::captionItem(DocIterator const & dit, docstring const & s,
+ bool output_active)
+{
+ // first show the float before moving to the caption
+ docstring arg = "paragraph-goto " + paragraph_goto_arg(dit);
+ if (!stack_.empty())
+ arg = "paragraph-goto " +
+ paragraph_goto_arg((*toc_)[stack_.top().pos].dit_) + ";" + arg;
+ FuncRequest func(LFUN_COMMAND_SEQUENCE, arg);
+
+ if (!stack_.empty() && !stack_.top().is_captioned) {
+ // The float we entered has not yet been assigned a caption.
+ // Assign the caption string to it.
+ TocItem & captionable = (*toc_)[stack_.top().pos];
+ captionable.str(s);
+ captionable.setAction(func);
+ stack_.top().is_captioned = true;
+ } else {
+ // This is a new entry.
+ pop();
+ // the dit is at the float's level, e.g. for the contextual menu of
+ // outliner entries
+ DocIterator captionable_dit = dit;
+ captionable_dit.pop_back();
+ pushItem(captionable_dit, s, output_active, true);
+ (*toc_)[stack_.top().pos].setAction(func);
+ }
+}
+
+void TocBuilder::pop()
+{
+ if (!stack_.empty())
+ stack_.pop();
+}
+
+
+