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"
23 /// the flag used by FinishUndo();
28 bool textUndo(BufferView * bv)
30 // returns false if no undo possible
31 Undo * undo = bv->buffer()->undostack.pop();
35 Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
37 first = firstUndoParagraph(bv, undo->number_of_inset_id);
39 bv->buffer()->redostack.push(
40 createUndo(bv, undo->kind, first,
41 bv->buffer()->getParFromID(undo->number_of_behind_par)));
45 return textHandleUndo(bv, undo);
49 bool textRedo(BufferView * bv)
51 // returns false if no redo possible
52 Undo * undo = bv->buffer()->redostack.pop();
56 Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
58 first = firstUndoParagraph(bv, undo->number_of_inset_id);
60 bv->buffer()->undostack.push(
61 createUndo(bv, undo->kind, first,
62 bv->buffer()->getParFromID(undo->number_of_behind_par)));
66 return textHandleUndo(bv, undo);
70 bool textHandleUndo(BufferView * bv, Undo * undo)
72 // returns false if no undo possible
76 bv->buffer()->getParFromID(undo->number_of_before_par);
78 bv->buffer()->getParFromID(undo->number_of_behind_par);
84 // if there's no before take the beginning
85 // of the document for redoing
87 LyXText * t = bv->text;
88 int num = undo->number_of_inset_id;
89 if (undo->number_of_inset_id >= 0) {
90 Inset * in = bv->buffer()->getInsetFromID(num);
92 t = in->getLyXText(bv);
97 t->setCursorIntern(bv, firstUndoParagraph(bv, num), 0);
100 // replace the paragraphs with the undo informations
102 Paragraph * tmppar3 = undo->par;
103 undo->par = 0; // otherwise the undo destructor would delete the paragraph
104 Paragraph * tmppar4 = tmppar3;
107 while (tmppar4->next())
108 tmppar4 = tmppar4->next();
109 } // get last undo par
111 // now remove the old text if there is any
112 if (before != behind || (!behind && !before)) {
114 tmppar5 = before->next();
116 tmppar5 = firstUndoParagraph(bv, undo->number_of_inset_id);
118 while (tmppar5 && tmppar5 != behind) {
120 tmppar5 = tmppar5->next();
121 // a memory optimization for edit: Only layout information
122 // is stored in the undo. So restore the text informations.
123 if (undo->kind == Undo::EDIT) {
124 tmppar2->setContentsFromPar(tmppar);
125 tmppar->clearContents();
126 tmppar2 = tmppar2->next();
131 // put the new stuff in the list if there is one
134 before->next(tmppar3);
136 bv->text->ownerParagraph(tmppar3->id(), tmppar3);
137 tmppar3->previous(before);
139 // Do we really enter here ??? (Jug)
141 bv->text->ownerParagraph(behind);
144 tmppar4->next(behind);
146 behind->previous(tmppar4);
150 // Set the cursor for redoing
152 bv->text->setCursorIntern(bv, before, 0);
155 // calculate the endpar for redoing the paragraphs.
157 endpar = behind->next();
161 tmppar = bv->buffer()->getParFromID(undo->number_of_cursor_par);
162 UpdatableInset* it = static_cast<UpdatableInset*>(tmppar3->InInset());
164 it->getLyXText(bv)->redoParagraphs(bv, it->getLyXText(bv)->cursor,
167 it->getLyXText(bv)->setCursorIntern(bv, tmppar, undo->cursor_pos);
168 it->getLyXText(bv)->updateCounters(bv, it->getLyXText(bv)->cursor.row());
170 #ifdef THIS_DOES_NOT_WORK
171 // we need this anyway as also if the undo was inside an inset
172 // we have to redo the paragraph breaking
173 bv->text->redoParagraphs(bv, bv->text->cursor,
174 bv->text->cursor.par());
177 bv->text->redoParagraphs(bv, bv->text->cursor, endpar);
179 bv->text->setCursorIntern(bv, tmppar, undo->cursor_pos);
180 bv->text->updateCounters(bv, bv->text->cursor.row());
187 bv->text->status(bv, LyXText::NEED_MORE_REFRESH);
194 // makes sure the next operation will be stored
195 undo_finished = true;
201 // this is dangerous and for internal use only
208 // this is dangerous and for internal use only
213 void setUndo(BufferView * bv, Undo::undo_kind kind,
214 Paragraph const * first, Paragraph const * behind)
217 bv->buffer()->undostack.push(createUndo(bv, kind, first, behind));
218 bv->buffer()->redostack.clear();
222 void setRedo(BufferView * bv, Undo::undo_kind kind,
223 Paragraph const * first, Paragraph const * behind)
225 bv->buffer()->redostack.push(createUndo(bv, kind, first, behind));
229 Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
230 Paragraph const * first, Paragraph const * behind)
234 int before_number = -1;
235 int behind_number = -1;
238 if (first->previous())
239 before_number = first->previous()->id();
241 behind_number = behind->id();
242 if (first->InInset())
243 inset_id = first->InInset()->id();
245 // Undo::EDIT and Undo::FINISH are
246 // always finished. (no overlapping there)
247 // overlapping only with insert and delete inside one paragraph:
248 // Nobody wants all removed character
249 // appear one by one when undoing.
250 // EDIT is special since only layout information, not the
251 // contents of a paragaph are stored.
252 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
253 // check wether storing is needed
254 if (!bv->buffer()->undostack.empty() &&
255 bv->buffer()->undostack.top()->kind == kind &&
256 bv->buffer()->undostack.top()->number_of_before_par == before_number &&
257 bv->buffer()->undostack.top()->number_of_behind_par == behind_number ){
265 Paragraph * start = const_cast<Paragraph *>(first);
270 start = const_cast<Paragraph*>(before->next());
272 start = firstUndoParagraph(bv);
275 end = const_cast<Paragraph*>(behind->previous());
281 if (start && end && (start != end->next()) &&
282 ((before_number != behind_number) ||
283 ((before_number < 0) && (behind_number < 0)))) {
284 Paragraph * tmppar = start;
285 Paragraph * tmppar2 = new Paragraph(*tmppar, true);
286 tmppar2->id(tmppar->id());
288 // a memory optimization: Just store the layout information
290 if (kind == Undo::EDIT) {
291 tmppar2->clearContents();
296 while (tmppar != end && tmppar->next()) {
297 tmppar = tmppar->next();
298 tmppar2->next(new Paragraph(*tmppar));
299 tmppar2->next()->id(tmppar->id());
300 // a memory optimization: Just store the layout
301 // information when only edit
302 if (kind == Undo::EDIT) {
303 tmppar2->clearContents();
305 tmppar2->next()->previous(tmppar2);
306 tmppar2 = tmppar2->next();
310 undopar = 0; // nothing to replace (undo of delete maybe)
312 int cursor_par = undoCursor(bv).par()->id();
313 int cursor_pos = undoCursor(bv).pos();
315 Undo * undo = new Undo(kind, inset_id,
316 before_number, behind_number,
317 cursor_par, cursor_pos, undopar);
319 undo_finished = false;
324 void setCursorParUndo(BufferView * bv)
326 setUndo(bv, Undo::FINISH,
327 bv->text->cursor.par(),
328 bv->text->cursor.par()->next());
331 Paragraph * firstUndoParagraph(BufferView * bv, int inset_id)
333 Inset * inset = bv->buffer()->getInsetFromID(inset_id);
335 Paragraph * result = inset->firstParagraph();
339 return bv->text->ownerParagraph();
342 LyXCursor const & undoCursor(BufferView * bv)
344 if (bv->theLockingInset())
345 return bv->theLockingInset()->cursor(bv);
346 return bv->text->cursor;