mirror of
https://git.lyx.org/repos/lyx.git
synced 2025-01-21 23:09:40 +00:00
Undo /does/ seem to still work properly :)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4212 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
cc7901c5b8
commit
a0e30632d6
@ -1,3 +1,14 @@
|
||||
2002-05-26 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* Makefile.am:
|
||||
* buffer.h:
|
||||
* undostack.h:
|
||||
* undostack.C:
|
||||
* undo_funcs.h:
|
||||
* undo_funcs.C: some cleanups. Use shared_ptr
|
||||
and a template for the undo stacks.
|
||||
|
||||
|
||||
2002-05-26 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* BufferView_pimpl.h:
|
||||
|
@ -202,8 +202,6 @@ lyx_SOURCES = \
|
||||
undo.h \
|
||||
undo_funcs.C \
|
||||
undo_funcs.h \
|
||||
undostack.C \
|
||||
undostack.h \
|
||||
vc-backend.C \
|
||||
vc-backend.h \
|
||||
version.C \
|
||||
|
15
src/buffer.h
15
src/buffer.h
@ -19,12 +19,15 @@
|
||||
|
||||
#include "LString.h"
|
||||
#include "undo.h"
|
||||
#include "undostack.h"
|
||||
#include "support/limited_stack.h"
|
||||
|
||||
#include "lyxvc.h"
|
||||
#include "bufferparams.h"
|
||||
#include "texrow.h"
|
||||
#include "paragraph.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class BufferView;
|
||||
class LyXRC;
|
||||
class TeXErrors;
|
||||
@ -298,11 +301,11 @@ public:
|
||||
bool isMultiLingual();
|
||||
|
||||
/// Does this mean that this is buffer local?
|
||||
UndoStack undostack;
|
||||
|
||||
/// Does this mean that this is buffer local?
|
||||
UndoStack redostack;
|
||||
|
||||
limited_stack<boost::shared_ptr<Undo> > undostack;
|
||||
|
||||
/// Does this mean that this is buffer local?
|
||||
limited_stack<boost::shared_ptr<Undo> > redostack;
|
||||
|
||||
///
|
||||
BufferParams params;
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2002-05-26 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* limited_stack.h: new template for limited-size
|
||||
stacks
|
||||
|
||||
2002-05-25 Lars Gullik Bjønnes <larsbj@birdstep.com>
|
||||
|
||||
* filetools.C: do not include LSubstring.h
|
||||
|
77
src/support/limited_stack.h
Normal file
77
src/support/limited_stack.h
Normal file
@ -0,0 +1,77 @@
|
||||
// -*- C++ -*-
|
||||
/**
|
||||
* \file limited_stack.h
|
||||
* Copyright 2002 the LyX Team
|
||||
* Read the file COPYING
|
||||
*
|
||||
* \author John Levon <moz@compsoc.man.ac.uk>
|
||||
*/
|
||||
|
||||
#ifndef LIMITED_STACK_H
|
||||
#define LIMITED_STACK_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
/**
|
||||
* limited_stack - a stack of limited size
|
||||
*
|
||||
* Like a normal stack, but only accepts pointer types,
|
||||
* and bottom elements are deleted on overflow
|
||||
*/
|
||||
template <typename T>
|
||||
class limited_stack {
|
||||
public:
|
||||
typedef std::list<T> container_type;
|
||||
typedef typename container_type::value_type value_type;
|
||||
typedef typename container_type::size_type size_type;
|
||||
|
||||
/// limit is the maximum size of the stack
|
||||
limited_stack(size_type limit = 10) {
|
||||
limit_ = limit;
|
||||
}
|
||||
|
||||
/// return the top element
|
||||
value_type top() {
|
||||
return c_.front();
|
||||
}
|
||||
|
||||
/// pop and throw away the top element
|
||||
void pop() {
|
||||
c_.pop_front();
|
||||
}
|
||||
|
||||
/// return true if the stack is empty
|
||||
bool empty() const {
|
||||
return c_.size() == 0;
|
||||
}
|
||||
|
||||
/// clear all elements, deleting them
|
||||
void clear() {
|
||||
while (!c_.empty()) {
|
||||
c_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/// push an item on to the stack, deleting the
|
||||
/// bottom item on overflow.
|
||||
void push(value_type const & v) {
|
||||
c_.push_front(v);
|
||||
if (c_.size() > limit_) {
|
||||
c_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// internal contents
|
||||
container_type c_;
|
||||
/// the maximum number elements stored
|
||||
size_type limit_;
|
||||
};
|
||||
|
||||
// make pointer type an error.
|
||||
template <typename T>
|
||||
class limited_stack<T*>;
|
||||
|
||||
#endif // LIMITED_STACK_H
|
634
src/undo_funcs.C
634
src/undo_funcs.C
@ -23,328 +23,243 @@
|
||||
|
||||
#include "iterators.h"
|
||||
|
||||
#define DELETE_UNUSED_PARAGRAPHS 1
|
||||
#ifdef DELETE_UNUSED_PARAGRAPHS
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
using std::vector;
|
||||
using boost::shared_ptr;
|
||||
|
||||
|
||||
/// the flag used by FinishUndo();
|
||||
bool undo_finished;
|
||||
/// a flag
|
||||
/// FIXME
|
||||
bool undo_frozen;
|
||||
|
||||
namespace {
|
||||
|
||||
bool textUndo(BufferView * bv)
|
||||
/// utility to return the cursor
|
||||
LyXCursor const & undoCursor(BufferView * bv)
|
||||
{
|
||||
// returns false if no undo possible
|
||||
Undo * undo = bv->buffer()->undostack.top();
|
||||
bv->buffer()->undostack.pop();
|
||||
if (undo) {
|
||||
finishUndo();
|
||||
if (!undo_frozen) {
|
||||
Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
|
||||
if (first && first->next())
|
||||
first = first->next();
|
||||
else if (!first)
|
||||
first = firstUndoParagraph(bv, undo->number_of_inset_id);
|
||||
if (first) {
|
||||
bv->buffer()->redostack.push(
|
||||
createUndo(bv, undo->kind, first,
|
||||
bv->buffer()->getParFromID(undo->number_of_behind_par)));
|
||||
}
|
||||
}
|
||||
if (bv->theLockingInset())
|
||||
return bv->theLockingInset()->cursor(bv);
|
||||
return bv->text->cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a pointer to the very first Paragraph depending of where we are
|
||||
* so it will return the first paragraph of the buffer or the first paragraph
|
||||
* of the textinset we're in.
|
||||
*/
|
||||
Paragraph * firstUndoParagraph(BufferView * bv, int inset_id)
|
||||
{
|
||||
Inset * inset = bv->buffer()->getInsetFromID(inset_id);
|
||||
if (inset) {
|
||||
Paragraph * result = inset->getFirstParagraph(0);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
// now we can unlock the inset for saftey because the inset pointer could
|
||||
// be changed during the undo-function. Anyway if needed we have to lock
|
||||
// the right inset/position if this is requested.
|
||||
freezeUndo();
|
||||
bv->unlockInset(bv->theLockingInset());
|
||||
bool ret = textHandleUndo(bv, undo);
|
||||
unFreezeUndo();
|
||||
return ret;
|
||||
return bv->text->ownerParagraph();
|
||||
}
|
||||
|
||||
|
||||
bool textRedo(BufferView * bv)
|
||||
/**
|
||||
* Finish the undo operation in the case there was no entry
|
||||
* on the stack to perform.
|
||||
*/
|
||||
void finishNoUndo(BufferView * bv)
|
||||
{
|
||||
// returns false if no redo possible
|
||||
Undo * undo = bv->buffer()->redostack.top();
|
||||
bv->buffer()->redostack.pop();
|
||||
if (undo) {
|
||||
finishUndo();
|
||||
if (!undo_frozen) {
|
||||
Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
|
||||
if (first && first->next())
|
||||
first = first->next();
|
||||
else if (!first)
|
||||
first = firstUndoParagraph(bv, undo->number_of_inset_id);
|
||||
if (first) {
|
||||
bv->buffer()->undostack.push(
|
||||
createUndo(bv, undo->kind, first,
|
||||
bv->buffer()->getParFromID(undo->number_of_behind_par)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// now we can unlock the inset for saftey because the inset pointer could
|
||||
// be changed during the undo-function. Anyway if needed we have to lock
|
||||
// the right inset/position if this is requested.
|
||||
freezeUndo();
|
||||
bv->unlockInset(bv->theLockingInset());
|
||||
bool ret = textHandleUndo(bv, undo);
|
||||
finishUndo();
|
||||
bv->text->status(bv, LyXText::NEED_MORE_REFRESH);
|
||||
unFreezeUndo();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool textHandleUndo(BufferView * bv, Undo * undo)
|
||||
|
||||
|
||||
// returns false if no undo possible
|
||||
bool textHandleUndo(BufferView * bv, Undo & undo)
|
||||
{
|
||||
// returns false if no undo possible
|
||||
bool result = false;
|
||||
if (undo) {
|
||||
Paragraph * before =
|
||||
bv->buffer()->getParFromID(undo->number_of_before_par);
|
||||
Paragraph * behind =
|
||||
bv->buffer()->getParFromID(undo->number_of_behind_par);
|
||||
Paragraph * tmppar;
|
||||
Paragraph * tmppar2;
|
||||
Paragraph * tmppar5;
|
||||
Buffer * b = bv->buffer();
|
||||
|
||||
Paragraph * before =
|
||||
b->getParFromID(undo.number_of_before_par);
|
||||
Paragraph * behind =
|
||||
b->getParFromID(undo.number_of_behind_par);
|
||||
Paragraph * tmppar;
|
||||
Paragraph * tmppar2;
|
||||
|
||||
// if there's no before take the beginning
|
||||
// of the document for redoing
|
||||
if (!before) {
|
||||
LyXText * t = bv->text;
|
||||
int num = undo->number_of_inset_id;
|
||||
if (undo->number_of_inset_id >= 0) {
|
||||
Inset * in = bv->buffer()->getInsetFromID(num);
|
||||
if (in) {
|
||||
t = in->getLyXText(bv);
|
||||
} else {
|
||||
num = -1;
|
||||
}
|
||||
// if there's no before take the beginning
|
||||
// of the document for redoing
|
||||
if (!before) {
|
||||
LyXText * t = bv->text;
|
||||
int num = undo.number_of_inset_id;
|
||||
if (undo.number_of_inset_id >= 0) {
|
||||
Inset * in = bv->buffer()->getInsetFromID(num);
|
||||
if (in) {
|
||||
t = in->getLyXText(bv);
|
||||
} else {
|
||||
num = -1;
|
||||
}
|
||||
t->setCursorIntern(bv, firstUndoParagraph(bv, num), 0);
|
||||
}
|
||||
t->setCursorIntern(bv, firstUndoParagraph(bv, num), 0);
|
||||
}
|
||||
|
||||
// replace the paragraphs with the undo informations
|
||||
// replace the paragraphs with the undo informations
|
||||
|
||||
Paragraph * tmppar3 = undo->par;
|
||||
undo->par = 0; /* otherwise the undo destructor would
|
||||
delete the paragraph */
|
||||
Paragraph * tmppar3 = undo.par;
|
||||
undo.par = 0; /* otherwise the undo destructor would
|
||||
delete the paragraph */
|
||||
|
||||
// get last undo par and set the right(new) inset-owner of the
|
||||
// paragraph if there is any. This is not needed if we don't have
|
||||
// a paragraph before because then in is automatically done in the
|
||||
// function which assigns the first paragraph to an InsetText. (Jug)
|
||||
Paragraph * tmppar4 = tmppar3;
|
||||
if (tmppar4) {
|
||||
Inset * in = 0;
|
||||
if (before)
|
||||
in = before->inInset();
|
||||
else if (undo->number_of_inset_id >= 0)
|
||||
in = bv->buffer()->getInsetFromID(undo->number_of_inset_id);
|
||||
// get last undo par and set the right(new) inset-owner of the
|
||||
// paragraph if there is any. This is not needed if we don't have
|
||||
// a paragraph before because then in is automatically done in the
|
||||
// function which assigns the first paragraph to an InsetText. (Jug)
|
||||
Paragraph * tmppar4 = tmppar3;
|
||||
if (tmppar4) {
|
||||
Inset * in = 0;
|
||||
if (before)
|
||||
in = before->inInset();
|
||||
else if (undo.number_of_inset_id >= 0)
|
||||
in = bv->buffer()->getInsetFromID(undo.number_of_inset_id);
|
||||
tmppar4->setInsetOwner(in);
|
||||
while (tmppar4->next()) {
|
||||
tmppar4 = tmppar4->next();
|
||||
tmppar4->setInsetOwner(in);
|
||||
while (tmppar4->next()) {
|
||||
tmppar4 = tmppar4->next();
|
||||
tmppar4->setInsetOwner(in);
|
||||
}
|
||||
}
|
||||
|
||||
vector<Paragraph *> deletelist;
|
||||
|
||||
Paragraph * deletepar;
|
||||
|
||||
// now add old paragraphs to be deleted
|
||||
if (before != behind || (!behind && !before)) {
|
||||
if (before)
|
||||
deletepar = before->next();
|
||||
else
|
||||
deletepar = firstUndoParagraph(bv, undo.number_of_inset_id);
|
||||
tmppar2 = tmppar3;
|
||||
while (deletepar && deletepar != behind) {
|
||||
deletelist.push_back(deletepar);
|
||||
tmppar = deletepar;
|
||||
deletepar = deletepar->next();
|
||||
|
||||
// a memory optimization for edit:
|
||||
// Only layout information
|
||||
// is stored in the undo. So restore
|
||||
// the text informations.
|
||||
if (undo.kind == Undo::EDIT) {
|
||||
tmppar2->setContentsFromPar(tmppar);
|
||||
tmppar2 = tmppar2->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now remove the old text if there is any
|
||||
#ifdef DELETE_UNUSED_PARAGRAPHS
|
||||
vector<Paragraph *> vvpar;
|
||||
#endif
|
||||
if (before != behind || (!behind && !before)) {
|
||||
if (before)
|
||||
tmppar5 = before->next();
|
||||
else
|
||||
tmppar5 = firstUndoParagraph(bv, undo->number_of_inset_id);
|
||||
tmppar2 = tmppar3;
|
||||
while (tmppar5 && tmppar5 != behind) {
|
||||
#ifdef DELETE_UNUSED_PARAGRAPHS
|
||||
vvpar.push_back(tmppar5);
|
||||
#endif
|
||||
tmppar = tmppar5;
|
||||
tmppar5 = tmppar5->next();
|
||||
// a memory optimization for edit:
|
||||
// Only layout information
|
||||
// is stored in the undo. So restore
|
||||
// the text informations.
|
||||
if (undo->kind == Undo::EDIT) {
|
||||
tmppar2->setContentsFromPar(tmppar);
|
||||
#ifndef DELETE_UNUSED_PARAGRAPHS
|
||||
tmppar->clearContents();
|
||||
#endif
|
||||
tmppar2 = tmppar2->next();
|
||||
}
|
||||
}
|
||||
// put the new stuff in the list if there is one
|
||||
if (tmppar3) {
|
||||
if (before)
|
||||
before->next(tmppar3);
|
||||
else
|
||||
bv->text->ownerParagraph(firstUndoParagraph(bv, undo.number_of_inset_id)->id(),
|
||||
tmppar3);
|
||||
|
||||
tmppar3->previous(before);
|
||||
} else {
|
||||
// We enter here on DELETE undo operations where we have to
|
||||
// substitue the second paragraph with the first if the removed
|
||||
// one is the first!
|
||||
if (!before && behind) {
|
||||
bv->text->ownerParagraph(firstUndoParagraph(bv, undo.number_of_inset_id)->id(),
|
||||
behind);
|
||||
tmppar3 = behind;
|
||||
}
|
||||
|
||||
// put the new stuff in the list if there is one
|
||||
if (tmppar3) {
|
||||
if (before)
|
||||
before->next(tmppar3);
|
||||
else
|
||||
bv->text->ownerParagraph(firstUndoParagraph(bv, undo->number_of_inset_id)->id(),
|
||||
tmppar3);
|
||||
|
||||
tmppar3->previous(before);
|
||||
} else {
|
||||
// We enter here on DELETE undo operations where we have to
|
||||
// substitue the second paragraph with the first if the removed
|
||||
// one is the first!
|
||||
if (!before && behind) {
|
||||
bv->text->ownerParagraph(firstUndoParagraph(bv, undo->number_of_inset_id)->id(),
|
||||
behind);
|
||||
tmppar3 = behind;
|
||||
}
|
||||
}
|
||||
if (tmppar4) {
|
||||
tmppar4->next(behind);
|
||||
if (behind)
|
||||
behind->previous(tmppar4);
|
||||
}
|
||||
|
||||
|
||||
// Set the cursor for redoing
|
||||
if (before) {
|
||||
Inset * it = before->inInset();
|
||||
if (it)
|
||||
it->getLyXText(bv)->setCursorIntern(bv, before, 0);
|
||||
else
|
||||
bv->text->setCursorIntern(bv, before, 0);
|
||||
}
|
||||
|
||||
Paragraph * endpar = 0;
|
||||
// calculate the endpar for redoing the paragraphs.
|
||||
}
|
||||
if (tmppar4) {
|
||||
tmppar4->next(behind);
|
||||
if (behind)
|
||||
endpar = behind->next();
|
||||
behind->previous(tmppar4);
|
||||
}
|
||||
|
||||
tmppar = bv->buffer()->getParFromID(undo->number_of_cursor_par);
|
||||
UpdatableInset* it = 0;
|
||||
if (tmppar3)
|
||||
it = static_cast<UpdatableInset*>(tmppar3->inInset());
|
||||
if (it) {
|
||||
it->getLyXText(bv)->redoParagraphs(bv,
|
||||
it->getLyXText(bv)->cursor,
|
||||
endpar);
|
||||
if (tmppar) {
|
||||
it = static_cast<UpdatableInset*>(tmppar->inInset());
|
||||
LyXText * t;
|
||||
if (it) {
|
||||
it->edit(bv);
|
||||
t = it->getLyXText(bv);
|
||||
} else {
|
||||
t = bv->text;
|
||||
}
|
||||
t->setCursorIntern(bv, tmppar, undo->cursor_pos);
|
||||
// clear any selection and set the selection cursor
|
||||
// for an evt. new selection.
|
||||
t->clearSelection();
|
||||
t->selection.cursor = t->cursor;
|
||||
t->updateCounters(bv, t->cursor.row());
|
||||
bv->fitCursor();
|
||||
}
|
||||
bv->updateInset(it, false);
|
||||
bv->text->setCursorIntern(bv, bv->text->cursor.par(),
|
||||
bv->text->cursor.pos());
|
||||
} else {
|
||||
bv->text->redoParagraphs(bv, bv->text->cursor, endpar);
|
||||
if (tmppar) {
|
||||
LyXText * t;
|
||||
Inset * it = tmppar->inInset();
|
||||
if (it) {
|
||||
it->edit(bv);
|
||||
t = it->getLyXText(bv);
|
||||
} else {
|
||||
t = bv->text;
|
||||
}
|
||||
t->setCursorIntern(bv, tmppar, undo->cursor_pos);
|
||||
// clear any selection and set the selection cursor
|
||||
// for an evt. new selection.
|
||||
t->clearSelection();
|
||||
t->selection.cursor = t->cursor;
|
||||
t->updateCounters(bv, t->cursor.row());
|
||||
|
||||
// Set the cursor for redoing
|
||||
if (before) {
|
||||
Inset * it = before->inInset();
|
||||
if (it)
|
||||
it->getLyXText(bv)->setCursorIntern(bv, before, 0);
|
||||
else
|
||||
bv->text->setCursorIntern(bv, before, 0);
|
||||
}
|
||||
|
||||
Paragraph * endpar = 0;
|
||||
// calculate the endpar for redoing the paragraphs.
|
||||
if (behind)
|
||||
endpar = behind->next();
|
||||
|
||||
tmppar = bv->buffer()->getParFromID(undo.number_of_cursor_par);
|
||||
UpdatableInset* it = 0;
|
||||
if (tmppar3)
|
||||
it = static_cast<UpdatableInset*>(tmppar3->inInset());
|
||||
if (it) {
|
||||
it->getLyXText(bv)->redoParagraphs(bv,
|
||||
it->getLyXText(bv)->cursor,
|
||||
endpar);
|
||||
if (tmppar) {
|
||||
it = static_cast<UpdatableInset*>(tmppar->inInset());
|
||||
LyXText * t;
|
||||
if (it) {
|
||||
it->edit(bv);
|
||||
t = it->getLyXText(bv);
|
||||
} else {
|
||||
t = bv->text;
|
||||
}
|
||||
t->setCursorIntern(bv, tmppar, undo.cursor_pos);
|
||||
// clear any selection and set the selection cursor
|
||||
// for an evt. new selection.
|
||||
t->clearSelection();
|
||||
t->selection.cursor = t->cursor;
|
||||
t->updateCounters(bv, t->cursor.row());
|
||||
bv->fitCursor();
|
||||
}
|
||||
result = true;
|
||||
delete undo;
|
||||
#ifdef DELETE_UNUSED_PARAGRAPHS
|
||||
// And here it's save enough to delete all removed paragraphs
|
||||
vector<Paragraph *>::iterator pit = vvpar.begin();
|
||||
if (pit != vvpar.end()) {
|
||||
#if 0
|
||||
lyxerr << endl << "PARS BEFORE:";
|
||||
ParIterator end = bv->buffer()->par_iterator_end();
|
||||
ParIterator it = bv->buffer()->par_iterator_begin();
|
||||
for (; it != end; ++it)
|
||||
lyxerr << (*it)->previous() << "<- " << (*it) << " ->" << (*it)->next() << endl;
|
||||
lyxerr << "DEL: ";
|
||||
#endif
|
||||
for(;pit != vvpar.end(); ++pit) {
|
||||
// lyxerr << *pit << " ";
|
||||
bv->updateInset(it, false);
|
||||
bv->text->setCursorIntern(bv, bv->text->cursor.par(),
|
||||
bv->text->cursor.pos());
|
||||
} else {
|
||||
bv->text->redoParagraphs(bv, bv->text->cursor, endpar);
|
||||
if (tmppar) {
|
||||
LyXText * t;
|
||||
Inset * it = tmppar->inInset();
|
||||
if (it) {
|
||||
it->edit(bv);
|
||||
t = it->getLyXText(bv);
|
||||
} else {
|
||||
t = bv->text;
|
||||
}
|
||||
t->setCursorIntern(bv, tmppar, undo.cursor_pos);
|
||||
// clear any selection and set the selection cursor
|
||||
// for an evt. new selection.
|
||||
t->clearSelection();
|
||||
t->selection.cursor = t->cursor;
|
||||
t->updateCounters(bv, t->cursor.row());
|
||||
}
|
||||
}
|
||||
|
||||
// And here it's safe enough to delete all removed paragraphs
|
||||
vector<Paragraph *>::iterator pit = deletelist.begin();
|
||||
if (pit != deletelist.end()) {
|
||||
for(;pit != deletelist.end(); ++pit) {
|
||||
(*pit)->previous(0);
|
||||
(*pit)->next(0);
|
||||
delete (*pit);
|
||||
}
|
||||
#if 0
|
||||
lyxerr << endl << "PARS AFTER:";
|
||||
end = bv->buffer()->par_iterator_end();
|
||||
it = bv->buffer()->par_iterator_begin();
|
||||
for (; it != end; ++it)
|
||||
lyxerr << (*it)->previous() << "<- " << (*it) << " ->" << (*it)->next() << endl;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
finishUndo();
|
||||
bv->text->status(bv, LyXText::NEED_MORE_REFRESH);
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void finishUndo()
|
||||
{
|
||||
// makes sure the next operation will be stored
|
||||
undo_finished = true;
|
||||
}
|
||||
|
||||
|
||||
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 setUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind)
|
||||
{
|
||||
if (!undo_frozen) {
|
||||
bv->buffer()->undostack.push(createUndo(bv, kind, first, behind));
|
||||
bv->buffer()->redostack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setRedo(BufferView * bv, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind)
|
||||
{
|
||||
bv->buffer()->redostack.push(createUndo(bv, kind, first, behind));
|
||||
}
|
||||
|
||||
|
||||
Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind)
|
||||
|
||||
bool createUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind, shared_ptr<Undo> & u)
|
||||
{
|
||||
lyx::Assert(first);
|
||||
|
||||
@ -359,6 +274,8 @@ Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
if (first->inInset())
|
||||
inset_id = first->inInset()->id();
|
||||
|
||||
Buffer * b = bv->buffer();
|
||||
|
||||
// Undo::EDIT and Undo::FINISH are
|
||||
// always finished. (no overlapping there)
|
||||
// overlapping only with insert and delete inside one paragraph:
|
||||
@ -367,15 +284,16 @@ Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
// EDIT is special since only layout information, not the
|
||||
// contents of a paragaph are stored.
|
||||
if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)) {
|
||||
// check wether storing is needed
|
||||
if (!bv->buffer()->undostack.empty() &&
|
||||
bv->buffer()->undostack.top()->kind == kind &&
|
||||
bv->buffer()->undostack.top()->number_of_before_par == before_number &&
|
||||
bv->buffer()->undostack.top()->number_of_behind_par == behind_number) {
|
||||
// check whether storing is needed
|
||||
if (!b->undostack.empty() &&
|
||||
b->undostack.top()->kind == kind &&
|
||||
b->undostack.top()->number_of_before_par == before_number &&
|
||||
b->undostack.top()->number_of_behind_par == behind_number) {
|
||||
// no undo needed
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// create a new Undo
|
||||
Paragraph * undopar;
|
||||
|
||||
@ -406,6 +324,7 @@ Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
|
||||
while (tmppar != end && tmppar->next()) {
|
||||
tmppar = tmppar->next();
|
||||
// FIXME: what does this #if 0 mean ?
|
||||
#if 0
|
||||
tmppar2->next(new Paragraph(*tmppar, true));
|
||||
#else
|
||||
@ -428,12 +347,133 @@ Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
int cursor_par = undoCursor(bv).par()->id();
|
||||
int cursor_pos = undoCursor(bv).pos();
|
||||
|
||||
Undo * undo = new Undo(kind, inset_id,
|
||||
before_number, behind_number,
|
||||
cursor_par, cursor_pos, undopar);
|
||||
u.reset(new Undo(kind, inset_id,
|
||||
before_number, behind_number,
|
||||
cursor_par, cursor_pos, undopar));
|
||||
|
||||
undo_finished = false;
|
||||
return undo;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // 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
|
||||
undo_frozen = true;
|
||||
}
|
||||
|
||||
|
||||
void unFreezeUndo()
|
||||
{
|
||||
// this is dangerous and for internal use only
|
||||
undo_frozen = false;
|
||||
}
|
||||
|
||||
|
||||
// returns false if no undo possible
|
||||
bool textUndo(BufferView * bv)
|
||||
{
|
||||
Buffer * b = bv->buffer();
|
||||
|
||||
if (b->undostack.empty()) {
|
||||
finishNoUndo(bv);
|
||||
return false;
|
||||
}
|
||||
|
||||
shared_ptr<Undo> undo = b->undostack.top();
|
||||
b->undostack.pop();
|
||||
finishUndo();
|
||||
|
||||
if (!undo_frozen) {
|
||||
Paragraph * first = b->getParFromID(undo->number_of_before_par);
|
||||
if (first && first->next())
|
||||
first = first->next();
|
||||
else if (!first)
|
||||
first = firstUndoParagraph(bv, undo->number_of_inset_id);
|
||||
if (first) {
|
||||
shared_ptr<Undo> u;
|
||||
if (createUndo(bv, undo->kind, first,
|
||||
b->getParFromID(undo->number_of_behind_par), u))
|
||||
b->redostack.push(u);
|
||||
}
|
||||
}
|
||||
|
||||
// now we can unlock the inset for saftey because the inset pointer could
|
||||
// be changed during the undo-function. Anyway if needed we have to lock
|
||||
// the right inset/position if this is requested.
|
||||
freezeUndo();
|
||||
bv->unlockInset(bv->theLockingInset());
|
||||
bool const ret = textHandleUndo(bv, *undo.get());
|
||||
unFreezeUndo();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// returns false if no redo possible
|
||||
bool textRedo(BufferView * bv)
|
||||
{
|
||||
Buffer * b = bv->buffer();
|
||||
|
||||
if (b->redostack.empty()) {
|
||||
finishNoUndo(bv);
|
||||
return false;
|
||||
}
|
||||
|
||||
shared_ptr<Undo> undo = b->redostack.top();
|
||||
b->redostack.pop();
|
||||
finishUndo();
|
||||
|
||||
if (!undo_frozen) {
|
||||
Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
|
||||
if (first && first->next())
|
||||
first = first->next();
|
||||
else if (!first)
|
||||
first = firstUndoParagraph(bv, undo->number_of_inset_id);
|
||||
if (first) {
|
||||
shared_ptr<Undo> u;
|
||||
if (createUndo(bv, undo->kind, first,
|
||||
bv->buffer()->getParFromID(undo->number_of_behind_par), u))
|
||||
bv->buffer()->undostack.push(u);
|
||||
}
|
||||
}
|
||||
|
||||
// now we can unlock the inset for saftey because the inset pointer could
|
||||
// be changed during the undo-function. Anyway if needed we have to lock
|
||||
// the right inset/position if this is requested.
|
||||
freezeUndo();
|
||||
bv->unlockInset(bv->theLockingInset());
|
||||
bool ret = textHandleUndo(bv, *undo.get());
|
||||
unFreezeUndo();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void setUndo(BufferView * bv, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind)
|
||||
{
|
||||
if (!undo_frozen) {
|
||||
shared_ptr<Undo> u;
|
||||
if (createUndo(bv, kind, first, behind, u))
|
||||
bv->buffer()->undostack.push(u);
|
||||
bv->buffer()->redostack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setRedo(BufferView * bv, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind)
|
||||
{
|
||||
shared_ptr<Undo> u;
|
||||
if (createUndo(bv, kind, first, behind, u))
|
||||
bv->buffer()->redostack.push(u);
|
||||
}
|
||||
|
||||
|
||||
@ -442,23 +482,3 @@ void setCursorParUndo(BufferView * bv)
|
||||
setUndo(bv, Undo::FINISH, bv->text->cursor.par(),
|
||||
bv->text->cursor.par()->next());
|
||||
}
|
||||
|
||||
|
||||
Paragraph * firstUndoParagraph(BufferView * bv, int inset_id)
|
||||
{
|
||||
Inset * inset = bv->buffer()->getInsetFromID(inset_id);
|
||||
if (inset) {
|
||||
Paragraph * result = inset->getFirstParagraph(0);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
return bv->text->ownerParagraph();
|
||||
}
|
||||
|
||||
|
||||
LyXCursor const & undoCursor(BufferView * bv)
|
||||
{
|
||||
if (bv->theLockingInset())
|
||||
return bv->theLockingInset()->cursor(bv);
|
||||
return bv->text->cursor;
|
||||
}
|
||||
|
@ -19,43 +19,28 @@
|
||||
|
||||
class BufferView;
|
||||
class Paragraph;
|
||||
class LyXCursor;
|
||||
|
||||
/// returns false if no undo possible
|
||||
extern bool textUndo(BufferView *);
|
||||
/// returns false if no redo possible
|
||||
extern bool textRedo(BufferView *);
|
||||
/// used by TextUndo/TextRedo
|
||||
extern bool textHandleUndo(BufferView *, Undo * undo);
|
||||
/// makes sure the next operation will be stored
|
||||
extern void finishUndo();
|
||||
/// this is dangerous and for internal use only
|
||||
extern void freezeUndo();
|
||||
/// this is dangerous and for internal use only
|
||||
extern void unFreezeUndo();
|
||||
///
|
||||
/// FIXME
|
||||
extern void setUndo(BufferView *, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind);
|
||||
///
|
||||
/// FIXME
|
||||
extern void setRedo(BufferView *, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind);
|
||||
///
|
||||
extern Undo * createUndo(BufferView *, Undo::undo_kind kind,
|
||||
Paragraph const * first, Paragraph const * behind);
|
||||
/// for external use in lyx_cb.C
|
||||
/// FIXME
|
||||
extern void setCursorParUndo(BufferView *);
|
||||
|
||||
// returns a pointer to the very first Paragraph depending of where we are
|
||||
// so it will return the first paragraph of the buffer or the first paragraph
|
||||
// of the textinset we're in.
|
||||
extern Paragraph * firstUndoParagraph(BufferView *, int inset_arg);
|
||||
|
||||
///
|
||||
extern LyXCursor const & undoCursor(BufferView * bv);
|
||||
|
||||
/// the flag used by FinishUndo();
|
||||
extern bool undo_finished;
|
||||
/// a flag
|
||||
// This is only used in one place. Need a nicer way.
|
||||
/// is the undo frozen
|
||||
extern bool undo_frozen;
|
||||
|
||||
#endif
|
||||
#endif // UNDO_FUNCS_H
|
||||
|
@ -1,81 +0,0 @@
|
||||
/* This file is part of
|
||||
* ======================================================
|
||||
*
|
||||
* LyX, The Document Processor
|
||||
*
|
||||
* Copyright 1995 Matthias Ettrich
|
||||
* Copyright 1995-2001 The LyX Team.
|
||||
*
|
||||
* ====================================================== */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef __GNUG__
|
||||
#pragma implementation
|
||||
#endif
|
||||
|
||||
#include "undostack.h"
|
||||
#include "undo.h"
|
||||
#include "paragraph.h"
|
||||
|
||||
|
||||
UndoStack::UndoStack()
|
||||
: limit(100) {}
|
||||
|
||||
|
||||
void UndoStack::pop()
|
||||
{
|
||||
if (stakk.empty())
|
||||
return;
|
||||
stakk.pop_front();
|
||||
}
|
||||
|
||||
|
||||
Undo * UndoStack::top() const
|
||||
{
|
||||
if (stakk.empty())
|
||||
return 0;
|
||||
return stakk.front();
|
||||
}
|
||||
|
||||
|
||||
UndoStack::~UndoStack()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
void UndoStack::clear()
|
||||
{
|
||||
while (!stakk.empty()) {
|
||||
Undo * tmp = stakk.front();
|
||||
stakk.pop_front();
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UndoStack::SetStackLimit(Stakk::size_type l)
|
||||
{
|
||||
limit = l;
|
||||
}
|
||||
|
||||
|
||||
void UndoStack::push(Undo * undo_arg)
|
||||
{
|
||||
if (!undo_arg)
|
||||
return;
|
||||
|
||||
stakk.push_front(undo_arg);
|
||||
if (stakk.size() > limit) {
|
||||
Undo * tmp = stakk.back();
|
||||
stakk.pop_back();
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool UndoStack::empty() const
|
||||
{
|
||||
return stakk.empty();
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
/* This file is part of
|
||||
* ======================================================
|
||||
*
|
||||
* LyX, The Document Processor
|
||||
*
|
||||
* Copyright 1995 Matthias Ettrich
|
||||
* Copyright 1995-2001 The LyX Team.
|
||||
*
|
||||
* ====================================================== */
|
||||
|
||||
#ifndef UNDO_STACK_H
|
||||
#define UNDO_STACK_H
|
||||
|
||||
#ifdef __GNUG__
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
|
||||
class Undo;
|
||||
|
||||
/// A limited Stack for the undo informations.
|
||||
class UndoStack {
|
||||
private:
|
||||
///
|
||||
typedef std::list<Undo*> Stakk;
|
||||
///
|
||||
Stakk stakk;
|
||||
/// the maximum number of undo steps stored.
|
||||
Stakk::size_type limit;
|
||||
public:
|
||||
///
|
||||
UndoStack();
|
||||
///
|
||||
~UndoStack();
|
||||
///
|
||||
void pop();
|
||||
///
|
||||
Undo * top() const;
|
||||
///
|
||||
bool empty() const;
|
||||
///
|
||||
void clear();
|
||||
///
|
||||
void SetStackLimit(Stakk::size_type l);
|
||||
///
|
||||
void push(Undo * undo_arg);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user