]> git.lyx.org Git - features.git/commitdiff
Run updateBuffer when adding/merging changes
authorJean-Marc Lasgouttes <lasgouttes@lyx.org>
Thu, 28 Jan 2021 09:10:18 +0000 (10:10 +0100)
committerJean-Marc Lasgouttes <lasgouttes@lyx.org>
Thu, 28 Jan 2021 10:30:05 +0000 (11:30 +0100)
Following 4a4ded22, the enabling of some change-related functions is
handled in updateBuffer. However, this method is not ran at every
document change for performance reasons.

This patch adds code to every place that modifies
Paragraph::Private::changes_ that checks whether the `changedness' of
the paragraph, err... changes.

To this end, a new helper struct is introduced that remembers
paragraph state at contruction time, and compares it to new state in
the destructor.

New forceUpdate/needUpdate methods are added to Buffer class, since
the cursor is in general not available in the places where these
changes are made.

Fixes bug #12074.

src/Buffer.cpp
src/Buffer.h
src/BufferView.cpp
src/Paragraph.cpp

index 6454ba3c9213ec333988671642768116a84f20af..f2a370235a1374997b25903cae402c2c23ea0904 100644 (file)
@@ -354,6 +354,9 @@ public:
        /// whether the bibinfo cache is valid
        mutable bool bibinfo_cache_valid_;
 
+       ///
+       mutable bool need_update;
+
 private:
        int word_count_;
        int char_count_;
@@ -460,7 +463,7 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
          internal_buffer(false), read_only(readonly_), file_fully_loaded(false),
          need_format_backup(false), ignore_parent(false), macro_lock(false),
          externally_modified_(false), bibinfo_cache_valid_(false),
-         word_count_(0), char_count_(0), blank_count_(0)
+         need_update(false), word_count_(0), char_count_(0), blank_count_(0)
 {
        refreshFileMonitor();
        if (!cloned_buffer_) {
@@ -5286,6 +5289,18 @@ void Buffer::updateBuffer(ParIterator & parit, UpdateType utype, bool const dele
 }
 
 
+void Buffer::forceUpdate() const
+{
+       d->need_update = true;
+}
+
+
+bool Buffer::needUpdate() const
+{
+       return d->need_update;
+}
+
+
 int Buffer::spellCheck(DocIterator & from, DocIterator & to,
        WordLangTuple & word_lang, docstring_list & suggestions) const
 {
index 9adc7172c8eeb3dd7a218e2861a52e3df4b805b3..6d4f77c3fdaa15a2e923097cc060df63f998a8a1 100644 (file)
@@ -735,6 +735,10 @@ public:
        void updateBuffer(UpdateScope scope, UpdateType utype) const;
        ///
        void updateBuffer(ParIterator & parit, UpdateType utype, bool const deleted = false) const;
+       /// Forces an updateBuffer() call
+       void forceUpdate() const;
+       /// Do we need to call updateBuffer()?
+       bool needUpdate() const;
 
        /// Spellcheck starting from \p from.
        /// \p from initial position, will then points to the next misspelled
@@ -771,7 +775,7 @@ public:
        int wordCount() const;
        int charCount(bool with_blanks) const;
 
-       /// FIXME: dummy function for now
+       ///
        bool areChangesPresent() const;
 
        ///
index ec89084de756cf3699efcf3297d2f8d27d75672c..8094c6431db7202d9202bbb703382e34382b920b 100644 (file)
@@ -2417,7 +2417,7 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
        // Do we have a selection?
        theSelection().haveSelection(cursor().selection());
 
-       if (cur.needBufferUpdate()) {
+       if (cur.needBufferUpdate() || buffer().needUpdate()) {
                cur.clearBufferUpdate();
                buffer().updateBuffer();
        }
index abe1394ae1f668f7a72addcf289b42cba25c6bc6..e7d835fc634c2257bfeb5ba8386c9468c431a9c7 100644 (file)
@@ -564,6 +564,48 @@ Paragraph::Private::Private(Private const & p, Paragraph * owner,
 }
 
 
+/////////////////////////////////////////////////////////////////////
+//
+// Paragraph
+//
+/////////////////////////////////////////////////////////////////////
+
+namespace {
+
+/** This helper class should be instantiated at the start of methods
+ * that can create or merge changes. If as a result the value of
+ * Paragraph::isChanged is modified, it makes sure that updateBuffer()
+ * will be run.
+ */
+struct ChangesMonitor {
+       ///
+       ChangesMonitor(Paragraph & par)
+               : par_(par), was_changed_(par.isChanged()) {}
+       ///
+       ~ChangesMonitor()
+       {
+               /* We may need to run updateBuffer to check whether the buffer
+                * contains changes (and toggle the changes toolbar). We do it
+                * when:
+                * 1. the `changedness' of the paragraph has changed,
+                * 2. and we are not in the situation where the buffer has changes
+                * and new changes are added to the paragraph.
+                */
+               if (par_.isChanged() != was_changed_
+                   && par_.inInset().isBufferValid()
+                   && !(par_.inInset().buffer().areChangesPresent() && par_.isChanged()))
+                       par_.inInset().buffer().forceUpdate();
+       }
+
+private:
+       ///
+       Paragraph const & par_;
+       ///
+       bool was_changed_;
+};
+
+}
+
 void Paragraph::addChangesToToc(DocIterator const & cdit, Buffer const & buf,
                                 bool output_active, TocBackend & backend) const
 {
@@ -629,6 +671,9 @@ Change Paragraph::parEndChange() const
 
 void Paragraph::setChange(Change const & change)
 {
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        // beware of the imaginary end-of-par character!
        d->changes_.set(change, 0, size() + 1);
 
@@ -655,6 +700,9 @@ void Paragraph::setChange(Change const & change)
 
 void Paragraph::setChange(pos_type pos, Change const & change)
 {
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        LASSERT(pos >= 0 && pos <= size(), return);
        d->changes_.set(change, pos);
 
@@ -674,6 +722,9 @@ Change const & Paragraph::lookupChange(pos_type pos) const
 
 void Paragraph::acceptChanges(pos_type start, pos_type end)
 {
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        LASSERT(start >= 0 && start <= size(), return);
        LASSERT(end > start && end <= size() + 1, return);
 
@@ -712,6 +763,9 @@ void Paragraph::rejectChanges(pos_type start, pos_type end)
        LASSERT(start >= 0 && start <= size(), return);
        LASSERT(end > start && end <= size() + 1, return);
 
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        for (pos_type pos = start; pos < end; ++pos) {
                switch (lookupChange(pos).type) {
                        case Change::UNCHANGED:
@@ -747,6 +801,9 @@ void Paragraph::Private::insertChar(pos_type pos, char_type c,
 {
        LASSERT(pos >= 0 && pos <= int(text_.size()), return);
 
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*owner_);
+
        // track change
        changes_.insert(change, pos);
 
@@ -779,6 +836,9 @@ bool Paragraph::insertInset(pos_type pos, Inset * inset,
        LASSERT(inset, return false);
        LASSERT(pos >= 0 && pos <= size(), return false);
 
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        // Paragraph::insertInset() can be used in cut/copy/paste operation where
        // d->inset_owner_ is not set yet.
        if (d->inset_owner_ && !d->inset_owner_->insetAllowed(inset->lyxCode()))
@@ -801,6 +861,9 @@ bool Paragraph::eraseChar(pos_type pos, bool trackChanges)
 {
        LASSERT(pos >= 0 && pos <= size(), return false);
 
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        // keep the logic here in sync with the logic of isMergedOnEndOfParDeletion()
 
        if (trackChanges) {
@@ -1707,6 +1770,9 @@ void Paragraph::insert(pos_type pos, docstring const & str,
 void Paragraph::appendChar(char_type c, Font const & font,
                Change const & change)
 {
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        // track change
        d->changes_.insert(change, d->text_.size());
        // when appending characters, no need to update tables
@@ -1719,6 +1785,9 @@ void Paragraph::appendChar(char_type c, Font const & font,
 void Paragraph::appendString(docstring const & s, Font const & font,
                Change const & change)
 {
+       // Make sure that Buffer::hasChangesPresent is updated
+       ChangesMonitor cm(*this);
+
        pos_type end = s.size();
        size_t oldsize = d->text_.size();
        size_t newsize = oldsize + end;