X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FUndo.cpp;h=31eaec3dbd84977ee7d52e3dca4c86b3726df7f9;hb=d6fecb4aa47899ea3fe02d1699e0ffc81f364910;hp=7928c390966434ce9b6d3f0454f9de26dd749555;hpb=af77fb5186bed3602d9b4ac3c240909cb99879e1;p=lyx.git diff --git a/src/Undo.cpp b/src/Undo.cpp index 7928c39096..31eaec3dbd 100644 --- a/src/Undo.cpp +++ b/src/Undo.cpp @@ -20,7 +20,7 @@ #include "Buffer.h" #include "BufferParams.h" #include "buffer_funcs.h" -#include "DocIterator.h" +#include "Cursor.h" #include "Paragraph.h" #include "ParagraphList.h" #include "Text.h" @@ -30,8 +30,9 @@ #include "insets/Inset.h" -#include "support/lassert.h" #include "support/debug.h" +#include "support/gettext.h" +#include "support/lassert.h" #include #include @@ -60,17 +61,17 @@ structure ('Undo') _before_ it is changed in some edit operation. Obviously, the stored range should be as small as possible. However, there is a lower limit: The StableDocIterator stored in the undo class must be valid after the changes, too, as it will used as a pointer -where to insert the stored bits when performining undo. +where to insert the stored bits when performining undo. */ struct UndoElement { /// - UndoElement(UndoKind kin, StableDocIterator const & cur, + UndoElement(UndoKind kin, CursorData const & cb, StableDocIterator const & cel, - pit_type fro, pit_type en, ParagraphList * pl, - MathData * ar, BufferParams const & bp, + pit_type fro, pit_type en, ParagraphList * pl, + MathData * ar, BufferParams const & bp, bool ifb, bool lc, size_t gid) : - kind(kin), cursor(cur), cell(cel), from(fro), end(en), + kind(kin), cur_before(cb), cell(cel), from(fro), end(en), pars(pl), array(ar), bparams(0), isFullBuffer(ifb), lyx_clean(lc), group_id(gid) { @@ -81,7 +82,8 @@ struct UndoElement UndoElement(UndoElement const & ue) { kind = ue.kind; - cursor = ue.cursor; + cur_before = ue.cur_before; + cur_after = ue.cur_after; cell = ue.cell; from = ue.from; end = ue.end; @@ -101,8 +103,10 @@ struct UndoElement } /// Which kind of operation are we recording for? UndoKind kind; - /// the position of the cursor - StableDocIterator cursor; + /// the position of the cursor before recordUndo + CursorData cur_before; + /// the position of the cursor at the end of the undo group + CursorData cur_after; /// the position of the cell described StableDocIterator cell; /// counted from begin of cell @@ -123,11 +127,11 @@ struct UndoElement size_t group_id; private: /// Protect construction - UndoElement(); + UndoElement(); }; -class UndoElementStack +class UndoElementStack { public: /// limit is the maximum size of the stack @@ -156,20 +160,24 @@ public: /// Push an item on to the stack, deleting the bottom group on /// overflow. void push(UndoElement const & v) { - c_.push_front(v); - if (c_.size() > limit_) { + // Remove some entries if the limit has been reached. + // However, if the only group on the stack is the one + // we are currently populating, do nothing. + if (c_.size() >= limit_ + && c_.front().group_id != v.group_id) { // remove a whole group at once. const size_t gid = c_.back().group_id; while (!c_.empty() && c_.back().group_id == gid) c_.pop_back(); } + c_.push_front(v); } /// Mark all the elements of the stack as dirty void markDirty() { for (size_t i = 0; i != c_.size(); ++i) c_[i].lyx_clean = false; - } + } private: /// Internal contents. @@ -181,21 +189,21 @@ private: struct Undo::Private { - Private(Buffer & buffer) : buffer_(buffer), undo_finished_(true), + Private(Buffer & buffer) : buffer_(buffer), undo_finished_(true), group_id(0), group_level(0) {} - + // Do one undo/redo step - void doTextUndoOrRedo(DocIterator & cur, UndoElementStack & stack, + void doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, UndoElementStack & otherStack); // Apply one undo/redo group. Returns false if no undo possible. - bool textUndoOrRedo(DocIterator & cur, bool isUndoOperation); + bool textUndoOrRedo(CursorData & cur, bool isUndoOperation); /// void doRecordUndo(UndoKind kind, DocIterator const & cell, pit_type first_pit, pit_type last_pit, - DocIterator const & cur, + CursorData const & cur, bool isFullBuffer, UndoElementStack & stack); /// @@ -203,7 +211,7 @@ struct Undo::Private DocIterator const & cell, pit_type first_pit, pit_type last_pit, - DocIterator const & cur, + CursorData const & cur, bool isFullBuffer); /// @@ -246,8 +254,10 @@ void Undo::clear() d->undostack_.clear(); d->redostack_.clear(); d->undo_finished_ = true; - d->group_id = 0; - d->group_level = 0; + // 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; } @@ -267,7 +277,7 @@ void Undo::markDirty() { d->undo_finished_ = true; d->undostack_.markDirty(); - d->redostack_.markDirty(); + d->redostack_.markDirty(); } @@ -288,7 +298,7 @@ static bool samePar(StableDocIterator const & i1, StableDocIterator const & i2) void Undo::Private::doRecordUndo(UndoKind kind, DocIterator const & cell, pit_type first_pit, pit_type last_pit, - DocIterator const & cur, + CursorData const & cur_before, bool isFullBuffer, UndoElementStack & stack) { @@ -311,15 +321,18 @@ void Undo::Private::doRecordUndo(UndoKind kind, && samePar(stack.top().cell, cell) && stack.top().kind == kind && stack.top().from == from - && stack.top().end == end) + && stack.top().end == end) { + // reset cur_after; it will be filled correctly by endUndoGroup. + stack.top().cur_after = CursorData(); return; + } if (isFullBuffer) LYXERR(Debug::UNDO, "Create full buffer undo element of group " << group_id); else LYXERR(Debug::UNDO, "Create undo element of group " << group_id); // create the position information of the Undo entry - UndoElement undo(kind, cur, cell, from, end, 0, 0, + UndoElement undo(kind, cur_before, cell, from, end, 0, 0, buffer_.params(), isFullBuffer, buffer_.isClean(), group_id); // fill in the real data to be saved @@ -332,7 +345,7 @@ void Undo::Private::doRecordUndo(UndoKind kind, // main Text _is_ the whole document. // record the relevant paragraphs Text const * text = cell.text(); - LASSERT(text, /**/); + LBUFERR(text); ParagraphList const & plist = text->paragraphs(); ParagraphList::const_iterator first = plist.begin(); advance(first, first_pit); @@ -350,11 +363,11 @@ void Undo::Private::doRecordUndo(UndoKind kind, void Undo::Private::recordUndo(UndoKind kind, DocIterator const & cell, pit_type first_pit, pit_type last_pit, - DocIterator const & cur, + CursorData const & cur, bool isFullBuffer) { - LASSERT(first_pit <= cell.lastpit(), /**/); - LASSERT(last_pit <= cell.lastpit(), /**/); + LASSERT(first_pit <= cell.lastpit(), return); + LASSERT(last_pit <= cell.lastpit(), return); doRecordUndo(kind, cell, first_pit, last_pit, cur, isFullBuffer, undostack_); @@ -372,7 +385,7 @@ void Undo::Private::recordUndo(UndoKind kind, } -void Undo::Private::doTextUndoOrRedo(DocIterator & cur, UndoElementStack & stack, UndoElementStack & otherstack) +void Undo::Private::doTextUndoOrRedo(CursorData & cur, UndoElementStack & stack, UndoElementStack & otherstack) { // Adjust undo stack and get hold of current undo data. UndoElement & undo = stack.top(); @@ -384,14 +397,15 @@ void Undo::Private::doTextUndoOrRedo(DocIterator & cur, UndoElementStack & stack DocIterator cell_dit = undo.cell.asDocIterator(&buffer_); doRecordUndo(ATOMIC_UNDO, cell_dit, - undo.from, cell_dit.lastpit() - undo.end, cur, + undo.from, cell_dit.lastpit() - undo.end, undo.cur_after, undo.isFullBuffer, otherstack); + otherstack.top().cur_after = undo.cur_before; // This does the actual undo/redo. //LYXERR0("undo, performing: " << undo); DocIterator dit = undo.cell.asDocIterator(&buffer_); if (undo.isFullBuffer) { - LASSERT(undo.pars, /**/); + LBUFERR(undo.pars); // This is a full document delete otherstack.top().bparams; otherstack.top().bparams = new BufferParams(buffer_.params()); @@ -404,15 +418,15 @@ void Undo::Private::doTextUndoOrRedo(DocIterator & cur, UndoElementStack & stack // gained by storing just 'a few' paragraphs (most if not // all math inset cells have just one paragraph!) //LYXERR0("undo.array: " << *undo.array); - LASSERT(undo.array, /**/); + LBUFERR(undo.array); dit.cell().swap(*undo.array); delete undo.array; undo.array = 0; } else { // Some finer machinery is needed here. Text * text = dit.text(); - LASSERT(text, /**/); - LASSERT(undo.pars, /**/); + LBUFERR(text); + LBUFERR(undo.pars); ParagraphList & plist = text->paragraphs(); // remove new stuff between first and last @@ -436,10 +450,13 @@ void Undo::Private::doTextUndoOrRedo(DocIterator & cur, UndoElementStack & stack delete undo.pars; undo.pars = 0; } - LASSERT(undo.pars == 0, /**/); - LASSERT(undo.array == 0, /**/); - cur = undo.cursor.asDocIterator(&buffer_); + // We'll clean up in release mode. + LASSERT(undo.pars == 0, undo.pars = 0); + LASSERT(undo.array == 0, undo.array = 0); + + if (!undo.cur_before.empty()) + cur = undo.cur_before; if (undo.lyx_clean) buffer_.markClean(); else @@ -449,7 +466,7 @@ void Undo::Private::doTextUndoOrRedo(DocIterator & cur, UndoElementStack & stack } -bool Undo::Private::textUndoOrRedo(DocIterator & cur, bool isUndoOperation) +bool Undo::Private::textUndoOrRedo(CursorData & cur, bool isUndoOperation) { undo_finished_ = true; @@ -478,13 +495,13 @@ void Undo::finishUndo() } -bool Undo::textUndo(DocIterator & cur) +bool Undo::textUndo(CursorData & cur) { return d->textUndoOrRedo(cur, true); } -bool Undo::textRedo(DocIterator & cur) +bool Undo::textRedo(CursorData & cur) { return d->textUndoOrRedo(cur, false); } @@ -503,8 +520,10 @@ void Undo::beginUndoGroup() 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) { // real end of the group @@ -512,17 +531,26 @@ void Undo::endUndoGroup() } } + +void Undo::endUndoGroup(CursorData const & cur) +{ + endUndoGroup(); + if (!d->undostack_.empty() && d->undostack_.top().cur_after.empty()) + d->undostack_.top().cur_after = cur; +} + + // FIXME: remove these convenience functions and make // Private::recordUndo public as sole interface. The code in the // convenience functions can move to Cursor.cpp. -void Undo::recordUndo(DocIterator const & cur, UndoKind kind) +void Undo::recordUndo(CursorData const & cur, UndoKind kind) { d->recordUndo(kind, cur, cur.pit(), cur.pit(), cur, false); } -void Undo::recordUndoInset(DocIterator const & cur, UndoKind kind, +void Undo::recordUndoInset(CursorData const & cur, UndoKind kind, Inset const * inset) { if (!inset || inset == &cur.inset()) { @@ -536,25 +564,25 @@ void Undo::recordUndoInset(DocIterator const & cur, UndoKind kind, } -void Undo::recordUndo(DocIterator const & cur, UndoKind kind, pit_type from) +void Undo::recordUndo(CursorData const & cur, UndoKind kind, pit_type from) { d->recordUndo(kind, cur, cur.pit(), from, cur, false); } -void Undo::recordUndo(DocIterator const & cur, UndoKind kind, +void Undo::recordUndo(CursorData const & cur, UndoKind kind, pit_type from, pit_type to) { d->recordUndo(kind, cur, from, to, cur, false); } -void Undo::recordUndoFullDocument(DocIterator const & cur) +void Undo::recordUndoFullDocument(CursorData const & cur) { // This one may happen outside of the main undo group, so we // put it in its own subgroup to avoid complaints. beginUndoGroup(); - d->recordUndo(ATOMIC_UNDO, doc_iterator_begin(&d->buffer_), + d->recordUndo(ATOMIC_UNDO, doc_iterator_begin(&d->buffer_), 0, d->buffer_.paragraphs().size() - 1, cur, true); endUndoGroup(); }