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());
172 it->update(bv, font, false);
173 #ifdef THIS_DOES_NOT_WORK
174 // we need this anyway as also if the undo was inside an inset
175 // we have to redo the paragraph breaking
176 bv->text->redoParagraphs(bv, bv->text->cursor,
177 bv->text->cursor.par());
180 bv->text->redoParagraphs(bv, bv->text->cursor, endpar);
182 bv->text->setCursorIntern(bv, tmppar, undo->cursor_pos);
183 bv->text->updateCounters(bv, bv->text->cursor.row());
190 bv->text->status(bv, LyXText::NEED_MORE_REFRESH);
197 // makes sure the next operation will be stored
198 undo_finished = true;
204 // this is dangerous and for internal use only
211 // this is dangerous and for internal use only
216 void setUndo(BufferView * bv, Undo::undo_kind kind,
217 Paragraph const * first, Paragraph const * behind)
220 bv->buffer()->undostack.push(createUndo(bv, kind, first, behind));
221 bv->buffer()->redostack.clear();
225 void setRedo(BufferView * bv, Undo::undo_kind kind,
226 Paragraph const * first, Paragraph const * behind)
228 bv->buffer()->redostack.push(createUndo(bv, kind, first, behind));
233 Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
234 Paragraph const * first, Paragraph const * behind)
238 int before_number = -1;
239 int behind_number = -1;
242 if (first->previous())
243 before_number = first->previous()->id();
245 behind_number = behind->id();
246 if (first->inInset())
247 inset_id = first->inInset()->id();
249 // Undo::EDIT and Undo::FINISH are
250 // always finished. (no overlapping there)
251 // overlapping only with insert and delete inside one paragraph:
252 // Nobody wants all removed character
253 // appear one by one when undoing.
254 // EDIT is special since only layout information, not the
255 // contents of a paragaph are stored.
256 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
257 // check wether storing is needed
258 if (!bv->buffer()->undostack.empty() &&
259 bv->buffer()->undostack.top()->kind == kind &&
260 bv->buffer()->undostack.top()->number_of_before_par == before_number &&
261 bv->buffer()->undostack.top()->number_of_behind_par == behind_number ){
269 Paragraph * start = const_cast<Paragraph *>(first);
273 end = const_cast<Paragraph*>(behind->previous());
279 if (start && end && (start != end->next()) &&
280 ((before_number != behind_number) ||
281 ((before_number < 0) && (behind_number < 0)))) {
282 Paragraph * tmppar = start;
283 Paragraph * tmppar2 = new Paragraph(*tmppar, true);
284 tmppar2->id(tmppar->id());
286 // a memory optimization: Just store the layout information
288 if (kind == Undo::EDIT) {
289 tmppar2->clearContents();
294 while (tmppar != end && tmppar->next()) {
295 tmppar = tmppar->next();
296 tmppar2->next(new Paragraph(*tmppar, false));
297 tmppar2->next()->id(tmppar->id());
298 // a memory optimization: Just store the layout
299 // information when only edit
300 if (kind == Undo::EDIT) {
301 tmppar2->clearContents();
303 tmppar2->next()->previous(tmppar2);
304 tmppar2 = tmppar2->next();
308 undopar = 0; // nothing to replace (undo of delete maybe)
310 int cursor_par = undoCursor(bv).par()->id();
311 int cursor_pos = undoCursor(bv).pos();
313 Undo * undo = new Undo(kind, inset_id,
314 before_number, behind_number,
315 cursor_par, cursor_pos, undopar);
317 undo_finished = false;
322 void setCursorParUndo(BufferView * bv)
324 setUndo(bv, Undo::FINISH,
325 bv->text->cursor.par(),
326 bv->text->cursor.par()->next());
329 Paragraph * firstUndoParagraph(BufferView * bv, int inset_id)
331 Inset * inset = bv->buffer()->getInsetFromID(inset_id);
333 Paragraph * result = inset->firstParagraph();
337 return bv->text->ownerParagraph();
340 LyXCursor const & undoCursor(BufferView * bv)
342 if (bv->theLockingInset())
343 return bv->theLockingInset()->cursor(bv);
344 return bv->text->cursor;