X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FUndo.cpp;h=4e970df5a03cd4a394a9ef00de7798e6f4f01c1b;hb=975f304185eca53d62de8b36e6fc5f95b2da4fd9;hp=d7bcd75ea0b076bb128dfaf50808b8783a47928e;hpb=7760c5ccf2c558e48a54c101b779d0be25d7e7ba;p=features.git diff --git a/src/Undo.cpp b/src/Undo.cpp index d7bcd75ea0..4e970df5a0 100644 --- a/src/Undo.cpp +++ b/src/Undo.cpp @@ -18,25 +18,28 @@ #include "Undo.h" #include "Buffer.h" +#include "BufferList.h" #include "BufferParams.h" -#include "buffer_funcs.h" #include "Cursor.h" +#include "CutAndPaste.h" +#include "ErrorList.h" #include "Paragraph.h" #include "ParagraphList.h" #include "Text.h" -#include "mathed/MathSupport.h" +#include "mathed/InsetMath.h" #include "mathed/MathData.h" +#include "mathed/MathRow.h" -#include "insets/Inset.h" +#include "insets/InsetText.h" #include "support/debug.h" -#include "support/gettext.h" #include "support/lassert.h" #include "support/lyxtime.h" #include #include +#include using namespace std; using namespace lyx::support; @@ -71,43 +74,32 @@ struct UndoElement StableDocIterator const & cel, pit_type fro, pit_type en, ParagraphList * pl, MathData * ar, bool lc, size_t gid) : - kind(kin), cur_before(cb), cell(cel), from(fro), end(en), - pars(pl), array(ar), bparams(0), - lyx_clean(lc), group_id(gid), time(current_time()) - { - } + cur_before(cb), cell(cel), from(fro), end(en), + pars(pl), array(ar), bparams(nullptr), + group_id(gid), time(current_time()), kind(kin), lyx_clean(lc) + {} /// UndoElement(CursorData const & cb, BufferParams const & bp, bool lc, size_t gid) : - kind(ATOMIC_UNDO), cur_before(cb), cell(), from(0), end(0), - pars(0), array(0), bparams(new BufferParams(bp)), - lyx_clean(lc), group_id(gid), time(current_time()) - { - } + cur_before(cb), cell(), from(0), end(0), + pars(nullptr), array(nullptr), bparams(new BufferParams(bp)), + group_id(gid), time(current_time()), kind(ATOMIC_UNDO), lyx_clean(lc) + {} /// - UndoElement(UndoElement const & ue) : time(current_time()) - { - kind = ue.kind; - cur_before = ue.cur_before; - cur_after = ue.cur_after; - cell = ue.cell; - from = ue.from; - end = ue.end; - pars = ue.pars; - array = ue.array; - bparams = ue.bparams - ? new BufferParams(*ue.bparams) : 0; - lyx_clean = ue.lyx_clean; - group_id = ue.group_id; - } + UndoElement(UndoElement const & ue) : + cur_before(ue.cur_before), cur_after(ue.cur_after), + cell(ue.cell), from(ue.from), end(ue.end), + pars(ue.pars), array(ue.array), + bparams(ue.bparams ? new BufferParams(*ue.bparams) : nullptr), + group_id(ue.group_id), time(current_time()), kind(ue.kind), + lyx_clean(ue.lyx_clean) + {} /// ~UndoElement() { if (bparams) delete bparams; } - /// Which kind of operation are we recording for? - UndoKind kind; /// the position of the cursor before recordUndo CursorData cur_before; /// the position of the cursor at the end of the undo group @@ -124,12 +116,14 @@ struct UndoElement MathData * array; /// Only used in case of params undo BufferParams const * bparams; - /// Was the buffer clean at this point? - bool lyx_clean; /// the element's group id size_t group_id; /// timestamp time_t time; + /// Which kind of operation are we recording for? + UndoKind kind; + /// Was the buffer clean at this point? + bool lyx_clean; private: /// Protect construction UndoElement(); @@ -194,14 +188,14 @@ private: struct Undo::Private { - Private(Buffer & buffer) : buffer_(buffer), undo_finished_(true), - group_id(0), group_level(0) {} + Private(Buffer & buffer) : buffer_(buffer), + group_id_(0), group_level_(0), undo_finished_(true) {} // Do one undo/redo step - void doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, + void doUndoRedoAction(CursorData & cur, UndoElementStack & stack, UndoElementStack & otherStack); // Apply one undo/redo group. Returns false if no undo possible. - bool textUndoOrRedo(CursorData & cur, bool isUndoOperation); + bool undoRedoAction(CursorData & cur, bool isUndoOperation); /// void doRecordUndo(UndoKind kind, @@ -228,13 +222,16 @@ struct Undo::Private /// Redo stack. UndoElementStack redostack_; + /// Current group Id. + size_t group_id_; + /// Current group nesting nevel. + size_t group_level_; + /// the position of cursor before the group was created + CursorData group_cur_before_; + /// The flag used by Undo::finishUndo(). bool undo_finished_; - /// Current group Id. - size_t group_id; - /// Current group nesting nevel. - size_t group_level; }; @@ -263,8 +260,8 @@ void Undo::clear() d->undo_finished_ = true; // We used to do that, but I believe it is better to keep // groups (only used in Buffer::reload for now (JMarc) - //d->group_id = 0; - //d->group_level = 0; + //d->group_id_ = 0; + //d->group_level_ = 0; } @@ -308,9 +305,9 @@ void Undo::Private::doRecordUndo(UndoKind kind, CursorData const & cur_before, UndoElementStack & stack) { - if (!group_level) { + if (!group_level_) { LYXERR0("There is no group open (creating one)"); - ++group_id; + ++group_id_; } if (first_pit > last_pit) @@ -338,10 +335,11 @@ void Undo::Private::doRecordUndo(UndoKind kind, return; } - LYXERR(Debug::UNDO, "Create undo element of group " << group_id); + LYXERR(Debug::UNDO, "Create undo element of group " << group_id_); // create the position information of the Undo entry - UndoElement undo(kind, cur_before, cell, from, end, 0, 0, - buffer_.isClean(), group_id); + UndoElement undo(kind, + group_cur_before_.empty() ? cur_before : group_cur_before_, + cell, from, end, nullptr, nullptr, buffer_.isClean(), group_id_); // fill in the real data to be saved if (cell.inMathed()) { @@ -376,6 +374,9 @@ void Undo::Private::recordUndo(UndoKind kind, LASSERT(first_pit <= cell.lastpit(), return); LASSERT(last_pit <= cell.lastpit(), return); + if (buffer_.isReadonly()) + return; + doRecordUndo(kind, cell, first_pit, last_pit, cur, undostack_); @@ -390,17 +391,18 @@ void Undo::Private::recordUndo(UndoKind kind, void Undo::Private::doRecordUndoBufferParams(CursorData const & cur_before, - UndoElementStack & stack) + UndoElementStack & stack) { - if (!group_level) { + if (!group_level_) { LYXERR0("There is no group open (creating one)"); - ++group_id; + ++group_id_; } - LYXERR(Debug::UNDO, "Create full buffer undo element of group " << group_id); + LYXERR(Debug::UNDO, "Create full buffer undo element of group " << group_id_); // create the position information of the Undo entry - UndoElement undo(cur_before, buffer_.params(), buffer_.isClean(), - group_id); + UndoElement undo(group_cur_before_.empty() ? cur_before : group_cur_before_, + buffer_.params(), buffer_.isClean(), + group_id_); // push the undo entry to undo stack stack.push(undo); @@ -409,6 +411,9 @@ void Undo::Private::doRecordUndoBufferParams(CursorData const & cur_before, void Undo::Private::recordUndoBufferParams(CursorData const & cur) { + if (buffer_.isReadonly()) + return; + doRecordUndoBufferParams(cur, undostack_); // next time we'll try again to combine entries if possible @@ -421,7 +426,7 @@ void Undo::Private::recordUndoBufferParams(CursorData const & cur) } -void Undo::Private::doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, UndoElementStack & otherstack) +void Undo::Private::doUndoRedoAction(CursorData & cur, UndoElementStack & stack, UndoElementStack & otherstack) { // Adjust undo stack and get hold of current undo data. UndoElement & undo = stack.top(); @@ -434,10 +439,12 @@ void Undo::Private::doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, if (undo.bparams) doRecordUndoBufferParams(undo.cur_after, otherstack); - else + else { + LATTEST(undo.end <= cell_dit.lastpit()); doRecordUndo(ATOMIC_UNDO, cell_dit, undo.from, cell_dit.lastpit() - undo.end, undo.cur_after, otherstack); + } otherstack.top().cur_after = undo.cur_before; // This does the actual undo/redo. @@ -447,7 +454,10 @@ void Undo::Private::doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, // This is a params undo element delete otherstack.top().bparams; otherstack.top().bparams = new BufferParams(buffer_.params()); + DocumentClassConstPtr olddc = buffer_.params().documentClassPtr(); buffer_.params() = *undo.bparams; + cap::switchBetweenClasses(olddc, buffer_.params().documentClassPtr(), + static_cast(buffer_.inset())); } else if (dit.inMathed()) { // We stored the full cell here as there is not much to be // gained by storing just 'a few' paragraphs (most if not @@ -455,8 +465,9 @@ void Undo::Private::doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, //LYXERR0("undo.array: " << *undo.array); LBUFERR(undo.array); dit.cell().swap(*undo.array); + dit.inset().setBuffer(buffer_); delete undo.array; - undo.array = 0; + undo.array = nullptr; } else { // Some finer machinery is needed here. Text * text = dit.text(); @@ -482,13 +493,22 @@ void Undo::Private::doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, for (; pit != end; ++pit) pit->setInsetOwner(dit.realInset()); plist.insert(first, undo.pars->begin(), undo.pars->end()); + + // set the buffers for insets we created + ParagraphList::iterator fpit = plist.begin(); + advance(fpit, undo.from); + ParagraphList::iterator fend = fpit; + advance(fend, undo.pars->size()); + for (; fpit != fend; ++fpit) + fpit->setInsetBuffers(buffer_); + delete undo.pars; - undo.pars = 0; + undo.pars = nullptr; } // We'll clean up in release mode. - LASSERT(undo.pars == 0, undo.pars = 0); - LASSERT(undo.array == 0, undo.array = 0); + LASSERT(undo.pars == nullptr, undo.pars = nullptr); + LASSERT(undo.array == nullptr, undo.array = nullptr); if (!undo.cur_before.empty()) cur = undo.cur_before; @@ -501,8 +521,11 @@ void Undo::Private::doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, } -bool Undo::Private::textUndoOrRedo(CursorData & cur, bool isUndoOperation) +bool Undo::Private::undoRedoAction(CursorData & cur, bool isUndoOperation) { + if (buffer_.isReadonly()) + return false; + undo_finished_ = true; UndoElementStack & stack = isUndoOperation ? undostack_ : redostack_; @@ -515,10 +538,7 @@ bool Undo::Private::textUndoOrRedo(CursorData & cur, bool isUndoOperation) const size_t gid = stack.top().group_id; while (!stack.empty() && stack.top().group_id == gid) - doTextUndoOrRedo(cur, stack, otherstack); - - // Adapt the new material to current buffer. - buffer_.setBuffersForInsets(); // FIXME This shouldn't be here. + doUndoRedoAction(cur, stack, otherstack); return true; } @@ -530,48 +550,77 @@ void Undo::finishUndo() } -bool Undo::textUndo(CursorData & cur) +bool Undo::undoAction(CursorData & cur) { - return d->textUndoOrRedo(cur, true); + return d->undoRedoAction(cur, true); } -bool Undo::textRedo(CursorData & cur) +bool Undo::redoAction(CursorData & cur) { - return d->textUndoOrRedo(cur, false); + return d->undoRedoAction(cur, false); } void Undo::beginUndoGroup() { - if (d->group_level == 0) { + if (d->group_level_ == 0) { // create a new group - ++d->group_id; - LYXERR(Debug::UNDO, "+++++++Creating new group " << d->group_id); + ++d->group_id_; + LYXERR(Debug::UNDO, "+++++++ Creating new group " << d->group_id_ + << " for buffer " << &d->buffer_); } - ++d->group_level; + ++d->group_level_; +} + + +void Undo::beginUndoGroup(CursorData const & cur_before) +{ + beginUndoGroup(); + if (d->group_cur_before_.empty()) + d->group_cur_before_ = cur_before; } void Undo::endUndoGroup() { - if (d->group_level == 0) { + if (d->group_level_ == 0) { LYXERR0("There is no undo group to end here"); return; } - --d->group_level; - if (d->group_level == 0) { + --d->group_level_; + if (d->group_level_ == 0) { // real end of the group - LYXERR(Debug::UNDO, "-------End of group " << d->group_id); + d->group_cur_before_ = CursorData(); + LYXERR(Debug::UNDO, "------- End of group " << d->group_id_ + << " of buffer " << &d->buffer_); } } -void Undo::endUndoGroup(CursorData const & cur) +void Undo::endUndoGroup(CursorData const & cur_after) { endUndoGroup(); if (!d->undostack_.empty() && d->undostack_.top().cur_after.empty()) - d->undostack_.top().cur_after = cur; + d->undostack_.top().cur_after = cur_after; +} + + +void Undo::splitUndoGroup(CursorData const & cur) +{ + size_t const level = d->group_level_; + d->group_level_ = 1; + endUndoGroup(cur); + beginUndoGroup(cur); + d->group_level_ = level; +} + + +bool Undo::activeUndoGroup() const +{ + return d->group_level_ > 0 + && !d->undostack_.empty() + && d->undostack_.top().group_id == d->group_id_; } @@ -619,15 +668,32 @@ void Undo::recordUndoFullBuffer(CursorData const & cur) /// UndoGroupHelper class stuff +class UndoGroupHelper::Impl { + friend class UndoGroupHelper; + set buffers_; +}; + + +UndoGroupHelper::UndoGroupHelper(Buffer * buf) : d(new UndoGroupHelper::Impl) +{ + resetBuffer(buf); +} + + +UndoGroupHelper::~UndoGroupHelper() +{ + for (Buffer * buf : d->buffers_) + if (theBufferList().isLoaded(buf) || theBufferList().isInternal(buf)) + buf->undo().endUndoGroup(); + delete d; +} + void UndoGroupHelper::resetBuffer(Buffer * buf) { - if (buf == buffer_) - return; - if (buffer_) - buffer_->undo().endUndoGroup(); - buffer_ = buf; - if (buffer_) - buffer_->undo().beginUndoGroup(); + if (buf && d->buffers_.count(buf) == 0) { + d->buffers_.insert(buf); + buf->undo().beginUndoGroup(); + } }