Undo cleaned up. It seems to work pretty well now.

* undo_funcs.h: Removed setCursorParUndo to simplify things a bit.
	Renamed setUndo family to recordUndo. Renamed FINISH to ATOMIC
	which I think is a bit clearer. EDIT is gone, since it was
	premature optimisation, and broken for mathed anyway.
	* undo_funcs.C (performUndoOrRedo): Cleaned up and made it work
	with cursor positioning in insets as well (math insets still do not
	work, but that's a different story anyway.) It mysteriously
	crashes sometimes with undo in the first paragraph, but I'm fairly
	confident that this is a compiler bug.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@7358 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Asger Ottar Alstrup 2003-07-25 19:18:43 +00:00
parent 3501eef8f8
commit c3a34a64f1
22 changed files with 241 additions and 317 deletions

View File

@ -594,16 +594,6 @@ int BufferView::unlockInset(UpdatableInset * inset)
}
void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
{
if (!theLockingInset())
return; // shouldn't happen
if (kind == Undo::EDIT) // in this case insets would not be stored!
kind = Undo::FINISH;
setUndo(this, kind, text->cursor.par());
}
void BufferView::updateInset(Inset * inset)
{
pimpl_->updateInset(inset);

View File

@ -11,7 +11,6 @@
#define BUFFER_VIEW_H
#include "LString.h"
#include "undo.h"
#include "insets/inset.h"
@ -176,8 +175,6 @@ public:
/// FIXME
bool fitLockedInsetCursor(int x, int y, int asc, int desc);
/// FIXME
void lockedInsetStoreUndo(Undo::undo_kind kind);
/// FIXME
void toggleSelection(bool = true);
/// FIXME: my word !
void toggleToggle();

View File

@ -1377,7 +1377,7 @@ bool BufferView::Pimpl::insertInset(Inset * inset, string const & lout)
}
// not quite sure if we want this...
setCursorParUndo(bv_);
recordUndo(bv_, Undo::ATOMIC);
freezeUndo();
beforeChange(bv_->text);

View File

