1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995-2001 The LyX Team.
8 * ====================================================== */
13 #pragma implementation
16 #include "undo_funcs.h"
18 #include "BufferView.h"
20 #include "insets/inset.h"
22 #include "support/LAssert.h"
24 /// the flag used by FinishUndo();
29 bool textUndo(BufferView * bv)
31 // returns false if no undo possible
32 Undo * undo = bv->buffer()->undostack.pop();
36 Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
38 first = firstUndoParagraph(bv, undo->number_of_inset_id);
40 bv->buffer()->redostack.push(
41 createUndo(bv, undo->kind, first,
42 bv->buffer()->getParFromID(undo->number_of_behind_par)));
46 return textHandleUndo(bv, undo);
50 bool textRedo(BufferView * bv)
52 // returns false if no redo possible
53 Undo * undo = bv->buffer()->redostack.pop();
57 Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
59 first = firstUndoParagraph(bv, undo->number_of_inset_id);
61 bv->buffer()->undostack.push(
62 createUndo(bv, undo->kind, first,
63 bv->buffer()->getParFromID(undo->number_of_behind_par)));
67 return textHandleUndo(bv, undo);
71 bool textHandleUndo(BufferView * bv, Undo * undo)
73 // returns false if no undo possible
77 bv->buffer()->getParFromID(undo->number_of_before_par);
79 bv->buffer()->getParFromID(undo->number_of_behind_par);
85 // if there's no before take the beginning
86 // of the document for redoing
88 LyXText * t = bv->text;
89 int num = undo->number_of_inset_id;
90 if (undo->number_of_inset_id >= 0) {
91 Inset * in = bv->buffer()->getInsetFromID(num);
93 t = in->getLyXText(bv);
98 t->setCursorIntern(bv, firstUndoParagraph(bv, num), 0);
101 // replace the paragraphs with the undo informations
103 Paragraph * tmppar3 = undo->par;
104 undo->par = 0; // otherwise the undo destructor would delete the paragraph
105 Paragraph * tmppar4 = tmppar3;
108 while (tmppar4->next())
109 tmppar4 = tmppar4->next();
110 } // get last undo par
112 // now remove the old text if there is any
113 if (before != behind || (!behind && !before)) {
115 tmppar5 = before->next();
117 tmppar5 = firstUndoParagraph(bv, undo->number_of_inset_id);
119 while (tmppar5 && tmppar5 != behind) {
121 tmppar5 = tmppar5->next();
122 // a memory optimization for edit: Only layout information
123 // is stored in the undo. So restore the text informations.
124 if (undo->kind == Undo::EDIT) {
125 tmppar2->setContentsFromPar(tmppar);
126 tmppar->clearContents();
127 tmppar2 = tmppar2->next();
132 // put the new stuff in the list if there is one
135 before->next(tmppar3);
137 bv->text->ownerParagraph(tmppar3->id(), tmppar3);
138 tmppar3->previous(before);
140 // Do we really enter here ??? (Jug)
142 bv->text->ownerParagraph(behind);
145 tmppar4->next(behind);
147 behind->previous(tmppar4);
151 // Set the cursor for redoing
153 bv->text->setCursorIntern(bv, before, 0);
156 // calculate the endpar for redoing the paragraphs.
158 endpar = behind->next();
162 tmppar = bv->buffer()->getParFromID(undo->number_of_cursor_par);
163 UpdatableInset* it = static_cast<UpdatableInset*>(tmppar3->inInset());
165 it->getLyXText(bv)->redoParagraphs(bv, it->getLyXText(bv)->cursor,
168 it->getLyXText(bv)->setCursorIntern(bv, tmppar, undo->cursor_pos);
169 it->getLyXText(bv)->updateCounters(bv, it->getLyXText(bv)->cursor.row());
171 #ifdef THIS_DOES_NOT_WORK
172 // we need this anyway as also if the undo was inside an inset
173 // we have to redo the paragraph breaking
174 bv->text->redoParagraphs(bv, bv->text->cursor,
175 bv->text->cursor.par());
178 bv->text->redoParagraphs(bv, bv->text->cursor, endpar);
180 bv->text->setCursorIntern(bv, tmppar, undo->cursor_pos);
181 bv->text->updateCounters(bv, bv->text->cursor.row());
188 bv->text->status(bv, LyXText::NEED_MORE_REFRESH);
195 // makes sure the next operation will be stored
196 undo_finished = true;
202 // this is dangerous and for internal use only
209 // this is dangerous and for internal use only
214 void setUndo(BufferView * bv, Undo::undo_kind kind,
215 Paragraph const * first, Paragraph const * behind)
218 bv->buffer()->undostack.push(createUndo(bv, kind, first, behind));
219 bv->buffer()->redostack.clear();
223 void setRedo(BufferView * bv, Undo::undo_kind kind,
224 Paragraph const * first, Paragraph const * behind)
226 bv->buffer()->redostack.push(createUndo(bv, kind, first, behind));
230 Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
231 Paragraph const * first, Paragraph const * behind)
235 int before_number = -1;
236 int behind_number = -1;
239 if (first->previous())
240 before_number = first->previous()->id();
242 behind_number = behind->id();
243 if (first->inInset())
244 inset_id = first->inInset()->id();
246 // Undo::EDIT and Undo::FINISH are
247 // always finished. (no overlapping there)
248 // overlapping only with insert and delete inside one paragraph:
249 // Nobody wants all removed character
250 // appear one by one when undoing.
251 // EDIT is special since only layout information, not the
252 // contents of a paragaph are stored.
253 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
254 // check wether storing is needed
255 if (!bv->buffer()->undostack.empty() &&
256 bv->buffer()->undostack.top()->kind == kind &&
257 bv->buffer()->undostack.top()->number_of_before_par == before_number &&
258 bv->buffer()->undostack.top()->number_of_behind_par == behind_number ){
266 Paragraph * start = const_cast<Paragraph *>(first);
271 start = const_cast<Paragraph*>(before->next());
273 start = firstUndoParagraph(bv);
276 end = const_cast<Paragraph*>(behind->previous());
282 if (start && end && (start != end->next()) &&
283 ((before_number != behind_number) ||
284 ((before_number < 0) && (behind_number < 0)))) {
285 Paragraph * tmppar = start;
286 Paragraph * tmppar2 = new Paragraph(*tmppar, true);
287 tmppar2->id(tmppar->id());
289 // a memory optimization: Just store the layout information
291 if (kind == Undo::EDIT) {
292 tmppar2->clearContents();
297 while (tmppar != end && tmppar->next()) {
298 tmppar = tmppar->next();
299 tmppar2->next(new Paragraph(*tmppar, false));
300 tmppar2->next()->id(tmppar->id());
301 // a memory optimization: Just store the layout
302 // information when only edit
303 if (kind == Undo::EDIT) {
304 tmppar2->clearContents();
306 tmppar2->next()->previous(tmppar2);
307 tmppar2 = tmppar2->next();
311 undopar = 0; // nothing to replace (undo of delete maybe)
313 int cursor_par = undoCursor(bv).par()->id();
314 int cursor_pos = undoCursor(bv).pos();
316 Undo * undo = new Undo(kind, inset_id,
317 before_number, behind_number,
318 cursor_par, cursor_pos, undopar);
320 undo_finished = false;
325 void setCursorParUndo(BufferView * bv)
327 setUndo(bv, Undo::FINISH,
328 bv->text->cursor.par(),
329 bv->text->cursor.par()->next());
332 Paragraph * firstUndoParagraph(BufferView * bv, int inset_id)
334 Inset * inset = bv->buffer()->getInsetFromID(inset_id);
336 Paragraph * result = inset->firstParagraph();
340 return bv->text->ownerParagraph();
343 LyXCursor const & undoCursor(BufferView * bv)
345 if (bv->theLockingInset())
346 return bv->theLockingInset()->cursor(bv);
347 return bv->text->cursor;