redo undo

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8481 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
André Pönitz 2004-03-08 21:14:45 +00:00
parent b1fa5cd0d0
commit 4c8d536692
14 changed files with 225 additions and 304 deletions

View File

@ -607,6 +607,7 @@ void BufferView::Pimpl::update()
updateScrollbar();
}
screen().redraw(*bv_);
bv_->owner()->view_state_changed();
}

View File

@ -1,3 +1,9 @@
2004-03-08 André Pönitz <poenitz@gmx.net>
* undo.[Ch]: use 'StableDocumentIterator' as base for
the Undo struct.
2004-03-07 Jürgen Spitzmüller <j.spitzmueller@gmx.de>
* LaTeXFeatures.C:

View File

@ -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;

View File

@ -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.

View File

@ -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;
}

View File

@ -15,6 +15,7 @@
#include "cursor_slice.h"
#include <vector>
#include <iosfwd>
class BufferView;
class MathAtom;
@ -23,6 +24,7 @@ class Paragraph;
class Row;
// only needed for gcc 2.95, remove when support terminated
template <typename A, typename B>
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<CursorSlice> data_;
};
bool operator==(StableDocumentIterator const &, StableDocumentIterator const &);
#endif

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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 <algorithm>
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<Undo> & 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
BOOST_ASSERT(first_par <= cur.lastpar());
BOOST_ASSERT(last_par <= cur.lastpar());
if (first_par > last_par) {
paroffset_type t = first_par;
first_par = last_par;
last_par = t;
}
if (first_par > last_par)
std::swap(first_par, last_par);
Buffer & buf = *cur.bv().buffer();
int const end_par = cur.lastpar() + 1 - last_par;
// 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;
// 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;
}
}
// 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;
// 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
{
ParagraphList::iterator first = plist.begin();
advance(first, undo.first_par);
ParagraphList::iterator last = plist.begin();
advance(last, plist.size() - undo.end_par);
plist.erase(first, ++last);
}
// re-insert old stuff instead
if (plist.empty()) {
plist.assign(undo.pars.begin(), undo.pars.end());
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);
plist.erase(first, last);
// 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<Undo> & stack, limited_stack<Undo> & otherstack)
{
Buffer & buf = *bv.buffer();
if (stack.empty()) {
// nothing to do
finishUndo();
@ -223,46 +152,38 @@ 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;
undo_frozen = true;
performUndoOrRedo(bv, undo);
undo_frozen = false;
return true;
}
} // 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
undo_frozen = false;
}
void finishUndo()
{
// makes sure the next operation will be stored
@ -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;
}

View File

@ -16,7 +16,9 @@
#ifndef UNDO_H
#define UNDO_H
#include "dociterator.h"
#include "ParagraphList_fwd.h"
#include "support/types.h"
#include <string>
@ -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