]> git.lyx.org Git - lyx.git/blobdiff - src/undo.C
fix reading the author field.
[lyx.git] / src / undo.C
index e62cb065246e5c4608454673d54035bd089c7505..d7a36941d0b6769fd933840b2475f3ce4f988c80 100644 (file)
 #include "undo.h"
 
 #include "buffer.h"
+#include "cursor.h"
 #include "debug.h"
 #include "BufferView.h"
-#include "iterators.h"
 #include "lyxtext.h"
 #include "paragraph.h"
 
-#include "insets/updatableinset.h" // for dynamic_cast<UpdatableInset *>
+#include "mathed/math_support.h"
 
-using lyx::paroffset_type;
+#include <algorithm>
 
+using std::advance;
 
-/// The flag used by finishUndo().
-bool undo_finished;
+using lyx::par_type;
 
-/// Whether actions are not added to the undo stacks.
-bool undo_frozen;
-
-Undo::Undo(undo_kind kind_, int text_, int index_,
-          int first_par_, int end_par_, int cursor_par_, int cursor_pos_)
-       :
-               kind(kind_),
-               text(text_),
-               index(index_),
-               first_par(first_par_),
-               end_par(end_par_),
-               cursor_par(cursor_par_),
-               cursor_pos(cursor_pos_)
-{}
+using std::endl;
 
 
 namespace {
 
-std::ostream & operator<<(std::ostream & os, Undo const & undo)
-{
-       return os << " text: " << undo.text
-               << " index: " << undo.index
-               << " first: " << undo.first_par
-               << " from end: " << undo.end_par
-               << " cursor: " << undo.cursor_par
-               << "/" << undo.cursor_pos;
-}
-
-
-// translates LyXText pointer into offset count from document begin
-ParIterator text2pit(LyXText * text, int & tcount)
-{
-       tcount = 0;
-       Buffer * buf = text->bv()->buffer();
-       ParIterator pit = buf->par_iterator_begin();
-       ParIterator end = buf->par_iterator_end();
-
-       // it.text() returns 0 for outermost text.
-       if (text == text->bv()->text)
-               return pit;
-
-       for ( ; pit != end; ++pit, ++tcount)
-               if (pit.text() == text)
-                       return pit;
-       lyxerr << "undo: should not happen" << std::endl;
-       return end;
-}
-
-
-// translates offset from buffer begin to ParIterator
-ParIterator num2pit(BufferView * bv, int num)
-{
-       Buffer * buf = bv->buffer();
-       ParIterator pit = buf->par_iterator_begin();
-       ParIterator end = buf->par_iterator_end();
-
-       for ( ; num && pit != end; ++pit, --num)
-               ;
-
-       if (pit != end)
-               return pit;
-
-       // don't crash early...
-       lyxerr << "undo: num2pit: num: " << num << std::endl;
-       BOOST_ASSERT(false);
-       return buf->par_iterator_begin();
-}
+/// The flag used by finishUndo().
+bool undo_finished;
 
 
-// translates offset from buffer begin to LyXText
-LyXText * pit2text(BufferView * bv, ParIterator const & pit)
+std::ostream & operator<<(std::ostream & os, Undo const & undo)
 {
-       LyXText * text = pit.text();
-       return text ? text : bv->text;
+       return os << " from: " << undo.from
+               << " end: " << undo.end
+               << " cursor:\n" << undo.cursor;
 }
 
 
 void recordUndo(Undo::undo_kind kind,
-       LyXText * text, paroffset_type first_par, paroffset_type last_par,
+       LCursor & cur, par_type first_par, par_type last_par,
        limited_stack<Undo> & stack)
 {
-       Buffer * buf = text->bv()->buffer();
+       BOOST_ASSERT(first_par <= cur.lastpar());
+       BOOST_ASSERT(last_par <= cur.lastpar());
 
-       int const end_par = text->ownerParagraphs().size() - last_par;
-
-       // Undo::ATOMIC are always recorded (no overlapping there).
-       // overlapping only with insert and delete inside one paragraph:
-       // nobody wants all removed character appear one by one when undoing.
-       if (!undo_finished && kind != Undo::ATOMIC) {
-               // Check whether storing is needed.
-               if (!buf->undostack().empty()
-                   && buf->undostack().top().kind == kind
-                   && buf->undostack().top().first_par == first_par
-                   && buf->undostack().top().end_par == end_par) {
-                       // No additonal undo recording needed -
-                       // effectively, we combine undo recordings to one.
-                       return;
-               }
-       }
+       if (first_par > last_par)
+               std::swap(first_par, last_par);
 
-       // make and push the Undo entry
-       int textnum;
-       ParIterator pit = text2pit(text, textnum);
-       stack.push(Undo(kind, textnum, pit.index(),
-               first_par, end_par, text->cursor.par(), text->cursor.pos()));
-       lyxerr << "undo record: " << stack.top() << std::endl;
+       // create the position information of the Undo entry
+       Undo undo;
+       undo.kind = kind;
+       undo.cursor = StableDocIterator(cur);
+       undo.from = first_par;
+       undo.end = cur.lastpar() - last_par;
 
-       // record the relevant paragraphs
-       ParagraphList & undo_pars = stack.top().pars;
+       // Undo::ATOMIC are always recorded (no overlapping there).
+       // As nobody wants all removed character appear one by one when undoing,
+       // we want combine 'similar' non-ATOMIC undo recordings to one.
+       if (!undo_finished
+           && kind != Undo::ATOMIC
+           && !stack.empty()
+           && stack.top().cursor.size() == undo.cursor.size()
+                 && stack.top().kind == undo.kind
+                 && stack.top().from == undo.from
+                 && stack.top().end == undo.end)
+               return;
 
-       ParagraphList & plist = text->ownerParagraphs();
-       ParagraphList::iterator first = plist.begin();
-       advance(first, first_par);
-       ParagraphList::iterator last = plist.begin();
-       advance(last, last_par);
+       // fill in the real data to be saved
+       if (cur.inMathed()) {
+               // simply use the whole cell
+               undo.array = asString(cur.cell());
+       } else {
+               // some more effort needed here as 'the whole cell' of the
+               // main LyXText _is_ the whole document.
+               // record the relevant paragraphs
+               LyXText * text = cur.text();
+               BOOST_ASSERT(text);
+               ParagraphList & plist = text->paragraphs();
+               ParagraphList::iterator first = plist.begin();
+               advance(first, first_par);
+               ParagraphList::iterator last = plist.begin();
+               advance(last, last_par + 1);
+               undo.pars = ParagraphList(first, last);
+       }
 
-       for (ParagraphList::iterator it = first; it != last; ++it)
-               undo_pars.push_back(*it);
-       undo_pars.push_back(*last);
+       // push the undo entry to undo stack
+       //lyxerr << "undo record: " << stack.top() << std::endl;
+       stack.push(undo);
 
-       // and make sure that next time, we should be combining if possible
+       // next time we'll try again to combine entries if possible
        undo_finished = false;
 }
 
 
-// returns false if no undo possible
-bool performUndoOrRedo(BufferView * bv, Undo const & undo)
+void performUndoOrRedo(BufferView & bv, Undo const & undo)
 {
+       LCursor & cur = bv.cursor();
        lyxerr << "undo, performing: " << undo << std::endl;
-       ParIterator pit = num2pit(bv, undo.text);
-       LyXText * text = pit2text(bv, pit);
-       ParagraphList & plist = text->ownerParagraphs();
+       cur.setCursor(undo.cursor.asDocIterator(&bv.buffer()->inset()));
+       cur.selection() = false;
+
+       if (cur.inMathed()) {
+               // We stored the full cell here as there is not much to be
+               // gained by storing just 'a few' paragraphs (most if not
+               // all math inset cells have just one paragraph!)
+               asArray(undo.array, cur.cell());
+       } else {
+               // Some finer machinery is needed here.
+               LyXText * text = cur.text();
+               BOOST_ASSERT(text);
+               ParagraphList & plist = text->paragraphs();
 
-       // remove new stuff between first and last
-       {
+               // remove new stuff between first and last
                ParagraphList::iterator first = plist.begin();
-               advance(first, undo.first_par);
+               advance(first, undo.from);
                ParagraphList::iterator last = plist.begin();
-               advance(last, plist.size() - undo.end_par);
-               plist.erase(first, ++last);
-       }
+               advance(last, plist.size() - undo.end);
+               plist.erase(first, last);
 
-       // re-insert old stuff instead
-       if (plist.empty()) {
-               plist.assign(undo.pars.begin(), undo.pars.end());
-       } else {
-               ParagraphList::iterator first = plist.begin();
-               advance(first, undo.first_par);
+               // re-insert old stuff instead
+               first = plist.begin();
+               advance(first, undo.from);
                plist.insert(first, undo.pars.begin(), undo.pars.end());
        }
 
-       // set cursor
-       lyxerr <<   "undo, text: " << undo.text
-              << " inset: " << pit.inset()
-              << " index: " << undo.index
-              << " par: " << undo.cursor_par
-              << " pos: " << undo.cursor_pos
-              << std::endl;
-
-       // set cursor again to force the position to be the right one
-       text->cursor.par(undo.cursor_par);
-       text->cursor.pos(undo.cursor_pos);
-
-       // clear any selection
-       text->clearSelection();
-       text->selection.cursor = text->cursor;
-       text->updateCounters();
-
-       // rebreak the entire lyxtext
-       bv->text->fullRebreak();
-
-       pit.lockPath(bv);
-       
+       cur.resetAnchor();
        finishUndo();
-       return true;
 }
 
 
 // returns false if no undo possible
-bool textUndoOrRedo(BufferView * bv,
+bool textUndoOrRedo(BufferView & bv,
        limited_stack<Undo> & stack, limited_stack<Undo> & otherstack)
 {
        if (stack.empty()) {
                // nothing to do
-               freezeUndo();
-               bv->unlockInset(bv->theLockingInset());
                finishUndo();
-               unFreezeUndo();
                return false;
        }
 
@@ -226,91 +154,106 @@ bool textUndoOrRedo(BufferView * bv,
        stack.pop();
        finishUndo();
 
-       if (!undo_frozen) {
-               otherstack.push(undo);
+       // this implements redo
+       otherstack.push(undo);
+       DocIterator dit =
+               undo.cursor.asDocIterator(&bv.buffer()->inset());
+       if (dit.inMathed()) {
+               // Easy way out: store a full cell.
+               otherstack.top().array = asString(dit.cell());
+       } else {
+               // As cells might be too large in texted, store just a part
+               // of the paragraph list.
                otherstack.top().pars.clear();
-               ParIterator pit = num2pit(bv, undo.text);
-               ParagraphList & plist = pit.plist();
-               if (undo.first_par + undo.end_par <= int(plist.size())) {
+               LyXText * text = dit.text();
+               BOOST_ASSERT(text);
+               ParagraphList & plist = text->paragraphs();
+               if (undo.from + undo.end <= int(plist.size())) {
                        ParagraphList::iterator first = plist.begin();
-                       advance(first, undo.first_par);
+                       advance(first, undo.from);
                        ParagraphList::iterator last = plist.begin();
-                       advance(last, plist.size() - undo.end_par + 1);
+                       advance(last, plist.size() - undo.end);
                        otherstack.top().pars.insert(otherstack.top().pars.begin(), first, last);
                }
-               LyXText * text = pit2text(bv, pit);
-               otherstack.top().cursor_pos = text->cursor.pos();
-               otherstack.top().cursor_par = text->cursor.par();
-               lyxerr << " undo other: " << otherstack.top() << std::endl;
        }
+       otherstack.top().cursor = bv.cursor();
+       //lyxerr << " undo other: " << otherstack.top() << std::endl;
 
-       // Now we can unlock the inset for safety because the inset
-       // pointer could be changed during the undo-function. Anyway
-       // if needed we have to lock the right inset/position if this
-       // is requested.
-       freezeUndo();
-       bv->unlockInset(bv->theLockingInset());
-       bool const ret = performUndoOrRedo(bv, undo);
-       unFreezeUndo();
-       return ret;
+       performUndoOrRedo(bv, undo);
+       return true;
 }
 
 } // namespace anon
 
 
-void freezeUndo()
+void finishUndo()
 {
-       // this is dangerous and for internal use only
-       undo_frozen = true;
+       // makes sure the next operation will be stored
+       undo_finished = true;
 }
 
 
-void unFreezeUndo()
+bool textUndo(BufferView & bv)
 {
-       // this is dangerous and for internal use only
-       undo_frozen = false;
+       return textUndoOrRedo(bv, bv.buffer()->undostack(),
+                             bv.buffer()->redostack());
 }
 
 
-void finishUndo()
+bool textRedo(BufferView & bv)
 {
-       // makes sure the next operation will be stored
-       undo_finished = true;
+       return textUndoOrRedo(bv, bv.buffer()->redostack(),
+                             bv.buffer()->undostack());
 }
 
 
-bool textUndo(BufferView * bv)
+void recordUndo(Undo::undo_kind kind,
+       LCursor & cur, par_type first, par_type last)
 {
-       return textUndoOrRedo(bv, bv->buffer()->undostack(),
-                             bv->buffer()->redostack());
+       Buffer * buf = cur.bv().buffer();
+       recordUndo(kind, cur, first, last, buf->undostack());
+       buf->redostack().clear();
+       lyxerr << "undostack:\n";
+       for (size_t i = 0, n = buf->undostack().size(); i != n && i < 6; ++i)
+               lyxerr << "  " << i << ": " << buf->undostack()[i] << std::endl;
 }
 
 
-bool textRedo(BufferView * bv)
+void recordUndo(LCursor & cur, Undo::undo_kind kind)
 {
-       return textUndoOrRedo(bv, bv->buffer()->redostack(),
-                             bv->buffer()->undostack());
+       recordUndo(kind, cur, cur.par(), cur.par());
 }
 
 
-void recordUndo(Undo::undo_kind kind,
-       LyXText const * text, paroffset_type first, paroffset_type last)
+void recordUndoInset(LCursor & cur, Undo::undo_kind kind)
 {
-       if (undo_frozen)
-               return;
-       Buffer * buf = text->bv()->buffer();
-       recordUndo(kind, const_cast<LyXText *>(text), first, last, buf->undostack());
-       buf->redostack().clear();
+       LCursor c = cur;
+       c.pop();
+       recordUndo(c, kind);
+}
+
+
+void recordUndoSelection(LCursor & cur, Undo::undo_kind kind)
+{
+       recordUndo(kind, cur, cur.selBegin().par(), cur.selEnd().par());
+}
+
+
+void recordUndo(LCursor & cur, Undo::undo_kind kind, par_type from)
+{
+       recordUndo(kind, cur, cur.par(), from);
 }
 
 
-void recordUndo(Undo::undo_kind kind, LyXText const * text, paroffset_type par)
+void recordUndo(LCursor & cur, Undo::undo_kind kind,
+       par_type from, par_type to)
 {
-       recordUndo(kind, text, par, par);
+       recordUndo(kind, cur, from, to);
 }
 
 
-void recordUndo(BufferView * bv, Undo::undo_kind kind)
+void recordUndoFullDocument(LCursor &)
 {
-       recordUndo(kind, bv->text, bv->text->cursor.par());
+       //recordUndo(Undo::ATOMIC,
+       //      cur, 0, cur.bv().text()->paragraphs().size() - 1);
 }