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.
This commit is contained in:
Guillaume Munch 2016-01-30 23:14:36 +00:00 committed by Richard Heck
parent 5486beac29
commit c137ae4c43
11 changed files with 129 additions and 5 deletions

View File

@ -34,7 +34,8 @@ Include "stdtoolbars.inc"
# math: the toolbar is visible only when in math # math: the toolbar is visible only when in math
# mathmacrotemplate: the toolbar is visible only when in a macro definition # mathmacrotemplate: the toolbar is visible only when in a macro definition
# table: the toolbar is visible only when in a table # 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 # ipa: the toolbar is only visible when inside an ipa inset
# #
# top: the toolbar should be at the top of the window # top: the toolbar should be at the top of the window

View File

@ -370,6 +370,10 @@ public:
+ (with_blanks ? blank_count_ : 0); + (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: private:
/// So we can force access via the accessors. /// So we can force access via the accessors.
mutable Buffer const * parent_buffer; 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_file_ = cloned_buffer_->d->preview_file_;
preview_format_ = cloned_buffer_->d->preview_format_; preview_format_ = cloned_buffer_->d->preview_format_;
preview_error_ = cloned_buffer_->d->preview_error_; 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) if (params().save_transient_properties)
undo().recordUndoBufferParams(CursorData()); undo().recordUndoBufferParams(CursorData());
params().track_changes = !params().track_changes; params().track_changes = !params().track_changes;
if (!params().track_changes)
dr.forceChangesUpdate();
break; break;
case LFUN_CHANGES_OUTPUT: case LFUN_CHANGES_OUTPUT:
@ -4584,6 +4591,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
// update all caches // update all caches
clearReferenceCache(); clearReferenceCache();
updateMacros(); updateMacros();
setChangesPresent(false);
Buffer & cbuf = const_cast<Buffer &>(*this); Buffer & cbuf = const_cast<Buffer &>(*this);
@ -4847,6 +4855,9 @@ void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const
// set the counter for this paragraph // set the counter for this paragraph
d->setLabel(parit, utype); d->setLabel(parit, utype);
// update change-tracking flag
parit->addChangesToBuffer(*this);
// now the insets // now the insets
InsetList::const_iterator iit = parit->insetList().begin(); InsetList::const_iterator iit = parit->insetList().begin();
InsetList::const_iterator end = parit->insetList().end(); InsetList::const_iterator end = parit->insetList().end();
@ -5111,4 +5122,29 @@ string Buffer::includedFilePath(string const & name, string const & ext) const
from_utf8(filePath()))); 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 } // namespace lyx

View File

@ -760,6 +760,12 @@ public:
int wordCount() const; int wordCount() const;
int charCount(bool with_blanks) 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: private:
friend class MarkAsExporting; friend class MarkAsExporting;
/// mark the buffer as busy exporting something, or not /// mark the buffer as busy exporting something, or not

View File

