From 4c8d536692beabcec88771a53b40eaf6acd76f49 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20P=C3=B6nitz?= Date: Mon, 8 Mar 2004 21:14:45 +0000 Subject: [PATCH] redo undo git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8481 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/BufferView_pimpl.C | 1 + src/ChangeLog | 6 + src/cursor.C | 34 +---- src/cursor.h | 4 +- src/dociterator.C | 49 ++++++- src/dociterator.h | 32 +++++ src/insets/insetcollapsable.C | 8 +- src/lyxfunc.C | 2 +- src/mathed/math_nestinset.C | 28 ++-- src/text.C | 7 +- src/text2.C | 23 +-- src/text3.C | 49 ++----- src/undo.C | 258 ++++++++++++---------------------- src/undo.h | 28 ++-- 14 files changed, 225 insertions(+), 304 deletions(-) diff --git a/src/BufferView_pimpl.C b/src/BufferView_pimpl.C index a523795405..c7d75389e9 100644 --- a/src/BufferView_pimpl.C +++ b/src/BufferView_pimpl.C @@ -607,6 +607,7 @@ void BufferView::Pimpl::update() updateScrollbar(); } screen().redraw(*bv_); + bv_->owner()->view_state_changed(); } diff --git a/src/ChangeLog b/src/ChangeLog index 5ef35da4c6..c1ad6d27cb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ + +2004-03-08 André Pönitz + + * undo.[Ch]: use 'StableDocumentIterator' as base for + the Undo struct. + 2004-03-07 Jürgen Spitzmüller * LaTeXFeatures.C: diff --git a/src/cursor.C b/src/cursor.C index e712ea42d6..ab0fc05d94 100644 --- a/src/cursor.C +++ b/src/cursor.C @@ -85,7 +85,7 @@ void LCursor::setCursor(DocumentIterator const & cur, bool sel) DispatchResult LCursor::dispatch(FuncRequest const & cmd0) { - lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl; + //lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl; BOOST_ASSERT(pos() <= lastpos()); BOOST_ASSERT(idx() <= lastidx()); BOOST_ASSERT(par() <= lastpar()); @@ -1235,38 +1235,6 @@ CursorSlice LCursor::normalAnchor() } -/* -DispatchResult dispatch(LCursor & cur, FuncRequest const & cmd) -{ - // mouse clicks are somewhat special - // check - switch (cmd.action) { - case LFUN_MOUSE_PRESS: - case LFUN_MOUSE_MOTION: - case LFUN_MOUSE_RELEASE: - case LFUN_MOUSE_DOUBLE: { - CursorSlice & pos = back(); - int x = 0; - int y = 0; - getPos(x, y); - if (x < cmd.x && pos() != 0) { - DispatchResult const res = prevAtom().nucleus()->dispatch(cmd); - if (res.dispatched()) - return res; - } - if (x > cmd.x && pos() != lastpos()) { - DispatchResult const res = inset()->dispatch(cmd); - if (res.dispatched()) - return res; - } - } - default: - break; - } -} -*/ - - void LCursor::handleFont(string const & font) { lyxerr << "LCursor::handleFont: " << font << endl; diff --git a/src/cursor.h b/src/cursor.h index e14fb97006..6654f1660b 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -30,9 +30,7 @@ class MathUnknownInset; class MathGridInset; -/** - * The cursor class describes the position of a cursor within a document. - */ +/// The cursor class describes the position of a cursor within a document. // The public inheritance should go in favour of a suitable data member // (or maybe private inheritance) at some point of time. diff --git a/src/dociterator.C b/src/dociterator.C index fb7b7482ad..1293fb3d02 100644 --- a/src/dociterator.C +++ b/src/dociterator.C @@ -14,9 +14,6 @@ -std::ostream & operator<<(std::ostream & os, DocumentIterator const & cur); - - DocumentIterator::DocumentIterator() : bv_(0) {} @@ -393,9 +390,49 @@ DocumentIterator insetEnd() } -std::ostream & operator<<(std::ostream & os, DocumentIterator const & cur) +std::ostream & operator<<(std::ostream & os, DocumentIterator const & dit) { - for (size_t i = 0, n = cur.size(); i != n; ++i) - os << " " << cur.operator[](i) << "\n"; + os << "bv: " << &dit.bv() << "\n"; + for (size_t i = 0, n = dit.size(); i != n; ++i) + os << " " << dit.operator[](i) << "\n"; return os; } + + + +/////////////////////////////////////////////////////// + +StableDocumentIterator::StableDocumentIterator(const DocumentIterator & dit) +{ + data_ = dit; + for (size_t i = 0, n = data_.size(); i != n; ++i) + data_[i].inset_ = 0; +} + + +DocumentIterator +StableDocumentIterator::asDocumentIterator(BufferView & bv) const +{ + // this function re-creates the cache of inset pointers + //lyxerr << "converting:\n" << *this << std::endl; + DocumentIterator dit(bv); + dit.clear(); + InsetBase * inset = 0; + for (size_t i = 0, n = data_.size(); i != n; ++i) { + dit.push_back(data_[i]); + dit.back().inset_ = inset; + if (i + 1 != n) + inset = dit.nextInset(); + } + //lyxerr << "convert:\n" << *this << " to:\n" << dit << std::endl; + return dit; +} + + +std::ostream & operator<<(std::ostream & os, StableDocumentIterator const & dit) +{ + for (size_t i = 0, n = dit.data_.size(); i != n; ++i) + os << " " << dit.data_[i] << "\n"; + return os; +} + diff --git a/src/dociterator.h b/src/dociterator.h index 24c2b49a69..22e49c8b45 100644 --- a/src/dociterator.h +++ b/src/dociterator.h @@ -15,6 +15,7 @@ #include "cursor_slice.h" #include +#include class BufferView; class MathAtom; @@ -23,6 +24,7 @@ class Paragraph; class Row; + // only needed for gcc 2.95, remove when support terminated template bool ptr_cmp(A const * a, B const * b) @@ -166,6 +168,9 @@ public: void forwardIdx(); /// move on one inset void forwardInset(); + /// output + friend std::ostream & + operator<<(std::ostream & os, DocumentIterator const & cur); private: /// @@ -182,4 +187,31 @@ DocumentIterator insetBegin(BufferView & bv, InsetBase * inset); /// DocumentIterator insetEnd(); + +// The difference to a ('non stable') DocumentIterator is the removed +// (overwritte by 0...) part of the CursorSlice data items. So this thing +// is suitable for external storage, but not for iteration as such. + +class StableDocumentIterator { +public: + /// + StableDocumentIterator() {} + /// non-explicit intended + StableDocumentIterator(const DocumentIterator & it); + /// + DocumentIterator asDocumentIterator(BufferView & bv) const; + /// + size_t size() const { return data_.size(); } + /// + friend std::ostream & + operator<<(std::ostream & os, StableDocumentIterator const & cur); + /// + friend std::istream & + operator>>(std::istream & is, StableDocumentIterator & cur); +private: + std::vector data_; +}; + +bool operator==(StableDocumentIterator const &, StableDocumentIterator const &); + #endif diff --git a/src/insets/insetcollapsable.C b/src/insets/insetcollapsable.C index 17b81c6bf2..8174217e5d 100644 --- a/src/insets/insetcollapsable.C +++ b/src/insets/insetcollapsable.C @@ -272,7 +272,7 @@ bool InsetCollapsable::hitButton(FuncRequest const & cmd) const string const InsetCollapsable::getNewLabel(string const & l) const { - string la; + string label; pos_type const max_length = 15; pos_type const p_siz = inset.paragraphs().begin()->size(); pos_type const n = min(max_length, p_siz); @@ -281,13 +281,13 @@ string const InsetCollapsable::getNewLabel(string const & l) const for( ; i < n && j < p_siz; ++j) { if (inset.paragraphs().begin()->isInset(j)) continue; - la += inset.paragraphs().begin()->getChar(j); + label += inset.paragraphs().begin()->getChar(j); ++i; } if (inset.paragraphs().size() > 1 || (i > 0 && j < p_siz)) { - la += "..."; + label += "..."; } - return la.empty() ? l : la; + return label.empty() ? l : label; } diff --git a/src/lyxfunc.C b/src/lyxfunc.C index dee64f6b12..63cda7cf37 100644 --- a/src/lyxfunc.C +++ b/src/lyxfunc.C @@ -820,7 +820,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd, bool verbose) kb_action action = cmd.action; lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl; - lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl; + //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl; // we have not done anything wrong yet. errorstat = false; diff --git a/src/mathed/math_nestinset.C b/src/mathed/math_nestinset.C index 099f31766c..2c58c03fb3 100644 --- a/src/mathed/math_nestinset.C +++ b/src/mathed/math_nestinset.C @@ -307,7 +307,7 @@ void MathNestInset::handleFont { // this whole function is a hack and won't work for incremental font // changes... - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); if (cur.inset()->asMathInset()->name() == font) cur.handleFont(font); @@ -320,7 +320,7 @@ void MathNestInset::handleFont void MathNestInset::handleFont2(LCursor & cur, string const & arg) { - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); LyXFont font; bool b; bv_funcs::string2font(arg, font, b); @@ -354,7 +354,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) is >> n; if (was_macro) cur.macroModeClose(); - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); cur.selPaste(n); break; } @@ -531,13 +531,13 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) case LFUN_DELETE_WORD_BACKWARD: case LFUN_BACKSPACE: - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); cur.backspace(); break; case LFUN_DELETE_WORD_FORWARD: case LFUN_DELETE: - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); cur.erase(); cur.dispatched(FINISHED_LEFT); break; @@ -566,7 +566,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) cur.dispatched(FINISHED_RIGHT); break; } - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); if (cmd.argument.size() != 1) { cur.insert(cmd.argument); break; @@ -604,7 +604,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) } case LFUN_CUT: - //recordUndo(cur, Undo::DELETE); + recordUndo(cur, Undo::DELETE); cur.selCut(); break; @@ -618,7 +618,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) if (cmd.argument.empty()) { // do superscript if LyX handles // deadkeys - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); script(cur, true); } break; @@ -695,14 +695,14 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) case LFUN_MATH_SIZE: #if 0 if (!arg.empty()) { - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); cur.setSize(arg); } #endif break; case LFUN_INSERT_MATRIX: { - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); unsigned int m = 1; unsigned int n = 1; string v_align; @@ -728,14 +728,14 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) ls = '('; if (rs.empty()) rs = ')'; - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); cur.handleNest(MathAtom(new MathDelimInset(ls, rs))); break; } case LFUN_SPACE_INSERT: case LFUN_MATH_SPACE: - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); cur.insert(MathAtom(new MathSpaceInset(","))); break; @@ -746,7 +746,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) case LFUN_INSET_ERT: // interpret this as if a backslash was typed - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); interpret(cur, '\\'); break; @@ -754,7 +754,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) // handling such that "self-insert" works on "arbitrary stuff" too, and // math-insert only handles special math things like "matrix". case LFUN_INSERT_MATH: - //recordUndo(cur, Undo::ATOMIC); + recordUndo(cur, Undo::ATOMIC); cur.niceInsert(cmd.argument); break; diff --git a/src/text.C b/src/text.C index 74ccfbef41..8cef593271 100644 --- a/src/text.C +++ b/src/text.C @@ -898,6 +898,8 @@ void LyXText::redoParagraph(LCursor & cur) void LyXText::insertChar(LCursor & cur, char c) { BOOST_ASSERT(this == cur.text()); + BOOST_ASSERT(c != Paragraph::META_INSET); + recordUndo(cur, Undo::INSERT); Paragraph & par = cur.paragraph(); @@ -983,10 +985,7 @@ void LyXText::insertChar(LCursor & cur, char c) } } - // Here case LyXText::InsertInset already inserted the character - if (c != Paragraph::META_INSET) - par.insertChar(cur.pos(), c); - + par.insertChar(cur.pos(), c); setCharFont(pit, cur.pos(), rawtmpfont); current_font = rawtmpfont; diff --git a/src/text2.C b/src/text2.C index f5acc81d85..9515b42662 100644 --- a/src/text2.C +++ b/src/text2.C @@ -72,7 +72,7 @@ using std::string; LyXText::LyXText(BufferView * bv, bool in_inset) - : height_(0), width_(0), maxwidth_(bv ? bv->workWidth() : 100), + : width_(0), maxwidth_(bv ? bv->workWidth() : 100), height_(0), background_color_(LColor::background), bv_owner(bv), in_inset_(in_inset), xo_(0), yo_(0) {} @@ -865,19 +865,9 @@ void LyXText::updateCounters() void LyXText::insertInset(LCursor & cur, InsetBase * inset) { BOOST_ASSERT(this == cur.text()); - recordUndo(cur); - freezeUndo(); + BOOST_ASSERT(inset); cur.paragraph().insertInset(cur.pos(), inset); - // Just to rebreak and refresh correctly. - // The character will not be inserted a second time - insertChar(cur, Paragraph::META_INSET); - // If we enter a highly editable inset the cursor should be before - // the inset. After an undo LyX tries to call inset->edit(...) - // and fails if the cursor is behind the inset and getInset - // does not return the inset! - if (isHighlyEditableInset(inset)) - cursorLeft(cur); - unFreezeUndo(); + redoParagraph(cur); } @@ -1014,7 +1004,6 @@ void LyXText::setSelectionRange(LCursor & cur, lyx::pos_type length) void LyXText::replaceSelectionWithString(LCursor & cur, string const & str) { recordUndo(cur); - freezeUndo(); // Get font setting before we cut pos_type pos = cur.selEnd().pos(); @@ -1032,7 +1021,6 @@ void LyXText::replaceSelectionWithString(LCursor & cur, string const & str) // Cut the selection cutSelection(cur, true, false); - unFreezeUndo(); } @@ -1124,7 +1112,10 @@ void LyXText::setCursor(CursorSlice & cur, par_type par, } if (pos > end) { - lyxerr << "dont like 2 please report" << endl; + lyxerr << "dont like 2, pos: " << pos + << " size: " << para.size() + << " row.pos():" << row.pos() + << " par: " << par << endl; // This shouldn't happen. BOOST_ASSERT(false); } diff --git a/src/text3.C b/src/text3.C index 113d7b90a3..ba25ab6020 100644 --- a/src/text3.C +++ b/src/text3.C @@ -90,9 +90,6 @@ namespace { void toggleAndShow(LCursor & cur, LyXText * text, LyXFont const & font, bool toggleall = true) { - if (!cur.bv().available()) - return; - text->toggleFree(cur, font, toggleall); if (font.language() != ignore_language || @@ -106,7 +103,6 @@ namespace { text->setCursor(cur, cur.par(), cur.pos(), false, !cur.boundary()); } - cur.update(); } @@ -120,17 +116,17 @@ namespace { } - void finishChange(LCursor & cur, bool selecting = false) + void finishChange(LCursor & cur, bool selecting) { finishUndo(); moveCursor(cur, selecting); - cur.bv().owner()->view_state_changed(); } void mathDispatch(LCursor & cur, LyXText * text, FuncRequest const & cmd, bool display) { + recordUndo(cur); string sel = cur.selectionAsString(false); lyxerr << "selection is: '" << sel << "'" << endl; @@ -341,6 +337,7 @@ void doInsertInset(LCursor & cur, LyXText * text, if (!inset) return; + recordUndo(cur); bool gotsel = false; if (cur.selection()) { cur.bv().owner()->dispatch(FuncRequest(LFUN_CUT)); @@ -410,19 +407,19 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) case LFUN_DELETE_WORD_FORWARD: cur.clearSelection(); deleteWordForward(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_DELETE_WORD_BACKWARD: cur.clearSelection(); deleteWordBackward(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_DELETE_LINE_FORWARD: cur.clearSelection(); deleteLineForward(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_WORDRIGHT: @@ -432,7 +429,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) cursorLeftOneWord(cur); else cursorRightOneWord(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_WORDLEFT: @@ -442,21 +439,21 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) cursorRightOneWord(cur); else cursorLeftOneWord(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_BEGINNINGBUF: if (!cur.mark()) cur.clearSelection(); cursorTop(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_ENDBUF: if (!cur.mark()) cur.clearSelection(); cursorBottom(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_RIGHT: @@ -569,7 +566,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) if (!cur.mark()) cur.clearSelection(); cursorUpParagraph(cur); - finishChange(cur); + finishChange(cur, false); break; case LFUN_DOWN_PARAGRAPH: @@ -634,7 +631,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) cutSelection(cur, true, false); } moveCursor(cur, false); - bv->owner()->view_state_changed(); break; case LFUN_DELETE_SKIP: @@ -664,7 +660,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) } else { cutSelection(cur, true, false); } - bv->owner()->view_state_changed(); bv->switchKeyMap(); cur.update(); break; @@ -688,7 +683,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) cur.update(); cur.resetAnchor(); bv->switchKeyMap(); - bv->owner()->view_state_changed(); break; case LFUN_BREAKPARAGRAPHKEEPLAYOUT: @@ -697,7 +691,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) cur.update(); cur.resetAnchor(); bv->switchKeyMap(); - bv->owner()->view_state_changed(); break; case LFUN_BREAKPARAGRAPH_SKIP: { @@ -717,7 +710,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) cur.update(); // anchor() = cur; bv->switchKeyMap(); - bv->owner()->view_state_changed(); break; } @@ -774,6 +766,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) } case LFUN_INSET_INSERT: { + recordUndo(cur); InsetBase * inset = createInset(bv, cmd); if (inset) insertInset(cur, inset); @@ -1192,7 +1185,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) bv->haveSelection(cur.selection()); bv->switchKeyMap(); - bv->owner()->view_state_changed(); bv->owner()->updateMenubar(); bv->owner()->updateToolbar(); break; @@ -1229,7 +1221,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) // real_current_font.number can change so we need to // update the minibuffer if (old_font != real_current_font) - bv->owner()->view_state_changed(); bv->updateScrollbar(); break; } @@ -1341,7 +1332,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setEmph(LyXFont::TOGGLE); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1349,7 +1339,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setSeries(LyXFont::BOLD_SERIES); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1357,7 +1346,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setNoun(LyXFont::TOGGLE); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1365,7 +1353,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setFamily(LyXFont::TYPEWRITER_FAMILY); // no good toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1373,7 +1360,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setFamily(LyXFont::SANS_FAMILY); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1381,14 +1367,12 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setFamily(LyXFont::ROMAN_FAMILY); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } case LFUN_DEFAULT: { LyXFont font(LyXFont::ALL_INHERIT, ignore_language); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1396,7 +1380,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setUnderbar(LyXFont::TOGGLE); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1404,7 +1387,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) LyXFont font(LyXFont::ALL_IGNORE); font.setLyXSize(cmd.argument); toggleAndShow(cur, this, font); - bv->owner()->view_state_changed(); break; } @@ -1416,13 +1398,11 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) font.setLanguage(lang); toggleAndShow(cur, this, font); bv->switchKeyMap(); - bv->owner()->view_state_changed(); break; } case LFUN_FREEFONT_APPLY: toggleAndShow(cur, this, freefont, toggleall); - bv->owner()->view_state_changed(); cur.message(_("Character set")); break; @@ -1435,7 +1415,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) freefont = font; toggleall = toggle; toggleAndShow(cur, this, freefont, toggleall); - bv->owner()->view_state_changed(); cur.message(_("Character set")); } break; @@ -1519,7 +1498,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) if (tclass.floats().typeExist(cmd.argument)) { // not quite sure if we want this... recordUndo(cur); - freezeUndo(); cur.clearSelection(); breakParagraph(cur); @@ -1530,8 +1508,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest const & cmd) setLayout(cur, tclass.defaultLayoutName()); setParagraph(cur, Spacing(), LYX_ALIGN_LAYOUT, string(), 0); - cur.insert(new InsetFloatList(cmd.argument)); - unFreezeUndo(); + insertInset(cur, new InsetFloatList(cmd.argument)); } else { lyxerr << "Non-existent float type: " << cmd.argument << endl; diff --git a/src/undo.C b/src/undo.C index c5a14fe45b..9d028f03c7 100644 --- a/src/undo.C +++ b/src/undo.C @@ -20,10 +20,13 @@ #include "cursor.h" #include "debug.h" #include "BufferView.h" -#include "iterators.h" #include "lyxtext.h" #include "paragraph.h" +#include "mathed/math_support.h" + +#include + using lyx::paroffset_type; @@ -38,46 +41,9 @@ bool undo_finished; 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(Buffer & buf, LyXText * text, int & tcount) -{ - tcount = 0; - ParIterator pit = buf.par_iterator_begin(); - ParIterator end = buf.par_iterator_end(); - - for ( ; pit != end; ++pit, ++tcount) - if (pit.text(buf) == text) - return pit; - lyxerr << "undo: should not happen" << std::endl; - return end; -} - - -// translates offset from buffer begin to ParIterator -ParIterator num2pit(Buffer & buf, int num) -{ - 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(); + return os << " from: " << undo.from + << " end: " << undo.end + << " cursor:\n" << undo.cursor; } @@ -85,126 +51,90 @@ void recordUndo(Undo::undo_kind kind, LCursor & cur, paroffset_type first_par, paroffset_type last_par, limited_stack & stack) { -#if 0 - DocumentIterator it = bufferBegin(cur.bv()); - DocumentIterator et = bufferEnd(); - size_t count = 0; - for ( ; it != et; it.forwardPos(), ++count) - if (it.top() == cur.top()) - lyxerr << "### found at " << count << std::endl; -#endif - - if (first_par > last_par) { - paroffset_type t = first_par; - first_par = last_par; - last_par = t; - } + BOOST_ASSERT(first_par <= cur.lastpar()); + BOOST_ASSERT(last_par <= cur.lastpar()); - Buffer & buf = *cur.bv().buffer(); - int const end_par = cur.lastpar() + 1 - last_par; + if (first_par > last_par) + std::swap(first_par, 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; - } - } + // create the position information of the Undo entry + Undo undo; + undo.kind = kind; + undo.cursor = StableDocumentIterator(cur); + undo.from = first_par; + undo.end = cur.lastpar() - last_par; - // push and fill the Undo entry - if (cur.inTexted()) { - stack.push(Undo()); - LyXText * text = cur.text(); - int textnum; - ParIterator pit = text2pit(buf, text, textnum); - Undo & undo = stack.top(); - undo.kind = kind; - undo.text = textnum; - undo.index = pit.index(); - undo.first_par = first_par; - undo.end_par = end_par; - undo.cursor_par = cur.par(); - undo.cursor_pos = cur.pos(); - undo.math = false; - //lyxerr << "undo record: " << stack.top() << std::endl; + // 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; + // 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); - - for (ParagraphList::iterator it = first; it != last; ++it) - undo.pars.push_back(*it); - undo.pars.push_back(*last); - } else { - BOOST_ASSERT(false); // not in mathed (yet) - stack.push(Undo()); - Undo & undo = stack.top(); - undo.math = false; + advance(last, last_par + 1); + undo.pars = ParagraphList(first, last); } - // and make sure that next time, we should be combining if possible + // push the undo entry to undo stack + //lyxerr << "undo record: " << stack.top() << std::endl; + stack.push(undo); + + // 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) { - Buffer & buf = *bv.buffer(); + LCursor & cur = bv.cursor(); lyxerr << "undo, performing: " << undo << std::endl; - ParIterator pit = num2pit(buf, undo.text); - LyXText * text = pit.text(buf); - ParagraphList & plist = text->paragraphs(); + cur.setCursor(undo.cursor.asDocumentIterator(bv), false); - // remove new stuff between first and last - { + 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 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; - - text->updateCounters(); - - // rebreak the entire lyxtext -#warning needed? - text->redoParagraphs(buf.paragraphs().begin(), buf.paragraphs().end()); - bv.cursor().resetAnchor(); - - ParIterator pit2 = num2pit(buf, undo.text); - advance(pit2, undo.cursor_par); - bv.setCursor(pit2, undo.cursor_pos); - + cur.resetAnchor(); finishUndo(); - return true; } @@ -212,7 +142,6 @@ bool performUndoOrRedo(BufferView & bv, Undo const & undo) bool textUndoOrRedo(BufferView & bv, limited_stack & stack, limited_stack & otherstack) { - Buffer & buf = *bv.buffer(); if (stack.empty()) { // nothing to do finishUndo(); @@ -223,45 +152,37 @@ bool textUndoOrRedo(BufferView & bv, stack.pop(); finishUndo(); + // this implements redo if (!undo_frozen) { otherstack.push(undo); - otherstack.top().pars.clear(); - ParIterator pit = num2pit(buf, undo.text); - ParagraphList & plist = pit.plist(); - if (undo.first_par + undo.end_par <= int(plist.size())) { - ParagraphList::iterator first = plist.begin(); - advance(first, undo.first_par); - ParagraphList::iterator last = plist.begin(); - advance(last, plist.size() - undo.end_par + 1); - otherstack.top().pars.insert(otherstack.top().pars.begin(), first, last); + DocumentIterator dit = undo.cursor.asDocumentIterator(bv); + if (dit.inMathed()) { + // not much to be done + } else { + otherstack.top().pars.clear(); + 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.from); + ParagraphList::iterator last = plist.begin(); + advance(last, plist.size() - undo.end); + otherstack.top().pars.insert(otherstack.top().pars.begin(), first, last); + } } - otherstack.top().cursor_pos = bv.cursor().pos(); - otherstack.top().cursor_par = bv.cursor().par(); - lyxerr << " undo other: " << otherstack.top() << std::endl; + otherstack.top().cursor = bv.cursor(); + //lyxerr << " undo other: " << otherstack.top() << std::endl; } - freezeUndo(); - bool const ret = performUndoOrRedo(bv, undo); - unFreezeUndo(); - return ret; -} - -} // namespace anon - - -void freezeUndo() -{ - // this is dangerous and for internal use only undo_frozen = true; -} - - -void unFreezeUndo() -{ - // this is dangerous and for internal use only + performUndoOrRedo(bv, undo); undo_frozen = false; + return true; } +} // namespace anon + void finishUndo() { @@ -292,6 +213,9 @@ void recordUndo(Undo::undo_kind kind, 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; } diff --git a/src/undo.h b/src/undo.h index 17fc89dc62..6c3dcdd59a 100644 --- a/src/undo.h +++ b/src/undo.h @@ -16,7 +16,9 @@ #ifndef UNDO_H #define UNDO_H +#include "dociterator.h" #include "ParagraphList_fwd.h" + #include "support/types.h" #include @@ -49,24 +51,16 @@ struct Undo { /// which kind of operation are we recording for? undo_kind kind; - /// hosting LyXText counted from buffer begin - int text; - /// cell in a tabular or similar - int index; - /// offset to the first paragraph in the paragraph list - int first_par; - /// offset to the last paragraph from the end of paragraph list - int end_par; - /// offset to the first paragraph in the paragraph list - int cursor_par; - /// the position of the cursor in the hosting paragraph - int cursor_pos; + /// the position of the cursor + StableDocumentIterator cursor; + /// counted from begin of buffer + lyx::paroffset_type from; + /// complement to end of this cell + lyx::paroffset_type end; /// the contents of the saved paragraphs (for texted) ParagraphList pars; /// the contents of the saved matharray (for mathed) std::string array; - /// in mathed? - bool math; }; @@ -79,12 +73,6 @@ bool textRedo(BufferView &); /// makes sure the next operation will be stored void finishUndo(); -/// whilst undo is frozen, no actions gets added to the undo stack -void freezeUndo(); - -/// track undos again -void unFreezeUndo(); - /** * Record undo information - call with the current cursor and the 'other -- 2.39.2