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:
123 // Only layout information
124 // is stored in the undo. So restore
125 // the text informations.
126 if (undo->kind == Undo::EDIT) {
127 tmppar2->setContentsFromPar(tmppar);
128 tmppar->clearContents();
129 tmppar2 = tmppar2->next();
134 // put the new stuff in the list if there is one
137 before->next(tmppar3);
139 bv->text->ownerParagraph(tmppar3->id(), tmppar3);
140 tmppar3->previous(before);
142 // Do we really enter here ??? (Jug)
144 bv->text->ownerParagraph(behind);
147 tmppar4->next(behind);
149 behind->previous(tmppar4);
153 // Set the cursor for redoing
155 bv->text->setCursorIntern(bv, before, 0);
158 // calculate the endpar for redoing the paragraphs.
160 endpar = behind->next();
164 tmppar = bv->buffer()->getParFromID(undo->number_of_cursor_par);
165 UpdatableInset* it = static_cast<UpdatableInset*>(tmppar3->inInset());
167 it->getLyXText(bv)->redoParagraphs(bv, it->getLyXText(bv)->cursor,
170 it->getLyXText(bv)->setCursorIntern(bv, tmppar, undo->cursor_pos);
171 it->getLyXText(bv)->updateCounters(bv, it->getLyXText(bv)->cursor.row());
174 it->update(bv, font, false);
175 #ifdef THIS_DOES_NOT_WORK
176 // we need this anyway as also if the undo was
177 // inside an inset we have to redo the
178 // paragraph breaking
179 bv->text->redoParagraphs(bv, bv->text->cursor,
180 bv->text->cursor.par());
183 bv->text->redoParagraphs(bv, bv->text->cursor, endpar);
185 bv->text->setCursorIntern(bv, tmppar, undo->cursor_pos);
186 bv->text->updateCounters(bv, bv->text->cursor.row());
193 bv->text->status(bv, LyXText::NEED_MORE_REFRESH);
200 // makes sure the next operation will be stored
201 undo_finished = true;
207 // this is dangerous and for internal use only
214 // this is dangerous and for internal use only
219 void setUndo(BufferView * bv, Undo::undo_kind kind,
220 Paragraph const * first, Paragraph const * behind)
223 bv->buffer()->undostack.push(createUndo(bv, kind, first, behind));
224 bv->buffer()->redostack.clear();
228 void setRedo(BufferView * bv, Undo::undo_kind kind,
229 Paragraph const * first, Paragraph const * behind)
231 bv->buffer()->redostack.push(createUndo(bv, kind, first, behind));
236 Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
237 Paragraph const * first, Paragraph const * behind)
241 int before_number = -1;
242 int behind_number = -1;
245 if (first->previous())
246 before_number = first->previous()->id();
248 behind_number = behind->id();
249 if (first->inInset())
250 inset_id = first->inInset()->id();
252 // Undo::EDIT and Undo::FINISH are
253 // always finished. (no overlapping there)
254 // overlapping only with insert and delete inside one paragraph:
255 // Nobody wants all removed character
256 // appear one by one when undoing.
257 // EDIT is special since only layout information, not the
258 // contents of a paragaph are stored.
259 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
260 // check wether storing is needed
261 if (!bv->buffer()->undostack.empty() &&
262 bv->buffer()->undostack.top()->kind == kind &&
263 bv->buffer()->undostack.top()->number_of_before_par == before_number &&
264 bv->buffer()->undostack.top()->number_of_behind_par == behind_number ){
272 Paragraph * start = const_cast<Paragraph *>(first);
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;