From 6d4e6aad24edb7bcfbc49f03d2432fc9fa06954d Mon Sep 17 00:00:00 2001 From: Guillaume Munch Date: Sat, 30 Jan 2016 23:14:36 +0000 Subject: [PATCH] Automatically show the review toolbar if the document has tracked changes (#8738) For efficiency, we add a new flag to the buffer indicating when changes are present. This flag is updated at each buffer update, and also when explicitly requested via a dispatch result flag. --- lib/ui/default.ui | 3 ++- src/Buffer.cpp | 36 ++++++++++++++++++++++++++++ src/Buffer.h | 6 +++++ src/Changes.cpp | 28 ++++++++++++++++++++++ src/Changes.h | 13 ++++++++++ src/Cursor.cpp | 6 +++++ src/DispatchResult.h | 18 ++++++++++++-- src/Paragraph.cpp | 12 ++++++++++ src/Paragraph.h | 4 ++++ src/frontends/qt4/GuiApplication.cpp | 3 +++ src/frontends/qt4/GuiView.cpp | 5 ++-- 11 files changed, 129 insertions(+), 5 deletions(-) diff --git a/lib/ui/default.ui b/lib/ui/default.ui index 51a7f9b90e..4a1e154aab 100644 --- a/lib/ui/default.ui +++ b/lib/ui/default.ui @@ -34,7 +34,8 @@ Include "stdtoolbars.inc" # math: the toolbar is visible only when in math # mathmacrotemplate: the toolbar is visible only when in a macro definition # table: the toolbar is visible only when in a table -# review: the toolbar is visible only when inside a tracked change +# review: the toolbar is visible only when tracked changes are present or +# change tracking is enabled # ipa: the toolbar is only visible when inside an ipa inset # # top: the toolbar should be at the top of the window diff --git a/src/Buffer.cpp b/src/Buffer.cpp index e2185fbd89..ac64cf2f26 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -370,6 +370,10 @@ public: + (with_blanks ? blank_count_ : 0); } + // does the buffer contains tracked changes? (if so, we automatically + // display the review toolbar) + mutable bool tracked_changes_present_; + private: /// So we can force access via the accessors. mutable Buffer const * parent_buffer; @@ -442,6 +446,7 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_, preview_file_ = cloned_buffer_->d->preview_file_; preview_format_ = cloned_buffer_->d->preview_format_; preview_error_ = cloned_buffer_->d->preview_error_; + tracked_changes_present_ = cloned_buffer_->d->tracked_changes_present_; } @@ -2768,6 +2773,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) if (params().save_transient_properties) undo().recordUndoBufferParams(CursorData()); params().track_changes = !params().track_changes; + if (!params().track_changes) + dr.forceChangesUpdate(); break; case LFUN_CHANGES_OUTPUT: @@ -4584,6 +4591,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const // update all caches clearReferenceCache(); updateMacros(); + setChangesPresent(false); Buffer & cbuf = const_cast(*this); @@ -4847,6 +4855,9 @@ void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const // set the counter for this paragraph d->setLabel(parit, utype); + // update change-tracking flag + parit->addChangesToBuffer(*this); + // now the insets InsetList::const_iterator iit = parit->insetList().begin(); InsetList::const_iterator end = parit->insetList().end(); @@ -5111,4 +5122,29 @@ string Buffer::includedFilePath(string const & name, string const & ext) const from_utf8(filePath()))); } + +void Buffer::setChangesPresent(bool b) const +{ + d->tracked_changes_present_ = b; +} + + +bool Buffer::areChangesPresent() const +{ + return d->tracked_changes_present_; +} + + +void Buffer::updateChangesPresent() const +{ + LYXERR(Debug::CHANGES, "Buffer::updateChangesPresent"); + setChangesPresent(false); + ParConstIterator it = par_iterator_begin(); + ParConstIterator const end = par_iterator_end(); + for (; !areChangesPresent() && it != end; ++it) + it->addChangesToBuffer(*this); +} + + + } // namespace lyx diff --git a/src/Buffer.h b/src/Buffer.h index 3f5ab2231b..d4074b0fdb 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -760,6 +760,12 @@ public: int wordCount() const; int charCount(bool with_blanks) const; + // this is const because it does not modify the buffer's real contents, + // only the mutable flag. + void setChangesPresent(bool) const; + bool areChangesPresent() const; + void updateChangesPresent() const; + private: friend class MarkAsExporting; /// mark the buffer as busy exporting something, or not diff --git a/src/Changes.cpp b/src/Changes.cpp index 9fa46f92a3..616daf029f 100644 --- a/src/Changes.cpp +++ b/src/Changes.cpp @@ -298,8 +298,21 @@ bool Changes::isChanged(pos_type const start, pos_type const end) const } +bool Changes::isChanged() const +{ + ChangeTable::const_iterator it = table_.begin(); + ChangeTable::const_iterator const itend = table_.end(); + for (; it != itend; ++it) { + if (it->change.changed()) + return true; + } + return false; +} + + void Changes::merge() { + bool merged = false; ChangeTable::iterator it = table_.begin(); while (it != table_.end()) { @@ -312,6 +325,7 @@ void Changes::merge() << it->range.start); table_.erase(it); + merged = true; // start again it = table_.begin(); continue; @@ -330,6 +344,7 @@ void Changes::merge() (it + 1)->change.changetime = max(it->change.changetime, (it + 1)->change.changetime); table_.erase(it); + merged = true; // start again it = table_.begin(); continue; @@ -337,6 +352,8 @@ void Changes::merge() ++it; } + if (merged && !isChanged()) + is_update_required_ = true; } @@ -517,4 +534,15 @@ void Changes::addToToc(DocIterator const & cdit, Buffer const & buffer, } } + +void Changes::updateBuffer(Buffer const & buf) +{ + is_update_required_ = false; + if (!buf.areChangesPresent() && isChanged()) + buf.setChangesPresent(true); +} + + + + } // namespace lyx diff --git a/src/Changes.h b/src/Changes.h index 27710476a6..1d55b03b54 100644 --- a/src/Changes.h +++ b/src/Changes.h @@ -78,6 +78,8 @@ class BufferParams; class Changes { public: + Changes() : is_update_required_(false) {} + /// set the pos to the given change void set(Change const & change, pos_type pos); /// set the range (excluding end) to the given change @@ -98,6 +100,8 @@ public: /// return true if there is a change in the given range (excluding end) bool isChanged(pos_type start, pos_type end) const; + /// + bool isChanged() const; /// return true if the whole range is deleted bool isDeleted(pos_type start, pos_type end) const; @@ -119,6 +123,11 @@ public: void addToToc(DocIterator const & cdit, Buffer const & buffer, bool output_active) const; + /// + void updateBuffer(Buffer const & buf); + /// + bool isUpdateRequired() const { return is_update_required_; } + private: class Range { public: @@ -161,6 +170,10 @@ private: /// table of changes, every row a change and range descriptor ChangeTable table_; + + /// signals that the buffer's flag tracked_changes_present_ needs to be + /// recalculated + bool is_update_required_; }; diff --git a/src/Cursor.cpp b/src/Cursor.cpp index ed182ace64..1f84f45fea 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -2426,6 +2426,12 @@ void Cursor::checkBufferStructure() // In case the master has no gui associated with it, // the TocItem is not updated (part of bug 5699). buffer()->tocBackend().updateItem(*this); + + // If the last tracked change of the paragraph has just been + // deleted, then we need to recompute the buffer flag + // tracked_changes_present_. + if (inTexted() && paragraph().isChangeUpdateRequired()) + disp_.forceChangesUpdate(); } diff --git a/src/DispatchResult.h b/src/DispatchResult.h index 21dfa4f92b..f546be27bc 100644 --- a/src/DispatchResult.h +++ b/src/DispatchResult.h @@ -29,7 +29,8 @@ public: error_(false), update_(Update::None), need_buf_update_(false), - need_msg_update_(true) + need_msg_update_(true), + need_changes_update_(false) {} /// DispatchResult(bool dispatched, Update::flags f) : @@ -37,7 +38,8 @@ public: error_(false), update_(f), need_buf_update_(false), - need_msg_update_(true) + need_msg_update_(true), + need_changes_update_(false) {} /// bool dispatched() const { return dispatched_; } @@ -57,12 +59,14 @@ public: Update::flags screenUpdate() const { return update_; } /// void screenUpdate(Update::flags f) { update_ = f; } + /// Does the buffer need updating? bool needBufferUpdate() const { return need_buf_update_; } /// Force the buffer to be updated void forceBufferUpdate() { need_buf_update_ = true; } /// Clear the flag indicating we need an update void clearBufferUpdate() { need_buf_update_ = false; } + /// Do we need to display a message in the status bar? bool needMessageUpdate() const { return need_msg_update_; } /// Force the message to be displayed @@ -70,6 +74,14 @@ public: /// Clear the flag indicating we need to display the message void clearMessageUpdate() { need_msg_update_ = false; } + /// Do we need to update the change tracking presence flag? + bool needChangesUpdate() { return need_changes_update_; } + /// Force the change tracking presence flag to be updated + void forceChangesUpdate() { need_changes_update_ = true; } + /// Clear the flag indicating that we need to update the change tracking + /// presence flag + void clearChangesUpdate() { need_changes_update_ = false; } + private: /// was the event fully dispatched? bool dispatched_; @@ -83,6 +95,8 @@ private: bool need_buf_update_; /// bool need_msg_update_; + /// + bool need_changes_update_; }; diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index a405b6a806..d6106b37d4 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -562,6 +562,18 @@ void Paragraph::addChangesToToc(DocIterator const & cdit, } +void Paragraph::addChangesToBuffer(Buffer const & buf) const +{ + d->changes_.updateBuffer(buf); +} + + +bool Paragraph::isChangeUpdateRequired() const +{ + return d->changes_.isUpdateRequired(); +} + + bool Paragraph::isDeleted(pos_type start, pos_type end) const { LASSERT(start >= 0 && start <= size(), return false); diff --git a/src/Paragraph.h b/src/Paragraph.h index 73de6c173b..6f8d248ca0 100644 --- a/src/Paragraph.h +++ b/src/Paragraph.h @@ -153,6 +153,10 @@ public: /// void addChangesToToc(DocIterator const & cdit, Buffer const & buf, bool output_active) const; + /// set the buffer flag if there are changes in the paragraph + void addChangesToBuffer(Buffer const & buf) const; + /// + bool isChangeUpdateRequired() const; /// Language const * getParLanguage(BufferParams const &) const; /// diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 8b613794df..d64c9619fc 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -1399,6 +1399,9 @@ void GuiApplication::updateCurrentView(FuncRequest const & cmd, DispatchResult & if (dr.needBufferUpdate()) { bv->cursor().clearBufferUpdate(); bv->buffer().updateBuffer(); + } else if (dr.needChangesUpdate()) { + // updateBuffer() already updates the change-tracking presence flag + bv->buffer().updateChangesPresent(); } // BufferView::update() updates the ViewMetricsInfo and // also initializes the position cache for all insets in diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 8133ac246f..d228ca470d 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -1552,8 +1552,9 @@ void GuiView::updateToolbars() context |= Toolbars::MATH; if (lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled()) context |= Toolbars::TABLE; - if (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() - && lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true)) + if (currentBufferView()->buffer().areChangesPresent() + || (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() + && lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true))) context |= Toolbars::REVIEW; if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled()) context |= Toolbars::MATHMACROTEMPLATE; -- 2.39.2