Better construction of the TOC for floats and captions

We introduce TocBuilder for building TOCs that take into account both float
insets and their captions.

* Floats without caption are shown with their content.

* Floats with a caption are shown with their caption, but clicking the entry now
  correctly moves to the float and not to the caption.

* Subsequent captions produce additional entries in the TOC.

* Figures and subfigures are correctly ordered in the outliner.

* New TOC "senseless" for captions appearing alone (a bit like broken references
are still displayed in the menu and outliner).

* Disable LFUN_CAPTION_INSERT if there is already a caption in a listing

Known issues:

* Inconsistent output for includes located inside floats

* We should record the end of the float in addition of the beginning for a more
  accurate cursor -> outliner entry conversion
This commit is contained in:
Guillaume Munch 2015-09-01 17:08:35 +01:00
parent c02f6bd8a7
commit 94e992c5ed
28 changed files with 397 additions and 238 deletions

View File

@ -1005,9 +1005,9 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf)
// FIXME We may want to collect these differently, in the first case, // FIXME We may want to collect these differently, in the first case,
// so that we might have them in order of appearance. // so that we might have them in order of appearance.
set<docstring> citekeys; set<docstring> citekeys;
Toc const & toc = buf.tocBackend().toc("citation"); shared_ptr<Toc const> toc = buf.tocBackend().toc("citation");
Toc::const_iterator it = toc.begin(); Toc::const_iterator it = toc->begin();
Toc::const_iterator const en = toc.end(); Toc::const_iterator const en = toc->end();
for (; it != en; ++it) { for (; it != en; ++it) {
if (it->str().empty()) if (it->str().empty())
continue; continue;

View File

@ -2163,9 +2163,9 @@ void Buffer::getLabelList(vector<docstring> & list) const
} }
list.clear(); list.clear();
Toc & toc = d->toc_backend.toc("label"); shared_ptr<Toc> toc = d->toc_backend.toc("label");
TocIterator toc_it = toc.begin(); TocIterator toc_it = toc->begin();
TocIterator end = toc.end(); TocIterator end = toc->end();
for (; toc_it != end; ++toc_it) { for (; toc_it != end; ++toc_it) {
if (toc_it->depth() == 0) if (toc_it->depth() == 0)
list.push_back(toc_it->str()); list.push_back(toc_it->str());
@ -4461,6 +4461,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
d->bibinfo_cache_valid_ = true; d->bibinfo_cache_valid_ = true;
d->cite_labels_valid_ = true; d->cite_labels_valid_ = true;
/// FIXME: Perf
cbuf.tocBackend().update(utype == OutputUpdate); cbuf.tocBackend().update(utype == OutputUpdate);
if (scope == UpdateMaster) if (scope == UpdateMaster)
cbuf.structureChanged(); cbuf.structureChanged();

View File

@ -2429,9 +2429,9 @@ void BufferView::gotoLabel(docstring const & label)
Buffer const * buf = *it; Buffer const * buf = *it;
// find label // find label
Toc & toc = buf->tocBackend().toc("label"); shared_ptr<Toc> toc = buf->tocBackend().toc("label");
TocIterator toc_it = toc.begin(); TocIterator toc_it = toc->begin();
TocIterator end = toc.end(); TocIterator end = toc->end();
for (; toc_it != end; ++toc_it) { for (; toc_it != end; ++toc_it) {
if (label == toc_it->str()) { if (label == toc_it->str()) {
lyx::dispatch(toc_it->action()); lyx::dispatch(toc_it->action());

View File

@ -474,7 +474,7 @@ void Changes::addToToc(DocIterator const & cdit, Buffer const & buffer,
if (table_.empty()) if (table_.empty())
return; return;
Toc & change_list = buffer.tocBackend().toc("change"); shared_ptr<Toc> change_list = buffer.tocBackend().toc("change");
AuthorList const & author_list = buffer.params().authors(); AuthorList const & author_list = buffer.params().authors();
DocIterator dit = cdit; DocIterator dit = cdit;
@ -500,18 +500,18 @@ void Changes::addToToc(DocIterator const & cdit, Buffer const & buffer,
// the end of paragraph symbol from the Punctuation group // the end of paragraph symbol from the Punctuation group
str.push_back(0x204B); str.push_back(0x204B);
docstring const & author = author_list.get(it->change.author).name(); docstring const & author = author_list.get(it->change.author).name();
Toc::iterator it = change_list.item(0, author); Toc::iterator it = change_list->item(0, author);
if (it == change_list.end()) { if (it == change_list->end()) {
change_list.push_back(TocItem(dit, 0, author, output_active)); change_list->push_back(TocItem(dit, 0, author, output_active));
change_list.push_back(TocItem(dit, 1, str, output_active, change_list->push_back(TocItem(dit, 1, str, output_active,
support::wrapParas(str, 4))); support::wrapParas(str, 4)));
continue; continue;
} }
for (++it; it != change_list.end(); ++it) { for (++it; it != change_list->end(); ++it) {
if (it->depth() == 0 && it->str() != author) if (it->depth() == 0 && it->str() != author)
break; break;
} }
change_list.insert(it, TocItem(dit, 1, str, output_active, change_list->insert(it, TocItem(dit, 1, str, output_active,
support::wrapParas(str, 4))); support::wrapParas(str, 4)));
} }
} }

View File

@ -6,6 +6,7 @@
* \author Jean-Marc Lasgouttes * \author Jean-Marc Lasgouttes
* \author Angus Leeming * \author Angus Leeming
* \author Abdelrazak Younes * \author Abdelrazak Younes
* \author Guillaume Munch
* *
* Full author contact details are available in file CREDITS. * Full author contact details are available in file CREDITS.
*/ */
@ -57,18 +58,6 @@ int TocItem::id() const
} }
int TocItem::depth() const
{
return depth_;
}
docstring const & TocItem::str() const
{
return str_;
}
docstring const & TocItem::tooltip() const docstring const & TocItem::tooltip() const
{ {
return tooltip_.empty() ? str_ : tooltip_; return tooltip_.empty() ? str_ : tooltip_;
@ -81,12 +70,6 @@ docstring const TocItem::asString() const
} }
DocIterator const & TocItem::dit() const
{
return dit_;
}
FuncRequest TocItem::action() const FuncRequest TocItem::action() const
{ {
string const arg = convert<string>(dit_.paragraph().id()) string const arg = convert<string>(dit_.paragraph().id())
@ -97,97 +80,10 @@ FuncRequest TocItem::action() const
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// //
// TocBackend implementation // Toc implementation
// //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
Toc const & TocBackend::toc(string const & type) const
{
// Is the type already supported?
TocList::const_iterator it = tocs_.find(type);
LASSERT(it != tocs_.end(), { static Toc dummy; return dummy; });
return it->second;
}
Toc & TocBackend::toc(string const & type)
{
return tocs_[type];
}
bool TocBackend::updateItem(DocIterator const & dit)
{
if (dit.text()->getTocLevel(dit.pit()) == Layout::NOT_IN_TOC)
return false;
if (toc("tableofcontents").empty()) {
// FIXME: should not happen,
// a call to TocBackend::update() is missing somewhere
LYXERR0("TocBackend::updateItem called but the TOC is empty!");
return false;
}
BufferParams const & bufparams = buffer_->params();
const int min_toclevel = bufparams.documentClass().min_toclevel();
TocIterator toc_item = item("tableofcontents", dit);
docstring tocstring;
// For each paragraph, traverse its insets and let them add
// their toc items
Paragraph & par = toc_item->dit_.paragraph();
InsetList::const_iterator it = par.insetList().begin();
InsetList::const_iterator end = par.insetList().end();
for (; it != end; ++it) {
Inset & inset = *it->inset;
if (inset.lyxCode() == ARG_CODE) {
if (!tocstring.empty())
break;
Paragraph const & inset_par =
*static_cast<InsetArgument&>(inset).paragraphs().begin();
if (!par.labelString().empty())
tocstring = par.labelString() + ' ';
tocstring += inset_par.asString(AS_STR_INSETS);
break;
}
}
int const toclevel = toc_item->dit_.text()->getTocLevel(toc_item->dit_.pit());
if (toclevel != Layout::NOT_IN_TOC && toclevel >= min_toclevel
&& tocstring.empty())
tocstring = par.asString(AS_STR_LABEL | AS_STR_INSETS);
const_cast<TocItem &>(*toc_item).str_ = tocstring;
buffer_->updateTocItem("tableofcontents", dit);
return true;
}
void TocBackend::update(bool output_active)
{
tocs_.clear();
if (!buffer_->isInternal()) {
DocIterator dit;
buffer_->inset().addToToc(dit, output_active);
}
}
TocIterator TocBackend::item(string const & type,
DocIterator const & dit) const
{
TocList::const_iterator toclist_it = tocs_.find(type);
// Is the type supported?
// We will try to make the best of it in release mode
LASSERT(toclist_it != tocs_.end(), toclist_it = tocs_.begin());
return toclist_it->second.item(dit);
}
TocIterator Toc::item(DocIterator const & dit) const TocIterator Toc::item(DocIterator const & dit) const
{ {
TocIterator last = begin(); TocIterator last = begin();
@ -233,13 +129,184 @@ Toc::iterator Toc::item(int depth, docstring const & str)
} }
///////////////////////////////////////////////////////////////////////////
//
// 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)
{
if (!stack_.empty() && !stack_.top().is_captioned) {
// The float we entered has not yet been assigned a caption.
// Assign the caption string to it.
(*toc_)[stack_.top().pos].str(s);
stack_.top().is_captioned = true;
} else {
// This is a new entry.
pop();
pushItem(dit, s, output_active, true);
}
}
void TocBuilder::pop()
{
if (!stack_.empty())
stack_.pop();
}
///////////////////////////////////////////////////////////////////////////
//
// TocBuilderStore implementation
//
///////////////////////////////////////////////////////////////////////////
shared_ptr<TocBuilder> TocBuilderStore::get(string const & type,
shared_ptr<Toc> toc)
{
map_t::const_iterator it = map_.find(type);
if (it == map_.end()) {
it = map_.insert(std::make_pair(type,
make_shared<TocBuilder>(toc))).first;
}
return it->second;
}
///////////////////////////////////////////////////////////////////////////
//
// TocBackend implementation
//
///////////////////////////////////////////////////////////////////////////
shared_ptr<Toc const> TocBackend::toc(string const & type) const
{
// Is the type already supported?
TocList::const_iterator it = tocs_.find(type);
LASSERT(it != tocs_.end(), { return make_shared<Toc>(); });
return it->second;
}
shared_ptr<Toc> TocBackend::toc(string const & type)
{
TocList::const_iterator it = tocs_.find(type);
if (it == tocs_.end()) {
it = tocs_.insert(std::make_pair(type, make_shared<Toc>())).first;
}
return it->second;
}
shared_ptr<TocBuilder> TocBackend::builder(string const & type)
{
return builders_.get(type, toc(type));
}
bool TocBackend::updateItem(DocIterator const & dit)
{
if (dit.text()->getTocLevel(dit.pit()) == Layout::NOT_IN_TOC)
return false;
if (toc("tableofcontents")->empty()) {
// FIXME: should not happen,
// a call to TocBackend::update() is missing somewhere
LYXERR0("TocBackend::updateItem called but the TOC is empty!");
return false;
}
BufferParams const & bufparams = buffer_->params();
const int min_toclevel = bufparams.documentClass().min_toclevel();
TocIterator toc_item = item("tableofcontents", dit);
docstring tocstring;
// For each paragraph, traverse its insets and let them add
// their toc items
Paragraph & par = toc_item->dit_.paragraph();
InsetList::const_iterator it = par.insetList().begin();
InsetList::const_iterator end = par.insetList().end();
for (; it != end; ++it) {
Inset & inset = *it->inset;
if (inset.lyxCode() == ARG_CODE) {
if (!tocstring.empty())
break;
Paragraph const & inset_par =
*static_cast<InsetArgument&>(inset).paragraphs().begin();
if (!par.labelString().empty())
tocstring = par.labelString() + ' ';
tocstring += inset_par.asString(AS_STR_INSETS);
break;
}
}
int const toclevel = toc_item->dit_.text()->getTocLevel(toc_item->dit_.pit());
if (toclevel != Layout::NOT_IN_TOC && toclevel >= min_toclevel
&& tocstring.empty())
tocstring = par.asString(AS_STR_LABEL | AS_STR_INSETS);
const_cast<TocItem &>(*toc_item).str_ = tocstring;
buffer_->updateTocItem("tableofcontents", dit);
return true;
}
void TocBackend::update(bool output_active)
{
for (TocList::iterator it = tocs_.begin(); it != tocs_.end(); ++it)
it->second->clear();
tocs_.clear();
builders_.clear();
if (!buffer_->isInternal()) {
DocIterator dit;
buffer_->inset().addToToc(dit, output_active);
}
}
TocIterator TocBackend::item(string const & type,
DocIterator const & dit) const
{
TocList::const_iterator toclist_it = tocs_.find(type);
// Is the type supported?
// We will try to make the best of it in release mode
LASSERT(toclist_it != tocs_.end(), toclist_it = tocs_.begin());
return toclist_it->second->item(dit);
}
void TocBackend::writePlaintextTocList(string const & type, void TocBackend::writePlaintextTocList(string const & type,
odocstringstream & os, size_t max_length) const odocstringstream & os, size_t max_length) const
{ {
TocList::const_iterator cit = tocs_.find(type); TocList::const_iterator cit = tocs_.find(type);
if (cit != tocs_.end()) { if (cit != tocs_.end()) {
TocIterator ccit = cit->second.begin(); TocIterator ccit = cit->second->begin();
TocIterator end = cit->second.end(); TocIterator end = cit->second->end();
for (; ccit != end; ++ccit) { for (; ccit != end; ++ccit) {
os << ccit->asString() << from_utf8("\n"); os << ccit->asString() << from_utf8("\n");
if (os.str().size() > max_length) if (os.str().size() > max_length)

View File

@ -7,6 +7,7 @@
* \author Jean-Marc Lasgouttes * \author Jean-Marc Lasgouttes
* \author Angus Leeming * \author Angus Leeming
* \author Abdelrazak Younes * \author Abdelrazak Younes
* \author Guillaume Munch
* *
* Full author contact details are available in file CREDITS. * Full author contact details are available in file CREDITS.
*/ */
@ -16,10 +17,12 @@
#include "DocIterator.h" #include "DocIterator.h"
#include "support/shared_ptr.h"
#include "support/strfwd.h" #include "support/strfwd.h"
#include <map> #include <map>
#include <vector> #include <vector>
#include <stack>
#include <string> #include <string>
@ -28,6 +31,34 @@ namespace lyx {
class Buffer; class Buffer;
class FuncRequest; class FuncRequest;
/* FIXME: toc types are currently identified by strings. It cannot be converted
* into an enum because of the user-configurable indexing categories and
* the user-definable float types provided by layout files.
*
* I leave this for documentation purposes for the moment.
*
enum TocType {
TABLE_OF_CONTENTS,//"tableofcontents"
CHILD,//"child"
GRAPHICS,//"graphics"
NOTE,//"note"
BRANCH,//"branch"
CHANGE,//"change"
LABEL,//"label"
CITATION,//"citation"
EQUATION,//"equation"
FOOTNOTE,//"footnote"
MARGINAL_NOTE,//"marginalnote"
INDEX,//"index", "index:<user-str>" (from interface)
NOMENCL,//"nomencl"
LISTING,//"listings"
FLOAT,//"figure", "table", "algorithm", user-defined (from layout?)
SENSELESS,//"senseless"
TOC_TYPE_COUNT
}
*/
/// ///
/** /**
*/ */
@ -51,15 +82,17 @@ public:
/// ///
int id() const; int id() const;
/// ///
int depth() const; int depth() const { return depth_; }
/// ///
docstring const & str() const; docstring const & str() const { return str_; }
///
void str(docstring const & s) { str_ = s; }
/// ///
docstring const & tooltip() const; docstring const & tooltip() const;
/// ///
docstring const asString() const; docstring const asString() const;
/// ///
DocIterator const & dit() const; DocIterator const & dit() const { return dit_; }
/// ///
bool isOutput() const { return output_; } bool isOutput() const { return output_; }
@ -95,9 +128,57 @@ public:
typedef Toc::const_iterator TocIterator; typedef Toc::const_iterator TocIterator;
/// Caption-enabled TOC builders
class TocBuilder
{
public:
TocBuilder(shared_ptr<Toc> const toc);
/// When entering a float
void pushItem(DocIterator const & dit, docstring const & s,
bool output_active, bool is_captioned = false);
/// When encountering a caption
void captionItem(DocIterator const & dit, docstring const & s,
bool output_active);
/// When exiting a float
void pop();
private:
TocBuilder(){}
///
struct frame {
Toc::size_type const pos;
bool is_captioned;
};
///
shared_ptr<Toc> const toc_;
///
std::stack<frame> stack_;
};
/// The ToC list. /// The ToC list.
/// A class and no typedef because we want to forward declare it. /// A class and no typedef because we want to forward declare it.
class TocList : public std::map<std::string, Toc> {}; class TocList : public std::map<std::string, shared_ptr<Toc> >
{
private:
// this can create null pointers
using std::map<std::string, shared_ptr<Toc> >::operator[];
};
///
class TocBuilderStore
{
public:
TocBuilderStore() {};
///
shared_ptr<TocBuilder> get(std::string const & type, shared_ptr<Toc> toc);
///
void clear() { map_.clear(); };
private:
typedef std::map<std::string, shared_ptr<TocBuilder> > map_t;
map_t map_;
};
/// ///
@ -114,15 +195,13 @@ public:
void update(bool output_active); void update(bool output_active);
/// \return true if the item was updated. /// \return true if the item was updated.
bool updateItem(DocIterator const & pit); bool updateItem(DocIterator const & pit);
/// ///
TocList const & tocs() const { return tocs_; } TocList const & tocs() const { return tocs_; }
TocList & tocs() { return tocs_; } /// never null
shared_ptr<Toc const> toc(std::string const & type) const;
/// shared_ptr<Toc> toc(std::string const & type);
Toc const & toc(std::string const & type) const; /// nevel null
Toc & toc(std::string const & type); shared_ptr<TocBuilder> builder(std::string const & type);
/// Return the first Toc Item before the cursor /// Return the first Toc Item before the cursor
TocIterator item( TocIterator item(
std::string const & type, ///< Type of Toc. std::string const & type, ///< Type of Toc.
@ -137,20 +216,11 @@ private:
/// ///
TocList tocs_; TocList tocs_;
/// ///
TocBuilderStore builders_;
///
Buffer const * buffer_; Buffer const * buffer_;
}; // TocBackend }; // TocBackend
inline bool operator==(TocItem const & a, TocItem const & b)
{
return a.id() == b.id() && a.str() == b.str() && a.depth() == b.depth();
}
inline bool operator!=(TocItem const & a, TocItem const & b)
{
return !(a == b);
}
} // namespace lyx } // namespace lyx

View File

@ -1313,8 +1313,8 @@ void MenuDefinition::expandToc(Buffer const * buf)
MenuDefinition submenu; MenuDefinition submenu;
if (floatlist.typeExist(cit->first)) { if (floatlist.typeExist(cit->first)) {
TocIterator ccit = cit->second.begin(); TocIterator ccit = cit->second->begin();
TocIterator eend = cit->second.end(); TocIterator eend = cit->second->end();
for (; ccit != eend; ++ccit) { for (; ccit != eend; ++ccit) {
if (0 == ccit->depth()) {// omit subfloats if (0 == ccit->depth()) {// omit subfloats
submenu.add(MenuItem(MenuItem::Command, submenu.add(MenuItem(MenuItem::Command,
@ -1331,15 +1331,15 @@ void MenuDefinition::expandToc(Buffer const * buf)
item.setSubmenu(submenu); item.setSubmenu(submenu);
add(item); add(item);
} else { } else {
if (cit->second.size() >= 30) { if (cit->second->size() >= 30) {
// FIXME: the behaviour of the interface should not change // FIXME: the behaviour of the interface should not change
// arbitrarily. Each type should be audited to see if the list // arbitrarily. Each type should be audited to see if the list
// can be optimised like for floats above. // can be optimised like for floats above.
FuncRequest f(LFUN_DIALOG_SHOW, "toc " + cit->first); FuncRequest f(LFUN_DIALOG_SHOW, "toc " + cit->first);
submenu.add(MenuItem(MenuItem::Command, qt_("Open Navigator..."), f)); submenu.add(MenuItem(MenuItem::Command, qt_("Open Navigator..."), f));
} else { } else {
TocIterator ccit = cit->second.begin(); TocIterator ccit = cit->second->begin();
TocIterator eend = cit->second.end(); TocIterator eend = cit->second->end();
for (; ccit != eend; ++ccit) { for (; ccit != eend; ++ccit) {
submenu.add(MenuItem(MenuItem::Command, submenu.add(MenuItem(MenuItem::Command,
limitStringLength(ccit->str()) + '|', limitStringLength(ccit->str()) + '|',
@ -1367,8 +1367,8 @@ void MenuDefinition::expandToc(Buffer const * buf)
if (cit == end) if (cit == end)
LYXERR(Debug::GUI, "No table of contents."); LYXERR(Debug::GUI, "No table of contents.");
else { else {
if (!cit->second.empty()) if (!cit->second->empty())
expandToc2(cit->second, 0, cit->second.size(), 0); expandToc2(* cit->second, 0, cit->second->size(), 0);
else else
add(MenuItem(MenuItem::Info, qt_("<Empty Table of Contents>"))); add(MenuItem(MenuItem::Info, qt_("<Empty Table of Contents>")));
} }

View File

@ -364,7 +364,7 @@ void TocModels::reset(BufferView const * bv)
iterator mod_it = models_.find(type); iterator mod_it = models_.find(type);
if (mod_it == models_.end()) if (mod_it == models_.end())
mod_it = models_.insert(type, new TocModel(this)); mod_it = models_.insert(type, new TocModel(this));
mod_it.value()->reset(it->second); mod_it.value()->reset(*it->second);
// Fill in the names_ model. // Fill in the names_ model.
QString const gui_name = guiName(it->first, bv->buffer().params()); QString const gui_name = guiName(it->first, bv->buffer().params());

View File

@ -628,6 +628,8 @@ QString guiName(string const & type, BufferParams const & bp)
return qt_("Branches"); return qt_("Branches");
if (type == "change") if (type == "change")
return qt_("Changes"); return qt_("Changes");
if (type == "senseless")
return qt_("Senseless");
if (prefixIs(type, "index:")) { if (prefixIs(type, "index:")) {
string const itype = split(type, ':'); string const itype = split(type, ':');
IndicesList const & indiceslist = bp.indiceslist(); IndicesList const & indiceslist = bp.indiceslist();

View File

@ -353,10 +353,10 @@ void InsetBranch::addToToc(DocIterator const & cpit, bool output_active) const
DocIterator pit = cpit; DocIterator pit = cpit;
pit.push_back(CursorSlice(const_cast<InsetBranch &>(*this))); pit.push_back(CursorSlice(const_cast<InsetBranch &>(*this)));
Toc & toc = buffer().tocBackend().toc("branch"); shared_ptr<Toc> toc = buffer().tocBackend().toc("branch");
docstring str = params_.branch + ": "; docstring str = params_.branch + ": ";
text().forOutliner(str, TOC_ENTRY_LENGTH); text().forOutliner(str, TOC_ENTRY_LENGTH);
toc.push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60))); toc->push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60)));
// Proceed with the rest of the inset. // Proceed with the rest of the inset.
bool const doing_output = output_active && isBranchSelected(); bool const doing_output = output_active && isBranchSelected();
InsetCollapsable::addToToc(cpit, doing_output); InsetCollapsable::addToToc(cpit, doing_output);

View File

@ -92,18 +92,13 @@ void InsetCaption::setCustomLabel(docstring const & label)
void InsetCaption::addToToc(DocIterator const & cpit, bool output_active) const void InsetCaption::addToToc(DocIterator const & cpit, bool output_active) const
{ {
if (floattype_.empty()) string const & type = floattype_.empty() ? "senseless" : floattype_;
return;
DocIterator pit = cpit; DocIterator pit = cpit;
pit.push_back(CursorSlice(const_cast<InsetCaption &>(*this))); pit.push_back(CursorSlice(const_cast<InsetCaption &>(*this)));
Toc & toc = buffer().tocBackend().toc(floattype_);
docstring str = full_label_; docstring str = full_label_;
int length = output_active ? INT_MAX : TOC_ENTRY_LENGTH; int length = output_active ? INT_MAX : TOC_ENTRY_LENGTH;
text().forOutliner(str, length); text().forOutliner(str, length);
toc.push_back(TocItem(pit, is_subfloat_ ? 1 : 0, str, output_active)); buffer().tocBackend().builder(type)->captionItem(pit, str, output_active);
// Proceed with the rest of the inset. // Proceed with the rest of the inset.
InsetText::addToToc(cpit, output_active); InsetText::addToToc(cpit, output_active);
} }
@ -368,7 +363,7 @@ void InsetCaption::updateBuffer(ParIterator const & it, UpdateType utype)
} }
// Memorize type for addToToc(). // Memorize type for addToToc().
floattype_ = type; floattype_ = type;
if (type.empty()) if (type.empty() || type == "senseless")
full_label_ = master.B_("Senseless!!! "); full_label_ = master.B_("Senseless!!! ");
else { else {
// FIXME: life would be _much_ simpler if listings was // FIXME: life would be _much_ simpler if listings was

View File

@ -339,8 +339,8 @@ void InsetCitation::addToToc(DocIterator const & cpit, bool output_active) const
// by both XHTML and plaintext output. So, if we change what goes into the TOC, // by both XHTML and plaintext output. So, if we change what goes into the TOC,
// then we will also need to change that routine. // then we will also need to change that routine.
docstring const tocitem = getParam("key"); docstring const tocitem = getParam("key");
Toc & toc = buffer().tocBackend().toc("citation"); shared_ptr<Toc> toc = buffer().tocBackend().toc("citation");
toc.push_back(TocItem(cpit, 0, tocitem, output_active)); toc->push_back(TocItem(cpit, 0, tocitem, output_active));
} }

View File

@ -30,6 +30,7 @@
#include "output_xhtml.h" #include "output_xhtml.h"
#include "ParIterator.h" #include "ParIterator.h"
#include "TextClass.h" #include "TextClass.h"
#include "TocBackend.h"
#include "support/debug.h" #include "support/debug.h"
#include "support/docstream.h" #include "support/docstream.h"
@ -202,6 +203,22 @@ bool InsetFloat::getStatus(Cursor & cur, FuncRequest const & cmd,
} }
void InsetFloat::addToToc(DocIterator const & cpit, bool output_active) const
{
string const & type = params().type;
DocIterator pit = cpit;
pit.push_back(CursorSlice(const_cast<InsetFloat &>(*this)));
docstring str;
int length = output_active ? INT_MAX : TOC_ENTRY_LENGTH;
text().forOutliner(str, length);
shared_ptr<TocBuilder> builder = buffer().tocBackend().builder(type);
builder->pushItem(pit, str, output_active);
// Proceed with the rest of the inset.
InsetCollapsable::addToToc(cpit, output_active);
builder->pop();
}
void InsetFloat::updateBuffer(ParIterator const & it, UpdateType utype) void InsetFloat::updateBuffer(ParIterator const & it, UpdateType utype)
{ {
Counters & cnts = Counters & cnts =

View File

@ -18,7 +18,8 @@
namespace lyx { namespace lyx {
class InsetFloatParams { class InsetFloatParams
{
public: public:
/// ///
InsetFloatParams() : wide(false), sideways(false), subfloat(false) {} InsetFloatParams() : wide(false), sideways(false), subfloat(false) {}
@ -99,7 +100,9 @@ private:
bool inheritFont() const { return false; } bool inheritFont() const { return false; }
/// ///
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const; bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const;
// Update the counters of this inset and of its contents ///
void addToToc(DocIterator const & di, bool output_active) const;
/// Update the counters of this inset and of its contents
void updateBuffer(ParIterator const &, UpdateType); void updateBuffer(ParIterator const &, UpdateType);
/// ///
void doDispatch(Cursor & cur, FuncRequest & cmd); void doDispatch(Cursor & cur, FuncRequest & cmd);

View File

@ -211,8 +211,8 @@ docstring InsetFloatList::xhtml(XHTMLStream &, OutputParams const & op) const {
// FIXME Do we need to check if it exists? If so, we need a new // FIXME Do we need to check if it exists? If so, we need a new
// routine in TocBackend to do that. // routine in TocBackend to do that.
Toc const & toc = buffer().tocBackend().toc(toctype); shared_ptr<Toc const> toc = buffer().tocBackend().toc(toctype);
if (toc.empty()) if (toc->empty())
return docstring(); return docstring();
// we want to look like a chapter, section, or whatever. // we want to look like a chapter, section, or whatever.
@ -249,8 +249,8 @@ docstring InsetFloatList::xhtml(XHTMLStream &, OutputParams const & op) const {
<< toclabel << toclabel
<< html::EndTag(tag); << html::EndTag(tag);
Toc::const_iterator it = toc.begin(); Toc::const_iterator it = toc->begin();
Toc::const_iterator const en = toc.end(); Toc::const_iterator const en = toc->end();
for (; it != en; ++it) { for (; it != en; ++it) {
Paragraph const & par = it->dit().innerParagraph(); Paragraph const & par = it->dit().innerParagraph();
string const attr = "class='lyxtoc-floats lyxtoc-" + toctype + "'"; string const attr = "class='lyxtoc-floats lyxtoc-" + toctype + "'";

View File

@ -79,10 +79,10 @@ void InsetFoot::addToToc(DocIterator const & cpit, bool output_active) const
DocIterator pit = cpit; DocIterator pit = cpit;
pit.push_back(CursorSlice(const_cast<InsetFoot &>(*this))); pit.push_back(CursorSlice(const_cast<InsetFoot &>(*this)));
Toc & toc = buffer().tocBackend().toc("footnote"); shared_ptr<Toc> toc = buffer().tocBackend().toc("footnote");
docstring str = custom_label_ + ": "; docstring str = custom_label_ + ": ";
text().forOutliner(str, TOC_ENTRY_LENGTH); text().forOutliner(str, TOC_ENTRY_LENGTH);
toc.push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60))); toc->push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60)));
// Proceed with the rest of the inset. // Proceed with the rest of the inset.
InsetFootlike::addToToc(cpit, output_active); InsetFootlike::addToToc(cpit, output_active);
} }

View File

@ -1031,7 +1031,7 @@ void InsetGraphics::addToToc(DocIterator const & cpit, bool output_active) const
{ {
//FIXME UNICODE //FIXME UNICODE
docstring const str = from_utf8(params_.filename.onlyFileName()); docstring const str = from_utf8(params_.filename.onlyFileName());
buffer().tocBackend().toc("graphics").push_back(TocItem(cpit, 0, str, output_active)); buffer().tocBackend().toc("graphics")->push_back(TocItem(cpit, 0, str, output_active));
} }

View File

@ -1137,29 +1137,30 @@ void InsetInclude::addToToc(DocIterator const & cpit, bool output_active) const
string caption = p.getParamValue("caption"); string caption = p.getParamValue("caption");
if (caption.empty()) if (caption.empty())
return; return;
Toc & toc = backend.toc("listing"); shared_ptr<Toc> toc = backend.toc("listing");
docstring str = convert<docstring>(toc.size() + 1) docstring str = convert<docstring>(toc->size() + 1)
+ ". " + from_utf8(caption); + ". " + from_utf8(caption);
DocIterator pit = cpit; DocIterator pit = cpit;
toc.push_back(TocItem(pit, 0, str, output_active)); toc->push_back(TocItem(pit, 0, str, output_active));
return; } else {
}
Buffer const * const childbuffer = getChildBuffer(); Buffer const * const childbuffer = getChildBuffer();
if (!childbuffer) if (!childbuffer)
return; return;
Toc & toc = backend.toc("child"); shared_ptr<Toc> toc = backend.toc("child");
docstring str = childbuffer->fileName().displayName(); docstring str = childbuffer->fileName().displayName();
toc.push_back(TocItem(cpit, 0, str, output_active)); toc->push_back(TocItem(cpit, 0, str, output_active));
TocList & toclist = backend.tocs(); //TocList & toclist = backend.tocs();
childbuffer->tocBackend().update(output_active); childbuffer->tocBackend().update(output_active);
TocList const & childtoclist = childbuffer->tocBackend().tocs(); TocList const & childtoclist = childbuffer->tocBackend().tocs();
TocList::const_iterator it = childtoclist.begin(); TocList::const_iterator it = childtoclist.begin();
TocList::const_iterator const end = childtoclist.end(); TocList::const_iterator const end = childtoclist.end();
for(; it != end; ++it) for(; it != end; ++it) {
toclist[it->first].insert(toclist[it->first].end(), shared_ptr<Toc> toc = backend.toc(it->first);
it->second.begin(), it->second.end()); toc->insert(toc->end(), it->second->begin(), it->second->end());
}
}
} }

View File

@ -358,7 +358,7 @@ void InsetIndex::addToToc(DocIterator const & cpit, bool output_active) const
type += ":" + to_utf8(params_.index); type += ":" + to_utf8(params_.index);
// this is unlikely to be terribly long // this is unlikely to be terribly long
text().forOutliner(str, INT_MAX); text().forOutliner(str, INT_MAX);
buffer().tocBackend().toc(type).push_back(TocItem(pit, 0, str, output_active)); buffer().tocBackend().toc(type)->push_back(TocItem(pit, 0, str, output_active));
// Proceed with the rest of the inset. // Proceed with the rest of the inset.
InsetCollapsable::addToToc(cpit, output_active); InsetCollapsable::addToToc(cpit, output_active);
} }
@ -689,13 +689,13 @@ docstring InsetPrintIndex::xhtml(XHTMLStream &, OutputParams const & op) const
if (bp.use_indices && getParam("type") != from_ascii("idx")) if (bp.use_indices && getParam("type") != from_ascii("idx"))
return docstring(); return docstring();
Toc const & toc = buffer().tocBackend().toc("index"); shared_ptr<Toc const> toc = buffer().tocBackend().toc("index");
if (toc.empty()) if (toc->empty())
return docstring(); return docstring();
// Collect the index entries in a form we can use them. // Collect the index entries in a form we can use them.
Toc::const_iterator it = toc.begin(); Toc::const_iterator it = toc->begin();
Toc::const_iterator const en = toc.end(); Toc::const_iterator const en = toc->end();
vector<IndexEntry> entries; vector<IndexEntry> entries;
for (; it != en; ++it) for (; it != en; ++it)
if (it->isOutput()) if (it->isOutput())

View File

@ -172,26 +172,26 @@ void InsetLabel::updateBuffer(ParIterator const & par, UpdateType utype)
void InsetLabel::addToToc(DocIterator const & cpit, bool output_active) const void InsetLabel::addToToc(DocIterator const & cpit, bool output_active) const
{ {
docstring const & label = getParam("name"); docstring const & label = getParam("name");
Toc & toc = buffer().tocBackend().toc("label"); shared_ptr<Toc> toc = buffer().tocBackend().toc("label");
if (buffer().insetLabel(label) != this) { if (buffer().insetLabel(label) != this) {
toc.push_back(TocItem(cpit, 0, screen_label_, output_active)); toc->push_back(TocItem(cpit, 0, screen_label_, output_active));
return; } else {
} toc->push_back(TocItem(cpit, 0, screen_label_, output_active));
toc.push_back(TocItem(cpit, 0, screen_label_, output_active));
Buffer::References const & refs = buffer().references(label); Buffer::References const & refs = buffer().references(label);
Buffer::References::const_iterator it = refs.begin(); Buffer::References::const_iterator it = refs.begin();
Buffer::References::const_iterator end = refs.end(); Buffer::References::const_iterator end = refs.end();
for (; it != end; ++it) { for (; it != end; ++it) {
DocIterator const ref_pit(it->second); DocIterator const ref_pit(it->second);
if (it->first->lyxCode() == MATH_REF_CODE) if (it->first->lyxCode() == MATH_REF_CODE)
toc.push_back(TocItem(ref_pit, 1, toc->push_back(TocItem(ref_pit, 1,
it->first->asInsetMath()->asRefInset()->screenLabel(), it->first->asInsetMath()->asRefInset()->screenLabel(),
output_active)); output_active));
else else
toc.push_back(TocItem(ref_pit, 1, toc->push_back(TocItem(ref_pit, 1,
static_cast<InsetRef *>(it->first)->getTOCString(), static_cast<InsetRef *>(it->first)->getTOCString(),
output_active)); output_active));
} }
}
} }

View File

@ -349,7 +349,8 @@ bool InsetListings::getStatus(Cursor & cur, FuncRequest const & cmd,
status.setEnabled(true); status.setEnabled(true);
return true; return true;
case LFUN_CAPTION_INSERT: { case LFUN_CAPTION_INSERT: {
if (params().isInline()) { // the inset outputs at most one caption
if (params().isInline() || getCaptionInset()) {
status.setEnabled(false); status.setEnabled(false);
return true; return true;
} }

View File

@ -56,10 +56,10 @@ void InsetMarginal::addToToc(DocIterator const & cpit, bool output_active) const
DocIterator pit = cpit; DocIterator pit = cpit;
pit.push_back(CursorSlice(const_cast<InsetMarginal &>(*this))); pit.push_back(CursorSlice(const_cast<InsetMarginal &>(*this)));
Toc & toc = buffer().tocBackend().toc("marginalnote"); shared_ptr<Toc> toc = buffer().tocBackend().toc("marginalnote");
docstring str; docstring str;
text().forOutliner(str, TOC_ENTRY_LENGTH); text().forOutliner(str, TOC_ENTRY_LENGTH);
toc.push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60))); toc->push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60)));
// Proceed with the rest of the inset. // Proceed with the rest of the inset.
InsetFootlike::addToToc(cpit, output_active); InsetFootlike::addToToc(cpit, output_active);
} }

View File

@ -135,7 +135,7 @@ void InsetNomencl::validate(LaTeXFeatures & features) const
void InsetNomencl::addToToc(DocIterator const & cpit, bool output_active) const void InsetNomencl::addToToc(DocIterator const & cpit, bool output_active) const
{ {
docstring const str = getParam("symbol"); docstring const str = getParam("symbol");
buffer().tocBackend().toc("nomencl").push_back(TocItem(cpit, 0, str, output_active)); buffer().tocBackend().toc("nomencl")->push_back(TocItem(cpit, 0, str, output_active));
} }
@ -190,11 +190,11 @@ typedef map<docstring, NomenclEntry > EntryMap;
docstring InsetPrintNomencl::xhtml(XHTMLStream &, OutputParams const & op) const docstring InsetPrintNomencl::xhtml(XHTMLStream &, OutputParams const & op) const
{ {
Toc const & toc = buffer().tocBackend().toc("nomencl"); shared_ptr<Toc const> toc = buffer().tocBackend().toc("nomencl");
EntryMap entries; EntryMap entries;
Toc::const_iterator it = toc.begin(); Toc::const_iterator it = toc->begin();
Toc::const_iterator const en = toc.end(); Toc::const_iterator const en = toc->end();
for (; it != en; ++it) { for (; it != en; ++it) {
DocIterator dit = it->dit(); DocIterator dit = it->dit();
Paragraph const & par = dit.innerParagraph(); Paragraph const & par = dit.innerParagraph();

View File

@ -212,11 +212,11 @@ void InsetNote::addToToc(DocIterator const & cpit, bool output_active) const
DocIterator pit = cpit; DocIterator pit = cpit;
pit.push_back(CursorSlice(const_cast<InsetNote &>(*this))); pit.push_back(CursorSlice(const_cast<InsetNote &>(*this)));
Toc & toc = buffer().tocBackend().toc("note"); shared_ptr<Toc> toc = buffer().tocBackend().toc("note");
InsetLayout const & il = getLayout(); InsetLayout const & il = getLayout();
docstring str = translateIfPossible(il.labelstring()) + from_ascii(": "); docstring str = translateIfPossible(il.labelstring()) + from_ascii(": ");
text().forOutliner(str, TOC_ENTRY_LENGTH); text().forOutliner(str, TOC_ENTRY_LENGTH);
toc.push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60))); toc->push_back(TocItem(pit, 0, str, output_active, toolTipText(docstring(), 3, 60)));
// Proceed with the rest of the inset. // Proceed with the rest of the inset.
bool doing_output = output_active && producesOutput(); bool doing_output = output_active && producesOutput();

View File

@ -312,8 +312,8 @@ void InsetRef::addToToc(DocIterator const & cpit, bool output_active) const
// It seems that this reference does not point to any valid label. // It seems that this reference does not point to any valid label.
screen_label_ = _("BROKEN: ") + screen_label_; screen_label_ = _("BROKEN: ") + screen_label_;
Toc & toc = buffer().tocBackend().toc("label"); shared_ptr<Toc> toc = buffer().tocBackend().toc("label");
toc.push_back(TocItem(cpit, 0, screen_label_, output_active)); toc->push_back(TocItem(cpit, 0, screen_label_, output_active));
} }

View File

@ -235,8 +235,9 @@ docstring InsetTOC::xhtml(XHTMLStream &, OutputParams const & op) const
LASSERT(false, return docstring()); LASSERT(false, return docstring());
} }
Toc const & toc = buffer().masterBuffer()->tocBackend().toc(cmd2type(command)); shared_ptr<Toc const> toc =
if (toc.empty()) buffer().masterBuffer()->tocBackend().toc(cmd2type(command));
if (toc->empty())
return docstring(); return docstring();
// we'll use our own stream, because we are going to defer everything. // we'll use our own stream, because we are going to defer everything.
@ -264,9 +265,9 @@ docstring InsetTOC::xhtml(XHTMLStream &, OutputParams const & op) const
// Output of TOC // Output of TOC
if (use_depth) if (use_depth)
makeTOCWithDepth(xs, toc, op); makeTOCWithDepth(xs, *toc, op);
else else
makeTOCNoDepth(xs, toc, op); makeTOCNoDepth(xs, *toc, op);
xs << html::EndTag("div") << html::CR(); xs << html::EndTag("div") << html::CR();
return ods.str(); return ods.str();

View File

@ -805,7 +805,8 @@ void InsetText::addToToc(DocIterator const & cdit, bool output_active) const
void InsetText::iterateForToc(DocIterator const & cdit, bool output_active) const void InsetText::iterateForToc(DocIterator const & cdit, bool output_active) const
{ {
DocIterator dit = cdit; DocIterator dit = cdit;
Toc & toc = buffer().tocBackend().toc("tableofcontents"); // Ensure that any document has a table of contents
shared_ptr<Toc> toc = buffer().tocBackend().toc("tableofcontents");
BufferParams const & bufparams = buffer_->params(); BufferParams const & bufparams = buffer_->params();
int const min_toclevel = bufparams.documentClass().min_toclevel(); int const min_toclevel = bufparams.documentClass().min_toclevel();
@ -846,7 +847,7 @@ void InsetText::iterateForToc(DocIterator const & cdit, bool output_active) cons
} else } else
par.forOutliner(tocstring, length); par.forOutliner(tocstring, length);
dit.pos() = 0; dit.pos() = 0;
toc.push_back(TocItem(dit, toclevel - min_toclevel, toc->push_back(TocItem(dit, toclevel - min_toclevel,
tocstring, doing_output, tocstring)); tocstring, doing_output, tocstring));
} }

View File

@ -301,14 +301,14 @@ void InsetMathHull::addToToc(DocIterator const & pit, bool output_active) const
return; return;
} }
Toc & toc = buffer().tocBackend().toc("equation"); shared_ptr<Toc> toc = buffer().tocBackend().toc("equation");
for (row_type row = 0; row != nrows(); ++row) { for (row_type row = 0; row != nrows(); ++row) {
if (!numbered(row)) if (!numbered(row))
continue; continue;
if (label_[row]) if (label_[row])
label_[row]->addToToc(pit, output_active); label_[row]->addToToc(pit, output_active);
toc.push_back(TocItem(pit, 0, nicelabel(row), output_active)); toc->push_back(TocItem(pit, 0, nicelabel(row), output_active));
} }
} }