diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 708244e969..460fc910db 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -135,7 +135,22 @@ namespace { int const LYX_FORMAT = LYX_FORMAT_LYX; typedef map DepClean; -typedef map > RefCache; + +// Information about labels and their associated refs +struct LabelInfo { + /// label string + docstring label; + /// label inset + InsetLabel const * inset; + /// associated references cache + Buffer::References references; + /// whether this label is active (i.e., not deleted) + bool active; +}; + +typedef vector LabelCache; + +typedef map RefCache; } // namespace @@ -309,7 +324,11 @@ public: /// was missing). bool preview_error_; + /// Cache the references associated to a label and their positions + /// in the buffer. mutable RefCache ref_cache_; + /// Cache the label insets and their activity status. + mutable LabelCache label_cache_; /// our Text that should be wrapped in an InsetText InsetText * inset; @@ -3915,13 +3934,12 @@ Buffer::References & Buffer::getReferenceCache(docstring const & label) RefCache::iterator it = d->ref_cache_.find(label); if (it != d->ref_cache_.end()) - return it->second.second; + return it->second; - static InsetLabel const * dummy_il = 0; static References const dummy_refs = References(); it = d->ref_cache_.insert( - make_pair(label, make_pair(dummy_il, dummy_refs))).first; - return it->second.second; + make_pair(label, dummy_refs)).first; + return it->second; } @@ -3938,22 +3956,43 @@ void Buffer::addReference(docstring const & label, Inset * inset, ParIterator it } -void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il) +void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il, + bool const active) { - masterBuffer()->d->ref_cache_[label].first = il; + LabelInfo linfo; + linfo.label = label; + linfo.inset = il; + linfo.active = active; + masterBuffer()->d->label_cache_.push_back(linfo); } -InsetLabel const * Buffer::insetLabel(docstring const & label) const +InsetLabel const * Buffer::insetLabel(docstring const & label, + bool const active) const { - return masterBuffer()->d->ref_cache_[label].first; + for (auto & rc : masterBuffer()->d->label_cache_) { + if (rc.label == label && (rc.active || !active)) + return rc.inset; + } + return nullptr; +} + + +bool Buffer::activeLabel(docstring const & label) const +{ + if (!insetLabel(label, true)) + return false; + + return true; } void Buffer::clearReferenceCache() const { - if (!d->parent()) + if (!d->parent()) { d->ref_cache_.clear(); + d->label_cache_.clear(); + } } diff --git a/src/Buffer.h b/src/Buffer.h index f30b1a3fca..c81ba46f0d 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -707,18 +707,28 @@ public: /// bool isExporting() const; - /// + /// A collection of InsetRef insets and their position in the buffer typedef std::vector > References; - /// + /// Get all InsetRef insets and their positions associated with + /// the InsetLabel with the label string \p label References const & references(docstring const & label) const; - /// + /// Add an InsetRef at position \p it to the Insetlabel + /// with the label string \p label void addReference(docstring const & label, Inset * inset, ParIterator it); - /// + /// Clear the whole reference cache void clearReferenceCache() const; - /// - void setInsetLabel(docstring const & label, InsetLabel const * il); - /// - InsetLabel const * insetLabel(docstring const & label) const; + /// Set the InsetLabel for a given \p label string. \p active + /// determines whether this is an active label (see @ref activeLabel) + void setInsetLabel(docstring const & label, InsetLabel const * il, + bool const active); + /// \return the InsetLabel associated with this \p label string + /// If \p active is true we only return active labels + /// (see @ref activeLabel) + InsetLabel const * insetLabel(docstring const & label, + bool const active = false) const; + /// \return true if this \param label is an active label. + /// Inactive labels are currently deleted labels (in ct mode) + bool activeLabel(docstring const & label) const; /// return a list of all used branches (also in children) void getUsedBranches(std::list &, bool const from_master = false) const; diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 6b3a528f48..68d2c83f00 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2507,6 +2507,8 @@ bool BufferView::setCursorFromInset(Inset const * inset) void BufferView::gotoLabel(docstring const & label) { + FuncRequest action; + bool have_inactive = false; ListOfBuffers bufs = buffer().allRelatives(); ListOfBuffers::iterator it = bufs.begin(); for (; it != bufs.end(); ++it) { @@ -2517,12 +2519,21 @@ void BufferView::gotoLabel(docstring const & label) Toc::const_iterator toc_it = toc->begin(); Toc::const_iterator end = toc->end(); for (; toc_it != end; ++toc_it) { - if (label == toc_it->str()) { + if (label == toc_it->str() && toc_it->isOutput()) { lyx::dispatch(toc_it->action()); return; } + // If we find an inactive label, save it for the case + // that no active one is there + if (label == toc_it->str() && !have_inactive) { + have_inactive = true; + action = toc_it->action(); + } } } + // We only found an inactive label. Go there. + if (have_inactive) + lyx::dispatch(action); } diff --git a/src/Text.cpp b/src/Text.cpp index bdff46efec..2d916c834b 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -2041,7 +2041,7 @@ docstring Text::getPossibleLabel(Cursor const & cur) const // We need a unique label docstring label = text; int i = 1; - while (cur.buffer()->insetLabel(label)) { + while (cur.buffer()->activeLabel(label)) { label = text + '-' + convert(i); ++i; } diff --git a/src/insets/InsetLabel.cpp b/src/insets/InsetLabel.cpp index 7f3651f3a3..4a1cc453ff 100644 --- a/src/insets/InsetLabel.cpp +++ b/src/insets/InsetLabel.cpp @@ -67,11 +67,13 @@ void InsetLabel::uniqueLabel(docstring & label) const { docstring const new_label = label; int i = 1; - while (buffer().insetLabel(label)) { + bool ambiguous = false; + while (buffer().activeLabel(label)) { label = new_label + '-' + convert(i); ++i; + ambiguous = true; } - if (label != new_label) { + if (ambiguous) { // Warn the user that the label has been changed to something else. frontend::Alert::warning(_("Label names must be unique!"), bformat(_("The label %1$s already exists,\n" @@ -146,12 +148,27 @@ docstring InsetLabel::screenLabel() const void InsetLabel::updateBuffer(ParIterator const & par, UpdateType utype) { docstring const & label = getParam("name"); - if (buffer().insetLabel(label)) { - // Problem: We already have an InsetLabel with the same name! + + // Check if this one is deleted (ct) + Paragraph const & para = par.paragraph(); + bool active = !para.isDeleted(par.pos()); + // If not, check whether we are in a deleted inset + if (active) { + for (size_type sl = 0 ; sl < par.depth() ; ++sl) { + Paragraph const & outer_par = par[sl].paragraph(); + if (outer_par.isDeleted(par[sl].pos())) { + active = false; + break; + } + } + } + + if (buffer().activeLabel(label) && active) { + // Problem: We already have an active InsetLabel with the same name! screen_label_ = _("DUPLICATE: ") + label; return; } - buffer().setInsetLabel(label, this); + buffer().setInsetLabel(label, this, active); screen_label_ = label; if (utype == OutputUpdate) { @@ -175,23 +192,25 @@ void InsetLabel::addToToc(DocIterator const & cpit, bool output_active, UpdateType, TocBackend & backend) const { docstring const & label = getParam("name"); + // inactive labels get a cross mark + if (buffer().insetLabel(label, true) != this) + output_active = false; + + // We put both active and inactive labels to the outliner shared_ptr toc = backend.toc("label"); - if (buffer().insetLabel(label) != this) { - toc->push_back(TocItem(cpit, 0, screen_label_, output_active)); - } else { - toc->push_back(TocItem(cpit, 0, screen_label_, output_active)); - Buffer::References const & refs = buffer().references(label); - Buffer::References::const_iterator it = refs.begin(); - Buffer::References::const_iterator end = refs.end(); - for (; it != end; ++it) { - DocIterator const ref_pit(it->second); - if (it->first->lyxCode() == MATH_REF_CODE) + toc->push_back(TocItem(cpit, 0, screen_label_, output_active)); + // The refs get assigned only to the active label. If no active one exists, + // assign the (BROKEN) refs to the first inactive one. + if (buffer().insetLabel(label, true) == this || !buffer().activeLabel(label)) { + for (auto const & p : buffer().references(label)) { + DocIterator const ref_pit(p.second); + if (p.first->lyxCode() == MATH_REF_CODE) toc->push_back(TocItem(ref_pit, 1, - it->first->asInsetMath()->asRefInset()->screenLabel(), + p.first->asInsetMath()->asRefInset()->screenLabel(), output_active)); else toc->push_back(TocItem(ref_pit, 1, - static_cast(it->first)->getTOCString(), + static_cast(p.first)->getTOCString(), output_active)); } } diff --git a/src/insets/InsetRef.cpp b/src/insets/InsetRef.cpp index 92ad754e50..eef6a9751b 100644 --- a/src/insets/InsetRef.cpp +++ b/src/insets/InsetRef.cpp @@ -303,7 +303,7 @@ int InsetRef::docbook(odocstream & os, OutputParams const & runparams) const docstring InsetRef::xhtml(XHTMLStream & xs, OutputParams const & op) const { docstring const & ref = getParam("reference"); - InsetLabel const * il = buffer().insetLabel(ref); + InsetLabel const * il = buffer().insetLabel(ref, true); string const & cmd = params().getCmdName(); docstring display_string; @@ -423,12 +423,14 @@ void InsetRef::addToToc(DocIterator const & cpit, bool output_active, UpdateType, TocBackend & backend) const { docstring const & label = getParam("reference"); - if (buffer().insetLabel(label)) + if (buffer().insetLabel(label)) { + broken_ = !buffer().activeLabel(label); // This InsetRef has already been taken care of in InsetLabel::addToToc(). return; - + } + // It seems that this reference does not point to any valid label. - + broken_ = true; shared_ptr toc = backend.toc("label"); toc->push_back(TocItem(cpit, 0, screenLabel(), output_active)); diff --git a/status.23x b/status.23x index 68c3a51151..d62a9607b6 100644 --- a/status.23x +++ b/status.23x @@ -134,6 +134,8 @@ What's new - Fix display of gather environment in leqno mode (bug 11324). +- Fix handling of labels with change tracking (bug 6563). + * INTERNALS