@ -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() void Changes::merge()
{ {
bool merged = false;
ChangeTable::iterator it = table_.begin(); ChangeTable::iterator it = table_.begin();
while (it != table_.end()) { while (it != table_.end()) {
@ -312,6 +325,7 @@ void Changes::merge()
<< it->range.start); << it->range.start);
table_.erase(it); table_.erase(it);
merged = true;
// start again // start again
it = table_.begin(); it = table_.begin();
continue; continue;
@ -330,6 +344,7 @@ void Changes::merge()
(it + 1)->change.changetime = max(it->change.changetime, (it + 1)->change.changetime = max(it->change.changetime,
(it + 1)->change.changetime); (it + 1)->change.changetime);
table_.erase(it); table_.erase(it);
merged = true;
// start again // start again
it = table_.begin(); it = table_.begin();
continue; continue;
@ -337,6 +352,8 @@ void Changes::merge()
++it; ++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 } // namespace lyx

View File

@ -78,6 +78,8 @@ class BufferParams;
class Changes { class Changes {
public: public:
Changes() : is_update_required_(false) {}
/// set the pos to the given change /// set the pos to the given change
void set(Change const & change, pos_type pos); void set(Change const & change, pos_type pos);
/// set the range (excluding end) to the given change /// 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) /// return true if there is a change in the given range (excluding end)
bool isChanged(pos_type start, pos_type end) const; bool isChanged(pos_type start, pos_type end) const;
///
bool isChanged() const;
/// return true if the whole range is deleted /// return true if the whole range is deleted
bool isDeleted(pos_type start, pos_type end) const; bool isDeleted(pos_type start, pos_type end) const;
@ -119,6 +123,11 @@ public:
void addToToc(DocIterator const & cdit, Buffer const & buffer, void addToToc(DocIterator const & cdit, Buffer const & buffer,
bool output_active) const; bool output_active) const;
///
void updateBuffer(Buffer const & buf);
///
bool isUpdateRequired() const { return is_update_required_; }
private: private:
class Range { class Range {
public: public:
@ -161,6 +170,10 @@ private:
/// table of changes, every row a change and range descriptor /// table of changes, every row a change and range descriptor
ChangeTable table_; ChangeTable table_;
/// signals that the buffer's flag tracked_changes_present_ needs to be
/// recalculated
bool is_update_required_;
}; };

View File

@ -2432,6 +2432,12 @@ void Cursor::checkBufferStructure()
// In case the master has no gui associated with it, // In case the master has no gui associated with it,
// the TocItem is not updated (part of bug 5699). // the TocItem is not updated (part of bug 5699).
buffer()->tocBackend().updateItem(*this); 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();
} }

View File

@ -29,7 +29,8 @@ public:
error_(false), error_(false),
update_(Update::None), update_(Update::None),
need_buf_update_(false), need_buf_update_(false),
need_msg_update_(true) need_msg_update_(true),
need_changes_update_(false)
{} {}
/// ///
DispatchResult(bool dispatched, Update::flags f) : DispatchResult(bool dispatched, Update::flags f) :
@ -37,7 +38,8 @@ public:
error_(false), error_(false),
update_(f), update_(f),
need_buf_update_(false), need_buf_update_(false),
need_msg_update_(true) need_msg_update_(true),
need_changes_update_(false)
{} {}
/// ///
bool dispatched() const { return dispatched_; } bool dispatched() const { return dispatched_; }
@ -57,12 +59,14 @@ public:
Update::flags screenUpdate() const { return update_; } Update::flags screenUpdate() const { return update_; }
/// ///
void screenUpdate(Update::flags f) { update_ = f; } void screenUpdate(Update::flags f) { update_ = f; }
/// Does the buffer need updating? /// Does the buffer need updating?
bool needBufferUpdate() const { return need_buf_update_; } bool needBufferUpdate() const { return need_buf_update_; }
/// Force the buffer to be updated /// Force the buffer to be updated
void forceBufferUpdate() { need_buf_update_ = true; } void forceBufferUpdate() { need_buf_update_ = true; }
/// Clear the flag indicating we need an update /// Clear the flag indicating we need an update
void clearBufferUpdate() { need_buf_update_ = false; } void clearBufferUpdate() { need_buf_update_ = false; }
/// Do we need to display a message in the status bar? /// Do we need to display a message in the status bar?
bool needMessageUpdate() const { return need_msg_update_; } bool needMessageUpdate() const { return need_msg_update_; }
/// Force the message to be displayed /// Force the message to be displayed
@ -70,6 +74,14 @@ public:
/// Clear the flag indicating we need to display the message /// Clear the flag indicating we need to display the message
void clearMessageUpdate() { need_msg_update_ = false; } 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: private:
/// was the event fully dispatched? /// was the event fully dispatched?
bool dispatched_; bool dispatched_;
@ -83,6 +95,8 @@ private:
bool need_buf_update_; bool need_buf_update_;
/// ///
bool need_msg_update_; bool need_msg_update_;
///
bool need_changes_update_;
}; };

View File

@ -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 bool Paragraph::isDeleted(pos_type start, pos_type end) const
{ {
LASSERT(start >= 0 && start <= size(), return false); LASSERT(start >= 0 && start <= size(), return false);

View File

@ -154,6 +154,10 @@ public:
/// ///
void addChangesToToc(DocIterator const & cdit, Buffer const & buf, void addChangesToToc(DocIterator const & cdit, Buffer const & buf,
bool output_active) const; 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; Language const * getParLanguage(BufferParams const &) const;
/// ///

View File

@ -1399,6 +1399,9 @@ void GuiApplication::updateCurrentView(FuncRequest const & cmd, DispatchResult &
if (dr.needBufferUpdate()) { if (dr.needBufferUpdate()) {
bv->cursor().clearBufferUpdate(); bv->cursor().clearBufferUpdate();
bv->buffer().updateBuffer(); bv->buffer().updateBuffer();
} else if (dr.needChangesUpdate()) {
// updateBuffer() already updates the change-tracking presence flag
bv->buffer().updateChangesPresent();
} }
// BufferView::update() updates the ViewMetricsInfo and // BufferView::update() updates the ViewMetricsInfo and
// also initializes the position cache for all insets in // also initializes the position cache for all insets in

View File

@ -1552,8 +1552,9 @@ void GuiView::updateToolbars()
context |= Toolbars::MATH; context |= Toolbars::MATH;
if (lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled()) if (lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled())
context |= Toolbars::TABLE; context |= Toolbars::TABLE;
if (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() if (currentBufferView()->buffer().areChangesPresent()
&& lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true)) || (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled()
&& lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true)))
context |= Toolbars::REVIEW; context |= Toolbars::REVIEW;
if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled()) if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled())
context |= Toolbars::MATHMACROTEMPLATE; context |= Toolbars::MATHMACROTEMPLATE;