the latest undo patch without the paragraphlist stuff

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@7102 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
André Pönitz 2003-06-04 12:45:26 +00:00
parent 6a50ae699b
commit a5c7dde1e4
6 changed files with 201 additions and 218 deletions

View File

@ -17,11 +17,13 @@
#include <boost/next_prior.hpp>
#include <boost/optional.hpp>
#include <stack>
// it's conceptionally a stack, but undo needs random access...
//#include <stack>
#include <vector>
using boost::next;
using boost::optional;
using std::stack;
using std::vector;
///
/// ParPosition
@ -68,14 +70,14 @@ bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
///
struct ParIterator::Pimpl {
typedef stack<ParPosition> PosHolder;
typedef vector<ParPosition> PosHolder;
PosHolder positions;
};
ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
: pimpl_(new Pimpl)
{
pimpl_->positions.push(ParPosition(pit, pl));
pimpl_->positions.push_back(ParPosition(pit, pl));
}
@ -98,14 +100,14 @@ void ParIterator::operator=(ParIterator const & pi)
ParIterator & ParIterator::operator++()
{
while (!pimpl_->positions.empty()) {
ParPosition & p = pimpl_->positions.top();
ParPosition & p = pimpl_->positions.back();
// Does the current inset contain more "cells" ?
if (p.index) {
++(*p.index);
ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
if (plist && !plist->empty()) {
pimpl_->positions.push(ParPosition(plist->begin(), *plist));
pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
return *this;
}
++(*p.it);
@ -121,7 +123,7 @@ ParIterator & ParIterator::operator++()
ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
if (plist && !plist->empty()) {
p.index.reset(0);
pimpl_->positions.push(ParPosition(plist->begin(), *plist));
pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
return *this;
}
}
@ -137,7 +139,7 @@ ParIterator & ParIterator::operator++()
}
// Drop end and move up in the stack.
pimpl_->positions.pop();
pimpl_->positions.pop_back();
}
return *this;
}
@ -145,13 +147,19 @@ ParIterator & ParIterator::operator++()
ParagraphList::iterator ParIterator::operator*() const
{
return pimpl_->positions.top().pit;
return pimpl_->positions.back().pit;
}
ParagraphList::iterator ParIterator::operator->() const
{
return pimpl_->positions.top().pit;
return pimpl_->positions.back().pit;
}
ParagraphList::iterator ParIterator::outerPar() const
{
return pimpl_->positions[0].pit;
}
@ -163,7 +171,7 @@ size_t ParIterator::size() const
ParagraphList & ParIterator::plist() const
{
return *const_cast<ParagraphList*>(pimpl_->positions.top().plist);
return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
}
@ -185,7 +193,7 @@ bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
struct ParConstIterator::Pimpl {
typedef stack<ParPosition> PosHolder;
typedef vector<ParPosition> PosHolder;
PosHolder positions;
};
@ -194,7 +202,7 @@ ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
ParagraphList const & pl)
: pimpl_(new Pimpl)
{
pimpl_->positions.push(ParPosition(pit, pl));
pimpl_->positions.push_back(ParPosition(pit, pl));
}
@ -210,14 +218,14 @@ ParConstIterator::ParConstIterator(ParConstIterator const & pi)
ParConstIterator & ParConstIterator::operator++()
{
while (!pimpl_->positions.empty()) {
ParPosition & p = pimpl_->positions.top();
ParPosition & p = pimpl_->positions.back();
// Does the current inset contain more "cells" ?
if (p.index) {
++(*p.index);
ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
if (plist && !plist->empty()) {
pimpl_->positions.push(ParPosition(plist->begin(), *plist));
pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
return *this;
}
++(*p.it);
@ -233,7 +241,7 @@ ParConstIterator & ParConstIterator::operator++()
ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
if (plist && !plist->empty()) {
p.index.reset(0);
pimpl_->positions.push(ParPosition(plist->begin(), *plist));
pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
return *this;
}
}
@ -249,7 +257,7 @@ ParConstIterator & ParConstIterator::operator++()
}
// Drop end and move up in the stack.
pimpl_->positions.pop();
pimpl_->positions.pop_back();
}
return *this;
@ -258,13 +266,13 @@ ParConstIterator & ParConstIterator::operator++()
ParagraphList::iterator ParConstIterator::operator*() const
{
return pimpl_->positions.top().pit;
return pimpl_->positions.back().pit;
}
ParagraphList::iterator ParConstIterator::operator->() const
{
return pimpl_->positions.top().pit;
return pimpl_->positions.back().pit;
}

View File

@ -33,6 +33,8 @@ public:
///
ParagraphList::iterator operator->() const;
///
ParagraphList::iterator outerPar() const;
///
ParagraphList & plist() const;
///
size_t size() const;