@ -1,3 +1,15 @@
2003-07-25 Asger Alstrup <alstrup@diku.dk>
* undo_funcs.h: Removed setCursorParUndo to simplify things a bit.
Renamed setUndo family to recordUndo. Renamed FINISH to ATOMIC
which I think is a bit clearer. EDIT is gone, since it was
premature optimisation, and broken for mathed anyway.
* undo_funcs.C (performUndoOrRedo): Cleaned up and made it work
with cursor positioning in insets as well (math insets still do not
work, but that's a different story anyway.) It mysteriously
crashes sometimes with undo in the first paragraph, but I'm fairly
confident that this is a compiler bug.
2003-07-25 Lars Gullik Bjønnes <larsbj@gullik.net>
* paragraph.C (Paragraph): adjust for new clone return type

View File

@ -30,6 +30,8 @@
#include "support/lstrings.h"
#include "debug.h"
// Initialization of the counter for the inset id's,
unsigned int Inset::inset_id = 0;
@ -43,10 +45,10 @@ Inset::Inset()
Inset::Inset(Inset const & in)
: InsetBase(),
top_x(0), top_baseline(0), scx(0), owner_(0),
top_x(0), top_baseline(0), scx(0), id_(in.id_), owner_(0),
name_(in.name_), background_color_(in.background_color_)
{
id_ = inset_id++;
lyxerr << "inset id: " << id_ << std::endl;
}

View File

@ -328,7 +328,7 @@ protected:
mutable int top_baseline;
///
mutable int scx;
///
/// Used to identify the inset for cursor positioning when undoing
unsigned int id_;
///
static unsigned int inset_id;

View File

@ -1011,7 +1011,7 @@ Inset::RESULT InsetTabular::localDispatch(FuncRequest const & cmd)
break;
// no break here!
case LFUN_DELETE:
setUndo(bv, Undo::DELETE);
recordUndo(bv, Undo::DELETE);
cutSelection(bv->buffer()->params);
updateLocal(bv, INIT);
break;
@ -1094,7 +1094,7 @@ Inset::RESULT InsetTabular::localDispatch(FuncRequest const & cmd)
}
case LFUN_PASTE:
if (hasPasteBuffer()) {
setUndo(bv, Undo::INSERT);
recordUndo(bv, Undo::INSERT);
pasteSelection(bv);
updateLocal(bv, INIT);
break;
@ -1587,7 +1587,7 @@ void InsetTabular::setFont(BufferView * bv, LyXFont const & font, bool tall,
setSelection(0, tabular.getNumberOfCells() - 1);
}
if (hasSelection()) {
setUndo(bv, Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
bool const frozen = undo_frozen;
if (!frozen)
freezeUndo();
@ -1708,7 +1708,7 @@ void InsetTabular::tabularFeatures(BufferView * bv,
sel_col_start = sel_col_end = tabular.column_of_cell(actcell);
sel_row_start = sel_row_end = tabular.row_of_cell(actcell);
}
setUndo(bv, Undo::FINISH);
recordUndo(bv, Undo::ATOMIC);
int row = tabular.row_of_cell(actcell);
int column = tabular.column_of_cell(actcell);

View File

@ -277,8 +277,8 @@ void InsetText::read(Buffer const * buf, LyXLex & lex)
void InsetText::metrics(MetricsInfo & mi, Dimension & dim) const
{
//lyxerr << "InsetText::metrics: width: " << mi.base.textwidth << "\n";
if (mi.base.textwidth)
textwidth_ = mi.base.textwidth;
textwidth_ = mi.base.textwidth;
BufferView * bv = mi.base.bv;
setViewCache(bv);
text_.metrics(mi, dim);
@ -967,7 +967,7 @@ Inset::RESULT InsetText::localDispatch(FuncRequest const & cmd)
* true (on). */
#if 0
// This should not be needed here and is also WRONG!
setUndo(bv, Undo::INSERT, text_.cursor.par());
recordUndo(bv, Undo::INSERT, text_.cursor.par());
#endif
bv->switchKeyMap();
if (lyxrc.auto_region_delete) {
@ -1681,7 +1681,7 @@ void InsetText::setFont(BufferView * bv, LyXFont const & font, bool toggleall,
if (text_.selection.set())
setUndo(bv, Undo::EDIT, text_.cursor.par());
recordUndo(bv, Undo::ATOMIC, text_.cursor.par());
if (selectall) {
text_.cursorTop();

View File

@ -32,7 +32,7 @@ public:
Paragraph & operator*() const;
///
ParagraphList::iterator operator->() const;
///
/// This gives us the top-most parent paragraph
ParagraphList::iterator outerPar() const;
///
ParagraphList::iterator pit() const;

View File

@ -124,7 +124,8 @@ void InsetFormulaBase::handleFont
{
// this whole function is a hack and won't work for incremental font
// changes...
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
if (mathcursor->inset()->name() == font)
mathcursor->handleFont(font);
else {
@ -395,7 +396,7 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
case LFUN_TABULAR_FEATURE:
case LFUN_PASTESELECTION:
case LFUN_MATH_LIMITS:
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->dispatch(cmd);
break;
@ -479,7 +480,7 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
case LFUN_DELETE_WORD_BACKWARD:
case LFUN_BACKSPACE:
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
if (!mathcursor->backspace()) {
result = FINISHED;
remove_inset = true;
@ -488,7 +489,7 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
case LFUN_DELETE_WORD_FORWARD:
case LFUN_DELETE:
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
if (!mathcursor->erase()) {
result = FINISHED;
remove_inset = true;
@ -515,13 +516,13 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
is >> n;
if (was_macro)
mathcursor->macroModeClose();
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->selPaste(n);
break;
}
case LFUN_CUT:
bv->lockedInsetStoreUndo(Undo::DELETE);
recordUndo(bv, Undo::DELETE);
mathcursor->selCut();
break;
@ -536,7 +537,7 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
if (cmd.argument.empty()) {
// do superscript if LyX handles
// deadkeys
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->script(true);
}
break;
@ -580,14 +581,14 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
case LFUN_MATH_SIZE:
#if 0
if (!arg.empty()) {
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->setSize(arg);
}
#endif
break;
case LFUN_INSERT_MATRIX: {
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
unsigned int m = 1;
unsigned int n = 1;
string v_align;
@ -605,7 +606,7 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
case LFUN_SUPERSCRIPT:
case LFUN_SUBSCRIPT:
{
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->script(cmd.action == LFUN_SUPERSCRIPT);
break;
}
@ -621,14 +622,14 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
if (rs.empty())
rs = ')';
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->handleNest(MathAtom(new MathDelimInset(ls, rs)));
break;
}
case LFUN_SPACE_INSERT:
case LFUN_MATH_SPACE:
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->insert(MathAtom(new MathSpaceInset(",")));
break;
@ -643,7 +644,7 @@ dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
case LFUN_INSET_ERT:
// interpret this as if a backslash was typed
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->interpret('\\');
break;
@ -657,14 +658,14 @@ dispatch_result InsetFormulaBase::localDispatch(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:
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
mathcursor->niceInsert(argument);
break;
case -1:
case LFUN_SELFINSERT:
if (!argument.empty()) {
bv->lockedInsetStoreUndo(Undo::EDIT);
recordUndo(bv, Undo::ATOMIC);
if (argument.size() == 1)
result = mathcursor->interpret(argument[0]) ? DISPATCHED : FINISHED_RIGHT;
else

View File

@ -1053,12 +1053,12 @@ dispatch_result MathGridInset::dispatch
return DISPATCHED_POP;
case LFUN_CELL_SPLIT:
//bv->lockedInsetStoreUndo(Undo::EDIT);
//recordUndo(bv, Undo::ATOMIC);
splitCell(idx, pos);
return DISPATCHED_POP;
case LFUN_BREAKLINE: {
//bv->lockedInsetStoreUndo(Undo::INSERT);
//recordUndo(bv, Undo::INSERT);
row_type const r = row(idx);
addRow(r);

View File

@ -763,7 +763,7 @@ dispatch_result MathHullInset::dispatch
case LFUN_MATH_NUMBER:
//lyxerr << "toggling all numbers\n";
if (display()) {
//bv->lockedInsetStoreUndo(Undo::INSERT);
//recordUndo(bv, Undo::INSERT);
bool old = numberedType();
if (type_ == "multline")
numbered(nrows() - 1, !old);
@ -777,7 +777,7 @@ dispatch_result MathHullInset::dispatch
case LFUN_MATH_NONUMBER:
if (display()) {
row_type r = (type_ == "multline") ? nrows() - 1 : row(idx);
//bv->lockedInsetStoreUndo(Undo::INSERT);
//recordUndo(bv, Undo::INSERT);
bool old = numbered(r);
//bv->owner()->message(old ? _("No number") : _("Number"));
numbered(r, !old);

View File

@ -104,7 +104,7 @@ void MathTextInset::metrics(MetricsInfo & mi, Dimension & dim) const
// This is a regular char. Go on if we either don't care for
// the width limit or have not reached that limit.
curr += cell(0)[i].width_;
if (!mi.base.restrictwidth || curr + safe <= mi.base.textwidth)
if (curr + safe <= mi.base.textwidth)
continue;
}

View File

@ -11,14 +11,14 @@
MetricsBase::MetricsBase()
: bv(0), font(), style(LM_ST_TEXT), fontname("mathnormal"),
restrictwidth(false), textwidth(0)
textwidth(0)
{}
MetricsBase::MetricsBase(BufferView * b, LyXFont const & f, int w)
: bv(b), font(f), style(LM_ST_TEXT), fontname("mathnormal"),
restrictwidth(false), textwidth(w)
textwidth(w)
{}
@ -149,7 +149,6 @@ WidthChanger::WidthChanger(MetricsBase & mb, int w)
: Changer<MetricsBase>(mb)
{
save_ = mb;
mb.restrictwidth = true;
mb.textwidth = w;
}

View File

@ -36,11 +36,9 @@ struct MetricsBase {
LyXFont font;
/// current math style (display/text/script/..)
Styles style;
/// name of current font
/// name of current font - mathed specific
string fontname;
/// if this is set...
bool restrictwidth;
/// ... this is valid
/// This is the width available in pixels
int textwidth;
};

View File

@ -1480,7 +1480,7 @@ void LyXText::breakParagraph(ParagraphList & paragraphs, char keep_layout)
&& layout->labeltype != LABEL_SENSITIVE)
return;
setUndo(bv(), Undo::FINISH, cursor.par());
recordUndo(bv(), Undo::ATOMIC, cursor.par());
// Always break behind a space
//
@ -1572,7 +1572,7 @@ void LyXText::redoParagraph()
// same Paragraph one to the right and make a rebreak
void LyXText::insertChar(char c)
{
setUndo(bv(), Undo::INSERT, cursor.par());
recordUndo(bv(), Undo::INSERT, cursor.par());
// When the free-spacing option is set for the current layout,
// disable the double-space checking
@ -2008,7 +2008,7 @@ void LyXText::acceptChange()
if (selection.start.par() == selection.end.par()) {
LyXCursor & startc = selection.start;
LyXCursor & endc = selection.end;
setUndo(bv(), Undo::INSERT, startc.par());
recordUndo(bv(), Undo::INSERT, startc.par());
startc.par()->acceptChange(startc.pos(), endc.pos());
finishUndo();
clearSelection();
@ -2027,7 +2027,7 @@ void LyXText::rejectChange()
if (selection.start.par() == selection.end.par()) {
LyXCursor & startc = selection.start;
LyXCursor & endc = selection.end;
setUndo(bv(), Undo::INSERT, startc.par());
recordUndo(bv(), Undo::INSERT, startc.par());
startc.par()->rejectChange(startc.pos(), endc.pos());
finishUndo();
clearSelection();
@ -2240,7 +2240,7 @@ void LyXText::changeCase(LyXText::TextCase action)
setCursor(to.par(), to.pos() + 1);
}
setUndo(bv(), Undo::FINISH, from.par(), to.par());
recordUndo(bv(), Undo::ATOMIC, from.par(), to.par());
pos_type pos = from.pos();
ParagraphList::iterator pit = from.par();
@ -2310,7 +2310,7 @@ void LyXText::Delete()
LyXCursor tmpcursor = cursor;
// to make sure undo gets the right cursor position
cursor = old_cursor;
setUndo(bv(), Undo::DELETE, cursor.par());
recordUndo(bv(), Undo::DELETE, cursor.par());
cursor = tmpcursor;
backspace();
}
@ -2366,7 +2366,7 @@ void LyXText::backspace()
}
if (cursor.par() != ownerParagraphs().begin()) {
setUndo(bv(), Undo::DELETE,
recordUndo(bv(), Undo::DELETE,
boost::prior(cursor.par()),
cursor.par());
}
@ -2434,7 +2434,7 @@ void LyXText::backspace()
} else {
// this is the code for a normal backspace, not pasting
// any paragraphs
setUndo(bv(), Undo::DELETE, cursor.par());
recordUndo(bv(), Undo::DELETE, cursor.par());
// We used to do cursorLeftIntern() here, but it is
// not a good idea since it triggers the auto-delete
// mechanism. So we do a cursorLeftIntern()-lite,

View File

@ -332,7 +332,7 @@ void LyXText::toggleInset()
// do we want to keep this?? (JMarc)
if (!isHighlyEditableInset(inset))
setCursorParUndo(bv());
recordUndo(bv(), Undo::ATOMIC);
if (inset->isOpen()) {
inset->close(bv());
@ -385,7 +385,7 @@ LyXText::setLayout(LyXCursor & cur, LyXCursor & sstart_cur,
++endpit;
}
setUndo(bv(), Undo::EDIT, sstart_cur.par(), boost::prior(undoendpit));
recordUndo(bv(), Undo::ATOMIC, sstart_cur.par(), boost::prior(undoendpit));
// ok we have a selection. This is always between sstart_cur
// and sel_end cursor
@ -478,7 +478,7 @@ bool LyXText::changeDepth(bv_funcs::DEPTH_CHANGE type, bool test_only)
ParagraphList::iterator pastend = boost::next(end);
if (!test_only)
setUndo(bv(), Undo::EDIT, start, end);
recordUndo(bv(), Undo::ATOMIC, start, end);
bool changed = false;
@ -579,7 +579,7 @@ void LyXText::setFont(LyXFont const & font, bool toggleall)
// ok we have a selection. This is always between sel_start_cursor
// and sel_end cursor
setUndo(bv(), Undo::EDIT, selection.start.par(), selection.end.par());
recordUndo(bv(), Undo::ATOMIC, selection.start.par(), selection.end.par());
freezeUndo();
cursor = selection.start;
while (cursor.par() != selection.end.par() ||
@ -929,7 +929,7 @@ void LyXText::setParagraph(bool line_top, bool line_bottom,
++endpit;
}
setUndo(bv(), Undo::EDIT, selection.start.par(),
recordUndo(bv(), Undo::ATOMIC, selection.start.par(),
boost::prior(undoendpit));
@ -1217,7 +1217,7 @@ void LyXText::insertInset(Inset * inset)
{
if (!cursor.par()->insetAllowed(inset->lyxCode()))
return;
setUndo(bv(), Undo::FINISH, cursor.par());
recordUndo(bv(), Undo::ATOMIC, cursor.par());
freezeUndo();
cursor.par()->insertInset(cursor.pos(), inset);
// Just to rebreak and refresh correctly.
@ -1269,7 +1269,7 @@ void LyXText::cutSelection(bool doclear, bool realcut)
++endpit;
}
setUndo(bv(), Undo::DELETE, selection.start.par(),
recordUndo(bv(), Undo::DELETE, selection.start.par(),
boost::prior(undoendpit));
@ -1344,7 +1344,7 @@ void LyXText::pasteSelection(size_t sel_index)
if (!CutAndPaste::checkPastePossible())
return;
setUndo(bv(), Undo::INSERT, cursor.par());
recordUndo(bv(), Undo::INSERT, cursor.par());
ParagraphList::iterator endpit;
PitPosPair ppp;
@ -1387,7 +1387,7 @@ void LyXText::setSelectionRange(lyx::pos_type length)
// simple replacing. The font of the first selected character is used
void LyXText::replaceSelectionWithString(string const & str)
{
setCursorParUndo(bv());
recordUndo(bv(), Undo::ATOMIC);
freezeUndo();
if (!selection.set()) { // create a dummy selection
@ -1423,7 +1423,7 @@ void LyXText::insertStringAsLines(string const & str)
pos_type pos = cursor.pos();
ParagraphList::iterator endpit = boost::next(cursor.par());
setCursorParUndo(bv());
recordUndo(bv(), Undo::ATOMIC);
// only to be sure, should not be neccessary
clearSelection();
@ -2196,7 +2196,7 @@ bool LyXText::deleteEmptyParagraphMechanism(LyXCursor const & old_cursor)
++endpit;
}
setUndo(bv(), Undo::DELETE, old_cursor.par(),
recordUndo(bv(), Undo::DELETE, old_cursor.par(),
boost::prior(endpit));
cursor = tmpcursor;
@ -2228,7 +2228,7 @@ bool LyXText::deleteEmptyParagraphMechanism(LyXCursor const & old_cursor)
++endpit;
}
setUndo(bv(), Undo::DELETE, old_cursor.par(), boost::prior(endpit));
recordUndo(bv(), Undo::DELETE, old_cursor.par(), boost::prior(endpit));
cursor = tmpcursor;
// delete old row

View File

@ -425,7 +425,7 @@ Inset::RESULT LyXText::dispatch(FuncRequest const & cmd)
for (; tmp != end; ++tmp) {
if (tmp->params().startOfAppendix()) {
setUndo(bv, Undo::EDIT, tmp);
recordUndo(bv, Undo::ATOMIC, tmp);
tmp->params().startOfAppendix(false);
int tmpy;
setHeightOfRow(getRow(tmp, 0, tmpy));
@ -433,7 +433,7 @@ Inset::RESULT LyXText::dispatch(FuncRequest const & cmd)
}
}
setUndo(bv, Undo::EDIT, pit);
recordUndo(bv, Undo::ATOMIC, pit);
pit->params().startOfAppendix(start);
// we can set the refreshing parameters now
@ -1021,7 +1021,7 @@ Inset::RESULT LyXText::dispatch(FuncRequest const & cmd)
case LFUN_TRANSPOSE_CHARS:
update();
setUndo(bv, Undo::FINISH, cursor.par());
recordUndo(bv, Undo::ATOMIC, cursor.par());
if (transposeChars(cursor))
checkParagraph(cursor.par(), cursor.pos());
if (inset_owner)
@ -1522,7 +1522,7 @@ Inset::RESULT LyXText::dispatch(FuncRequest const & cmd)
// ...or maybe the SetCursorParUndo()
// below isn't necessary at all anylonger?
if (inset_hit->lyxCode() == Inset::REF_CODE)
setCursorParUndo(bv);
recordUndo(bv, Undo::ATOMIC);
bv->owner()->message(inset_hit->editMessage());

View File

@ -12,14 +12,13 @@
#include "undo.h"
Undo::Undo(undo_kind kind_arg, int inset, int plist,
Undo::Undo(undo_kind kind_arg, int inset,
int first, int last,
int cursor, int cursor_pos_arg,
ParagraphList const & par)
:
kind(kind_arg),
inset_id(inset),
plist_id(plist),
first_par_offset(first),
last_par_offset(last),
cursor_par_offset(cursor),

View File

@ -14,43 +14,67 @@
#include "ParagraphList.h"
///
/**
* These are the elements put on the undo stack. Each object
* contains complete paragraphs and sufficient information
* to restore the state. The work is done in undo_funcs.C
*/
class Undo {
public:
/// The undo kinds
/**
* The undo kinds are used to combine consecutive undo recordings
* of the same kind.
*/
enum undo_kind {
///
/**
* Insert something - these will combine to one big chunk
* when many inserts come after each other.
*/
INSERT,
///
/**
* Delete something - these will combine to one big chunk
* when many deletes come after each other.
*/
DELETE,
///
EDIT,
///
FINISH
/// Atomic - each of these will have its own entry in the stack
ATOMIC
};
///
undo_kind kind;
///
int inset_id; // valid if >= 0, if < 0 then not in inset
///
int plist_id;
///
int first_par_offset;
///
int last_par_offset;
///
int cursor_par_offset;
///
int cursor_pos; // valid if >= 0
///
ParagraphList pars;
///
Undo(undo_kind kind, int inset_id, int plist_id,
Undo(undo_kind kind, int inset_id,
int first, int last,
int cursor, int cursor_pos,
ParagraphList const & par_arg);
/// Which kind of operation are we recording for?
undo_kind kind;
/**
* ID of hosting inset if the cursor is in one.
* if -1, then the cursor is not in an inset.
* if >= 0, then the cursor is in inset with given id.
*/
int inset_id;
/// Offset to the first paragraph in the main document paragraph list
int first_par_offset;
/// Offset to the last paragraph from the end of the main par. list
int last_par_offset;
/**
* Offset from the start of the main document paragraph list,
* except if inside an inset, in which case it's the offset
* inside the hosting inset.
*/
int cursor_par_offset;
/// The position of the cursor in the hosting paragraph
int cursor_pos;
/// The contents of the paragraphs saved
ParagraphList pars;
};

View File

@ -23,222 +23,67 @@
/// The flag used by FinishUndo().
bool undo_finished;
/// Whether actions are not added to the undo stacks.
bool undo_frozen;
namespace {
/**
* Finish the undo operation in the case there was no entry
* on the stack to perform.
*/
void finishNoUndo(BufferView * bv)
{
freezeUndo();
bv->unlockInset(bv->theLockingInset());
finishUndo();
bv->text->postPaint();
unFreezeUndo();
}
// Returns false if no undo possible.
bool textHandleUndo(BufferView * bv, Undo & undo)
{
Buffer * buf = bv->buffer();
ParagraphList * plist = &buf->paragraphs;
/*
ParIterator null = buf->par_iterator_end();
for (ParIterator it = buf->par_iterator_begin(); it != null; ++it)
if (it.plist().id() == undo.plist_id) {
plist = &it.plist();
break;
}
*/
// Set the right(new) inset-owner of the paragraph if there is any.
UpdatableInset * inset =
static_cast<UpdatableInset *>(buf->getInsetFromID(undo.inset_id));
ParagraphList::iterator pit = undo.pars.begin();
ParagraphList::iterator end = undo.pars.end();
for ( ; pit != end; ++pit)
pit->setInsetOwner(inset);
//lyxerr << "\nhandle: inset_id: " << undo.inset_id << "\n";
//lyxerr << "handle: inset: " << inset << "\n";
//lyxerr << "handle: plist_id: " << undo.plist_id << "\n";
lyxerr << "handle: undo.pars.size(): " << undo.pars.size() << "\n";
lyxerr << "handle: first_offset: " << undo.first_par_offset << "\n";
lyxerr << "handle: last_offset: " << undo.last_par_offset << "\n";
// remove stuff between first and behind
{
ParagraphList::iterator first = plist->begin();
advance(first, undo.first_par_offset);
ParagraphList::iterator last = plist->begin();
advance(last, plist->size() - undo.last_par_offset);
lyxerr << "handle: first_id: " << first->id() << "\n";
lyxerr << "handle: last_id: " << last->id() << "\n";
lyxerr << "handle: remove: " << distance(first, last) + 1 << " pars\n";
plist->erase(first, ++last);
lyxerr << "handle: after remove\n";
}
// re-insert old stuff
{
ParagraphList::iterator first = plist->begin();
advance(first, undo.first_par_offset);
lyxerr << "handle: plist->size: " << plist->size() << "\n";
lyxerr << "handle: offset: " << undo.first_par_offset << "\n";
plist->insert(first, undo.pars.begin(), undo.pars.end());
lyxerr << "handle: after insert\n";
}
/*
// A memory optimization for edit:
// Only layout information
// is stored in the undo. So restore
// the text informations.
if (undo.kind == Undo::EDIT) {
undo.pars[par]->setContentsFromPar(*deletelist.back());
++par;
}
*/
// redo Paragraphs (should be handled outside undo...)
{
//LyXText * text = inset ? inset->getLyXText(bv) : bv->text;
LyXText * text = bv->text;
lyxerr << "handle: text: " << text << "\n";
// The cursor should be sane, so we will put it to the top
text->setCursorIntern(plist->begin(), 0);
lyxerr << "handle: 3\n";
// Rebreak the entire document
text->fullRebreak();
lyxerr << "handle: after redo\n";
if (inset) {
FuncRequest cmd(bv, LFUN_INSET_EDIT, "left");
inset->localDispatch(cmd);
}
}
if (inset) {
lyxerr << "fit cursor...\n";
bv->fitCursor();
bv->updateInset(inset);
}
// set cursor
{
LyXText * text = inset ? inset->getLyXText(bv) : bv->text;
ParagraphList::iterator cursor = text->ownerParagraphs().begin();
advance(cursor, undo.cursor_par_offset);
text->setCursorIntern(cursor, undo.cursor_pos);
// Clear any selection and set the selection
// cursor for an evt. new selection.
text->clearSelection();
text->selection.cursor = text->cursor;
text->updateCounters();
lyxerr << "after setCursor\n";
}
finishUndo();
bv->text->postPaint();
lyxerr << "finished textHandleUndo...\n";
return true;
}
void createUndo(BufferView * bv, Undo::undo_kind kind,
void recordUndo(BufferView * bv, Undo::undo_kind kind,
ParagraphList::iterator first, ParagraphList::iterator last,
limited_stack<Undo> & stack)
{
Buffer * buf = bv->buffer();
ParagraphList * plist = 0;
ParIterator null = buf->par_iterator_end();
lyxerr << "\n";
// First, record inset id, if cursor is in one
UpdatableInset * inset = first->inInset();
LyXText * text = inset ? inset->getLyXText(bv) : bv->text;
int const inset_id = inset ? inset->id() : -1;
#if 0
// this is what we'd like to have in the end for small grained undo
for (ParIterator it = buf->par_iterator_begin(); it != null; ++it) {
if (it->id() == first->id()) {
plist = &it.plist();
break;
}
}
// We simply record the entire outer paragraphs
ParagraphList * plist = &buf->paragraphs;
ParIterator null = buf->par_iterator_end();
#else
// and that's the big stick we wield now
lyxerr << "create: first_id orig: " << first->id() << "\n";
lyxerr << "create: last_id orig: " << last->id() << "\n";
plist = &buf->paragraphs;
// this is what we'd like to have in the end for small grained undo
// First, identify the outer paragraphs
for (ParIterator it = buf->par_iterator_begin(); it != null; ++it) {
// This does not work if we are nested twice or more
if (it->id() == first->id())
first = it.outerPar();
if (it->id() == last->id())
last = it.outerPar();
}
#endif
// And calculate a stable reference to them
int const first_offset = std::distance(plist->begin(), first);
int const last_offset = std::distance(last, plist->end());
int const last_offset = std::distance(last, plist->end());
if (last == plist->end()) {
lyxerr << "*** createUndo: last == end should not happen\n";
}
// Undo::ATOMIC are always recorded (no overlapping there).
// Undo::EDIT and Undo::FINISH are always finished.
// (no overlapping there)
// overlapping only with insert and delete inside one paragraph:
// Overlapping only with insert and delete inside one paragraph:
// Nobody wants all removed character appear one by one when undoing.
// EDIT is special since only layout information, not the
// contents of a paragaph are stored.
if (! undo_finished && kind != Undo::EDIT && kind != Undo::FINISH) {
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_offset == first_offset
&& buf->undostack.top().last_par_offset == last_offset) {
// No undo recording needed.
// No additonal undo recording needed -
// effectively, we combine undo recordings to one.
return;
}
}
// Record the cursor position in a stable way.
int const cursor_offset = std::distance
(text->ownerParagraphs().begin(), text->cursor.par());
//lyxerr << "create: plist_id: " << plist->id() << "\n";
//lyxerr << "create: inset_id: " << inset_id << "\n";
lyxerr << "create: first_id: " << first->id() << "\n";
lyxerr << "create: last_id: " << last->id() << "\n";
lyxerr << "create: first_offset: " << first_offset << "\n";
lyxerr << "create: last_offset: " << last_offset << "\n";
lyxerr << "create: cursor_offset: " << cursor_offset << "\n";
lyxerr << "create: cursor_pos: " << text->cursor.pos() << "\n";
stack.push(Undo(kind, inset_id, 0, //plist->id(),
// Make and push the Undo entry
stack.push(Undo(kind, inset_id,
first_offset, last_offset,
cursor_offset, text->cursor.pos(),
ParagraphList()));
// Record the relevant paragraphs
ParagraphList & undo_pars = stack.top().pars;
for (ParagraphList::iterator it = first; it != last; ++it) {
@ -248,24 +93,92 @@ void createUndo(BufferView * bv, Undo::undo_kind kind,
undo_pars.push_back(*last);
undo_pars.back().id(last->id());
// A memory optimization: Just store the layout
// information when only edit.
#warning Waste...
//if (kind == Undo::EDIT)
// for (size_t i = 0, n = undo_pars.size(); i < n; ++i)
// undo_pars[i]->clearContents();
// And make sure that next time, we should be combining if possible
undo_finished = false;
}
// Returns false if no undo possible.
bool performUndoOrRedo(BufferView * bv, Undo & undo)
{
Buffer * buf = bv->buffer();
ParagraphList * plist = &buf->paragraphs;
// Remove new stuff between first and last
{
ParagraphList::iterator first = plist->begin();
advance(first, undo.first_par_offset);
ParagraphList::iterator last = plist->begin();
advance(last, plist->size() - undo.last_par_offset);
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_offset);
plist->insert(first, undo.pars.begin(), undo.pars.end());
}
}
// Rebreak the entire document
bv->text->fullRebreak();
// set cursor
{
// Get a hold of the inset for the cursor, if relevant
UpdatableInset * inset =
static_cast<UpdatableInset *>(
buf->getInsetFromID(undo.inset_id));
LyXText * text = inset ? inset->getLyXText(bv) : bv->text;
ParagraphList::iterator cursor = text->ownerParagraphs().begin();
advance(cursor, undo.cursor_par_offset);
text->setCursorIntern(cursor, undo.cursor_pos);
if (inset) {
// Magic needed to update inset internal state
FuncRequest cmd(bv, LFUN_INSET_EDIT, "left");
inset->localDispatch(cmd);
}
// set cursor again to force the position to be the right one
text->setCursorIntern(cursor, undo.cursor_pos);
// Clear any selection and set the selection
// cursor for any new selection.
text->clearSelection();
text->selection.cursor = text->cursor;
text->updateCounters();
}
finishUndo();
// And repaint the lot
bv->text->postPaint();
return true;
}
// Returns false if no undo possible.
bool textUndoOrRedo(BufferView * bv,
limited_stack<Undo> & stack,
limited_stack<Undo> & otherstack)
{
if (stack.empty()) {
finishNoUndo(bv);
/*
* Finish the undo operation in the case there was no entry
* on the stack to perform.
*/
freezeUndo();
bv->unlockInset(bv->theLockingInset());
finishUndo();
bv->text->postPaint();
unFreezeUndo();
return false;
}
@ -278,9 +191,6 @@ bool textUndoOrRedo(BufferView * bv,
otherstack.top().pars.clear();
Buffer * buf = bv->buffer();
ParagraphList & plist = buf->paragraphs;
lyxerr << "\nredo: first: " << undo.first_par_offset << "\n";
lyxerr << "redo: last: " << undo.last_par_offset << "\n";
lyxerr << "redo: size: " << plist.size() << "\n";
if (undo.first_par_offset + undo.last_par_offset <= int(plist.size())) {
ParagraphList::iterator first = plist.begin();
advance(first, undo.first_par_offset);
@ -296,7 +206,7 @@ bool textUndoOrRedo(BufferView * bv,
// is requested.
freezeUndo();
bv->unlockInset(bv->theLockingInset());
bool const ret = textHandleUndo(bv, undo);
bool const ret = performUndoOrRedo(bv, undo);
unFreezeUndo();
return ret;
}
@ -304,13 +214,6 @@ bool textUndoOrRedo(BufferView * bv,
} // namespace anon
void finishUndo()
{
// Makes sure the next operation will be stored.
undo_finished = true;
}
void freezeUndo()
{
// This is dangerous and for internal use only.
@ -325,6 +228,13 @@ void unFreezeUndo()
}
void finishUndo()
{
// Makes sure the next operation will be stored.
undo_finished = true;
}
bool textUndo(BufferView * bv)
{
return textUndoOrRedo(bv, bv->buffer()->undostack,
@ -339,30 +249,25 @@ bool textRedo(BufferView * bv)
}
void setUndo(BufferView * bv, Undo::undo_kind kind,
void recordUndo(BufferView * bv, Undo::undo_kind kind,
ParagraphList::iterator first, ParagraphList::iterator last)
{
if (!undo_frozen) {
createUndo(bv, kind, first, last, bv->buffer()->undostack);
recordUndo(bv, kind, first, last, bv->buffer()->undostack);
bv->buffer()->redostack.clear();
}
}
void setUndo(BufferView * bv, Undo::undo_kind kind,
void recordUndo(BufferView * bv, Undo::undo_kind kind,
ParagraphList::iterator first)
{
setUndo(bv, kind, first, first);
recordUndo(bv, kind, first, first);
}
void setUndo(BufferView * bv, Undo::undo_kind kind)
void recordUndo(BufferView * bv, Undo::undo_kind kind)
{
setUndo(bv, kind, bv->text->cursor.par());
recordUndo(bv, kind, bv->text->cursor.par());
}
void setCursorParUndo(BufferView * bv)
{
setUndo(bv, Undo::FINISH);
}

View File

@ -17,13 +17,13 @@
class BufferView;
class Paragraph;
/// returns false if no undo possible
/// This will undo the last action - returns false if no undo possible
bool textUndo(BufferView *);
/// returns false if no redo possible
/// This will redo the last undo - returns false if no redo possible
bool textRedo(BufferView *);
/// makes sure the next operation will be stored
/// Makes sure the next operation will be stored
void finishUndo();
/**
@ -42,17 +42,14 @@ void unFreezeUndo();
* This is called before you make the changes to the paragraph, and it
* will record the original information of the paragraphs in the undo stack.
*/
void setUndo(BufferView *, Undo::undo_kind kind,
void recordUndo(BufferView *, Undo::undo_kind kind,
ParagraphList::iterator first, ParagraphList::iterator last);
/// Convienience: Prepare undo when change in a single paragraph.
void setUndo(BufferView *, Undo::undo_kind kind,
void recordUndo(BufferView *, Undo::undo_kind kind,
ParagraphList::iterator first);
/// Convienience: Prepare undo for the paragraph that contains the cursor
void setUndo(BufferView *, Undo::undo_kind kind);
/// Convienience: Prepare and finish undo for the paragraph that contains the cursor
void setCursorParUndo(BufferView *);
void recordUndo(BufferView *, Undo::undo_kind kind);
/// Are we avoiding tracking undos currently ?
extern bool undo_frozen;