View File

@ -658,7 +658,7 @@ void LyXText::redoDrawingOfParagraph(LyXCursor const & cur)
}
// deletes and inserts again all paragaphs between the cursor
// deletes and inserts again all paragraphs between the cursor
// and the specified par
// This function is needed after SetLayout and SetFont etc.
void LyXText::redoParagraphs(LyXCursor const & cur,

View File

@ -11,20 +11,19 @@
#include <config.h>
#include "undo.h"
#include "paragraph.h"
Undo::Undo(undo_kind kind_arg, int id_inset_arg,
int number_before_arg, int number_behind_arg,
int cursor_par_arg, int cursor_pos_arg,
ParagraphList const & par_arg)
: pars(par_arg)
{
kind = kind_arg;
number_of_inset_id = id_inset_arg;
number_of_before_par = number_before_arg;
number_of_behind_par = number_behind_arg;
number_of_cursor_par = cursor_par_arg;
cursor_pos = cursor_pos_arg;
}
Undo::Undo(undo_kind kind_arg, int inset, int plist,
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),
cursor_pos(cursor_pos_arg),
pars(par)
{}

View File

@ -31,22 +31,24 @@ public:
///
undo_kind kind;
///
int number_of_before_par;
int inset_id; // valid if >= 0, if < 0 then not in inset
///
int number_of_behind_par;
int plist_id;
///
int number_of_cursor_par;
int first_par_offset;
///
int number_of_inset_id; // valid if >= 0, if < 0 then not in inset
int last_par_offset;
///
int cursor_par_offset;
///
int cursor_pos; // valid if >= 0
///
ParagraphList pars;
///
Undo(undo_kind kind, int inset_id,
int before_par_id, int behind_par_id,
int cursor_par_id, int cursor_pos,
Undo(undo_kind kind, int inset_id, int plist_id,
int first, int last,
int cursor, int cursor_pos,
ParagraphList const & par_arg);
};

View File

@ -48,78 +48,53 @@ bool textHandleUndo(BufferView * bv, Undo & undo)
{
Buffer * buf = bv->buffer();
ParIterator const before = buf->getParFromID(undo.number_of_before_par);
ParIterator const behind = buf->getParFromID(undo.number_of_behind_par);
ParIterator const null = buf->par_iterator_end();
ParagraphList * plist = &buf->paragraphs;
/*
ParIterator null = buf->par_iterator_end();
int const before_id = (before == null) ? -1 : before->id();
int const behind_id = (behind == null) ? -1 : behind->id();
int const inset_id = undo.number_of_inset_id;
Inset * inset = bv->buffer()->getInsetFromID(inset_id);
LyXText * text = inset ? inset->getLyXText(bv) : bv->text;
ParagraphList * plist = &bv->text->ownerParagraphs();
if (inset) {
ParagraphList * tmp = inset->getParagraphs(0);
if (tmp && !tmp->empty())
plist = tmp;
}
ParagraphList::iterator first;
if (before == null) {
// if there's no before take the beginning of parlist.
first = plist->begin();
text->setCursorIntern(plist->begin(), 0);
} else {
first = *before;
++first;
}
int const first_id = first->id();
lyxerr << "\nhandle: before_id: " << before_id << "\n";
lyxerr << "handle: first_id: " << first_id << "\n";
lyxerr << "handle: behind_id: " << behind_id << "\n";
lyxerr << "handle: inset_id: " << inset_id << "\n";
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 * in = 0;
if (before != null)
in = before->inInset();
else if (inset_id >= 0) {
Inset * inset = bv->buffer()->getInsetFromID(inset_id);
in = static_cast<UpdatableInset *>(inset);
UpdatableInset * inset = 0;
if (undo.inset_id >= 0) {
Inset * in = bv->buffer()->getInsetFromID(undo.inset_id);
inset = static_cast<UpdatableInset *>(in);
}
ParagraphList::iterator pit = undo.pars.begin();
ParagraphList::iterator end = undo.pars.end();
for ( ; pit != end; ++pit)
pit->setInsetOwner(in);
lyxerr << "in: " << in << "\n";
lyxerr << "undo.pars.size(): " << undo.pars.size() << "\n";
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";
// remove stuff between first and behind
if (behind == null)
plist->erase(first, plist->end());
else
plist->erase(first, *behind);
lyxerr << "after erase\n";
// re-create first
if (before == null) {
// if there's no before take the beginning of parlist.
lyxerr << "no 'before'\n";
first = plist->begin();
} else {
lyxerr << "have 'before'\n";
first = *before;
++first;
{
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";
plist->erase(first, ++last);
lyxerr << "after remove\n";
}
// re-insert old stuff
{
ParagraphList::iterator first = plist->begin();
advance(first, undo.first_par_offset);
plist->insert(first, undo.pars.begin(), undo.pars.end());
lyxerr << "after insert\n";
}
// inset saved paragraphs
lyxerr << "undo.pars.size(): " << undo.pars.size() << "\n";
plist->insert(first, undo.pars.begin(), undo.pars.end());
lyxerr << "after insert\n";
/*
// A memory optimization for edit:
// Only layout information
@ -131,53 +106,53 @@ bool textHandleUndo(BufferView * bv, Undo & undo)
}
*/
// Set the cursor for redoing
// if we have a par before the first.
if (before != null) {
Inset * it = before->inInset();
LyXText * text = it ? it->getLyXText(bv) : bv->text;
text->setCursorIntern(*before, 0);
}
UpdatableInset * it = 0;
if (first != plist->end())
it = first->inInset();
lyxerr << "it: " << it << "\n";
text->redoParagraphs(text->cursor, plist->end());
ParIterator tmppar = bv->buffer()->getParFromID(inset_id);
if (tmppar != null) {
lyxerr << "tmppar: " << tmppar->id() << "\n";
LyXText * t;
Inset * it = tmppar->inInset();
if (it) {
FuncRequest cmd(bv, LFUN_INSET_EDIT, "left");
it->localDispatch(cmd);
t = it->getLyXText(bv);
} else {
t = bv->text;
// redo Paragraphs (should be handled outside undo...)
LyXText * text = inset ? inset->getLyXText(bv) : bv->text;
{
lyxerr << "text: " << text << "\n";
if (undo.first_par_offset) {
ParagraphList::iterator redo = plist->begin();
advance(redo, undo.first_par_offset);
text->setCursorIntern(plist->begin(), 0);
}
t->setCursorIntern(*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();
} else {
lyxerr << "tmppar == null \n";
text->redoParagraphs(text->cursor, plist->end());
lyxerr << "after redo\n";
}
/*
Inset * = bv->buffer()->getInsetFromID(inset_id);
lyxerr << "tmppar: " << tmppar->id() << "\n";
LyXText * t;
if (it) {
FuncRequest cmd(bv, LFUN_INSET_EDIT, "left");
it->localDispatch(cmd);
t = it->getLyXText(bv);
} else {
t = bv->text;
}
t->setCursorIntern(*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();
*/
if (inset) {
lyxerr << "fit cursor...\n";
bv->fitCursor();
bv->updateInset(it);
bv->text->setCursorIntern(bv->text->cursor.par(),
bv->text->cursor.pos());
bv->updateInset(inset);
}
// set cursor
{
ParagraphList::iterator cursor = plist->begin();
advance(cursor, undo.cursor_par_offset);
bv->text->setCursorIntern(cursor, undo.cursor_pos);
lyxerr << "after setCursor\n";
}
finishUndo();
bv->text->postPaint(0);
@ -187,55 +162,60 @@ bool textHandleUndo(BufferView * bv, Undo & undo)
void createUndo(BufferView * bv, Undo::undo_kind kind,
int first_id, int last_id,
ParagraphList::iterator first, ParagraphList::iterator last,
limited_stack<Undo> & stack)
{
Buffer * buf = bv->buffer();
ParIterator null = buf->par_iterator_end();
ParIterator prev = null;
ParIterator before = null;
ParIterator first = null;
ParIterator last = null;
ParIterator behind = null;
for (ParIterator it = buf->par_iterator_begin(); it != null; ++it) {
if (it->id() == first_id) {
first = it;
before = prev;
}
if (it->id() == last_id) {
last = it;
behind = last;
++behind;
}
prev = it;
}
if (last == null)
last = first;
int const before_id = (before == null) ? -1 : before->id();
int const behind_id = (behind == null) ? -1 : behind->id();
int inset_id = (first->inInset()) ? first->inInset()->id() : -1;
lyxerr << "\ncreate: before_id: " << before_id << "\n";
lyxerr << "create: first_id: " << first_id << "\n";
lyxerr << "create: last_id: " << last_id << "\n";
lyxerr << "create: behind_id: " << behind_id << "\n";
lyxerr << "create: inset_id: " << inset_id << "\n";
lyxerr << "create: kind: " << kind << "\n";
ParagraphList * plist = 0;
if (first != null)
plist = &first.plist();
else if (behind != null)
plist = &behind.plist();
else if (!plist) {
lyxerr << "plist from buffer (should this happen?)\n";
plist = &buf->paragraphs;
ParIterator null = buf->par_iterator_end();
lyxerr << "\n";
#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;
}
}
#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
for (ParIterator it = buf->par_iterator_begin(); it != null; ++it) {
if (it->id() == first->id()) {
first = it.outerPar();
last = it.outerPar();
break;
}
}
#endif
int const inset_id = first->inInset() ? first->inInset()->id() : -1;
int const first_offset = std::distance(plist->begin(), first);
int const last_offset = std::distance(last, plist->end());
if (last == plist->end()) {
lyxerr << "*** createUndo: last == end schould not happen\n";
}
//lyxerr << "create: plist_id: " << plist->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: inset_id: " << inset_id << "\n";
lyxerr << "create: kind: " << kind << "\n";
// Undo::EDIT and Undo::FINISH are
// always finished. (no overlapping there)
// overlapping only with insert and delete inside one paragraph:
@ -247,27 +227,33 @@ void createUndo(BufferView * bv, Undo::undo_kind kind,
// Check whether storing is needed.
if (!buf->undostack.empty() &&
buf->undostack.top().kind == kind &&
buf->undostack.top().number_of_before_par == before_id &&
buf->undostack.top().number_of_behind_par == behind_id) {
buf->undostack.top().first_par_offset == first_offset &&
buf->undostack.top().last_par_offset == last_offset) {
// No undo needed.
return;
}
}
// Create a new Undo.
/*
// this should be re-activated once we are back at fine-grained undo
LyXCursor const & cur = bv->theLockingInset() ?
bv->theLockingInset()->cursor(bv) : bv->text->cursor;
int const cursor_offset = std::distance(plist->begin(), cur.par());
stack.push(Undo(kind, inset_id,
before_id, behind_id, cur.par()->id(), cur.pos(), ParagraphList()));
stack.push(Undo(kind, inset_id, plist->id(),
first_offset, last_offset, cursor_offset, cur.pos(), ParagraphList()));
*/
stack.push(Undo(kind, inset_id, 0, //plist->id(),
first_offset, last_offset, first_offset, 0, ParagraphList()));
ParagraphList & undo_pars = stack.top().pars;
for (ParagraphList::iterator it = *first; it != *last; ++it) {
for (ParagraphList::iterator it = first; it != last; ++it) {
undo_pars.push_back(*it);
undo_pars.back().id(it->id());
}
undo_pars.push_back(**last);
undo_pars.push_back(*last);
undo_pars.back().id(last->id());
// A memory optimization: Just store the layout
@ -284,7 +270,7 @@ void createUndo(BufferView * bv, Undo::undo_kind kind,
// Returns false if no undo possible.
bool textUndoOrRedo(BufferView * bv,
limited_stack<Undo> & stack,
limited_stack<Undo> & /*otherstack*/)
limited_stack<Undo> & otherstack)
{
if (stack.empty()) {
finishNoUndo(bv);
@ -295,38 +281,24 @@ bool textUndoOrRedo(BufferView * bv,
stack.pop();
finishUndo();
/*
if (!undo_frozen) {
otherstack.push(undo);
otherstack.top().pars.clear();
Buffer * buf = bv->buffer();
ParIterator p = buf->getParFromID(undo->number_of_before_par);
ParIterator const end = buf->par_iterator_end();
bool ok = false;
ParagraphList::iterator first;
// default constructed?
if (p != end) {
first = p.par();
if (first->next())
first = first->next();
} else {
// Set first 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.
first = bv->text->ownerParagraphs()->begin();
Inset * inset = bv->buffer()->getInsetFromID(inset_id);
if (inset) {
ParagraphList * result = inset->getParagraphs(0);
if (result && !result->empty())
first = result->begin();
}
}
if (ok) {
ParIterator behind = buf->getParFromID(undo.number_of_behind_par);
createUndo(bv, undo.kind, first, behind.par(), otherstack);
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);
ParagraphList::iterator last = plist.begin();
advance(last, plist.size() - undo.last_par_offset + 1);
otherstack.top().pars.insert(otherstack.top().pars.begin(), first, last);
}
}
*/
// Now we can unlock the inset for saftey because the inset
// Now we can unlock the inset for safety because the inset
// pointer could be changed during the undo-function. Anyway
// if needed we have to lock the right inset/position if this
// is requested.
@ -386,7 +358,7 @@ void setUndo(BufferView * bv, Undo::undo_kind kind,
ParagraphList::iterator first, ParagraphList::iterator last)
{
if (!undo_frozen) {
createUndo(bv, kind, first->id(), last->id(), bv->buffer()->undostack);
createUndo(bv, kind, first, last, bv->buffer()->undostack);
bv->buffer()->redostack.clear();
}
}