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 #include "iterators.h"
26 //#define DELETE_UNUSED_PARAGRAPHS 1
27 #ifdef DELETE_UNUSED_PARAGRAPHS
34 /// the flag used by FinishUndo();
40 bool textUndo(BufferView * bv)
42 // returns false if no undo possible
43 Undo * undo = bv->buffer()->undostack.top();
44 bv->buffer()->undostack.pop();
48 Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
49 if (first && first->next())
50 first = first->next();
52 first = firstUndoParagraph(bv, undo->number_of_inset_id);
54 bv->buffer()->redostack.push(
55 createUndo(bv, undo->kind, first,
56 bv->buffer()->getParFromID(undo->number_of_behind_par)));
60 // now we can unlock the inset for saftey because the inset pointer could
61 // be changed during the undo-function. Anyway if needed we have to lock
62 // the right inset/position if this is requested.
64 bv->unlockInset(bv->theLockingInset());
65 bool ret = textHandleUndo(bv, undo);
71 bool textRedo(BufferView * bv)
73 // returns false if no redo possible
74 Undo * undo = bv->buffer()->redostack.top();
75 bv->buffer()->redostack.pop();
79 Paragraph * first = bv->buffer()->getParFromID(undo->number_of_before_par);
80 if (first && first->next())
81 first = first->next();
83 first = firstUndoParagraph(bv, undo->number_of_inset_id);
85 bv->buffer()->undostack.push(
86 createUndo(bv, undo->kind, first,
87 bv->buffer()->getParFromID(undo->number_of_behind_par)));
91 // now we can unlock the inset for saftey because the inset pointer could
92 // be changed during the undo-function. Anyway if needed we have to lock
93 // the right inset/position if this is requested.
95 bv->unlockInset(bv->theLockingInset());
96 bool ret = textHandleUndo(bv, undo);
102 bool textHandleUndo(BufferView * bv, Undo * undo)
104 // returns false if no undo possible
108 bv->buffer()->getParFromID(undo->number_of_before_par);
110 bv->buffer()->getParFromID(undo->number_of_behind_par);
115 // if there's no before take the beginning
116 // of the document for redoing
118 LyXText * t = bv->text;
119 int num = undo->number_of_inset_id;
120 if (undo->number_of_inset_id >= 0) {
121 Inset * in = bv->buffer()->getInsetFromID(num);
123 t = in->getLyXText(bv);
128 t->setCursorIntern(bv, firstUndoParagraph(bv, num), 0);
131 // replace the paragraphs with the undo informations
133 Paragraph * tmppar3 = undo->par;
134 undo->par = 0; /* otherwise the undo destructor would
135 delete the paragraph */
137 // get last undo par and set the right(new) inset-owner of the
138 // paragraph if there is any. This is not needed if we don't have
139 // a paragraph before because then in is automatically done in the
140 // function which assigns the first paragraph to an InsetText. (Jug)
141 Paragraph * tmppar4 = tmppar3;
145 in = before->inInset();
146 tmppar4->setInsetOwner(in);
147 while (tmppar4->next()) {
148 tmppar4 = tmppar4->next();
149 tmppar4->setInsetOwner(in);
153 // now remove the old text if there is any
154 #ifdef DELETE_UNUSED_PARAGRAPHS
155 vector<Paragraph *> vvpar;
157 if (before != behind || (!behind && !before)) {
159 tmppar5 = before->next();
161 tmppar5 = firstUndoParagraph(bv, undo->number_of_inset_id);
163 while (tmppar5 && tmppar5 != behind) {
164 #ifdef DELETE_UNUSED_PARAGRAPHS
165 vvpar.push_back(tmppar5);
168 tmppar5 = tmppar5->next();
169 // a memory optimization for edit:
170 // Only layout information
171 // is stored in the undo. So restore
172 // the text informations.
173 if (undo->kind == Undo::EDIT) {
174 tmppar2->setContentsFromPar(tmppar);
175 #ifndef DELETE_UNUSED_PARAGRAPHS
176 tmppar->clearContents();
178 tmppar2 = tmppar2->next();
183 // put the new stuff in the list if there is one
186 before->next(tmppar3);
188 bv->text->ownerParagraph(tmppar3->id(),
191 tmppar3->previous(before);
193 // Do we really enter here ??? (Jug)
194 if (!before && behind) {
195 bv->text->ownerParagraph(behind);
200 tmppar4->next(behind);
202 behind->previous(tmppar4);
206 // Set the cursor for redoing
208 Inset * it = before->inInset();
210 it->getLyXText(bv)->setCursorIntern(bv, before, 0);
212 bv->text->setCursorIntern(bv, before, 0);
215 Paragraph * endpar = 0;
216 // calculate the endpar for redoing the paragraphs.
218 endpar = behind->next();
220 tmppar = bv->buffer()->getParFromID(undo->number_of_cursor_par);
221 UpdatableInset* it = 0;
223 it = static_cast<UpdatableInset*>(tmppar3->inInset());
225 it->getLyXText(bv)->redoParagraphs(bv,
226 it->getLyXText(bv)->cursor,
229 it->update(bv, font, false);
230 // we now would have to rebreak the whole paragraph the
231 // undo-par was in. How we do it here is not really true.
232 // We would have to save this information in the undo-struct
233 // and then we could do the right rebreak. Here we only
234 // handle the case where this was in the actual paragraph,
235 // which not always is true.
236 bv->text->redoParagraphs(bv, bv->text->cursor,
237 bv->text->cursor.par());
239 it = static_cast<UpdatableInset*>(tmppar->inInset());
243 t = it->getLyXText(bv);
247 t->setCursorIntern(bv, tmppar, undo->cursor_pos);
248 t->updateCounters(bv, t->cursor.row());
250 bv->text->setCursorIntern(bv, bv->text->cursor.par(),
251 bv->text->cursor.pos());
253 bv->text->redoParagraphs(bv, bv->text->cursor, endpar);
256 Inset * it = tmppar->inInset();
259 t = it->getLyXText(bv);
263 t->setCursorIntern(bv, tmppar, undo->cursor_pos);
264 t->updateCounters(bv, t->cursor.row());
269 #ifdef DELETE_UNUSED_PARAGRAPHS
270 // And here it's save enough to delete all removed paragraphs
271 vector<Paragraph *>::iterator pit = vvpar.begin();
272 if (pit != vvpar.end()) {
274 for(;pit != vvpar.end(); ++pit) {
275 lyxerr << *pit << " ";
278 lyxerr << endl << "PARS:";
279 ParIterator end = bv->buffer()->par_iterator_end();
280 ParIterator it = bv->buffer()->par_iterator_begin();
281 for (; it != end; ++it)
282 lyxerr << *it << " ";
288 bv->text->status(bv, LyXText::NEED_MORE_REFRESH);
295 // makes sure the next operation will be stored
296 undo_finished = true;
302 // this is dangerous and for internal use only
309 // this is dangerous and for internal use only
314 void setUndo(BufferView * bv, Undo::undo_kind kind,
315 Paragraph const * first, Paragraph const * behind)
318 bv->buffer()->undostack.push(createUndo(bv, kind, first, behind));
319 bv->buffer()->redostack.clear();
324 void setRedo(BufferView * bv, Undo::undo_kind kind,
325 Paragraph const * first, Paragraph const * behind)
327 bv->buffer()->redostack.push(createUndo(bv, kind, first, behind));
331 Undo * createUndo(BufferView * bv, Undo::undo_kind kind,
332 Paragraph const * first, Paragraph const * behind)
336 int before_number = -1;
337 int behind_number = -1;
340 if (first->previous())
341 before_number = first->previous()->id();
343 behind_number = behind->id();
344 if (first->inInset())
345 inset_id = first->inInset()->id();
347 // Undo::EDIT and Undo::FINISH are
348 // always finished. (no overlapping there)
349 // overlapping only with insert and delete inside one paragraph:
350 // Nobody wants all removed character
351 // appear one by one when undoing.
352 // EDIT is special since only layout information, not the
353 // contents of a paragaph are stored.
354 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)) {
355 // check wether storing is needed
356 if (!bv->buffer()->undostack.empty() &&
357 bv->buffer()->undostack.top()->kind == kind &&
358 bv->buffer()->undostack.top()->number_of_before_par == before_number &&
359 bv->buffer()->undostack.top()->number_of_behind_par == behind_number) {
367 Paragraph * start = const_cast<Paragraph *>(first);
371 end = const_cast<Paragraph*>(behind->previous());
377 if (start && end && (start != end->next()) &&
378 ((before_number != behind_number) ||
379 ((before_number < 0) && (behind_number < 0))))
381 Paragraph * tmppar = start;
382 Paragraph * tmppar2 = new Paragraph(*tmppar, true);
384 // a memory optimization: Just store the layout information
386 if (kind == Undo::EDIT) {
387 tmppar2->clearContents();
392 while (tmppar != end && tmppar->next()) {
393 tmppar = tmppar->next();
395 tmppar2->next(new Paragraph(*tmppar, true));
397 Paragraph * ptmp = new Paragraph(*tmppar, true);
400 // a memory optimization: Just store the layout
401 // information when only edit
402 if (kind == Undo::EDIT) {
403 tmppar2->clearContents();
405 tmppar2->next()->previous(tmppar2);
407 tmppar2 = tmppar2->next();
411 undopar = 0; // nothing to replace (undo of delete maybe)
413 int cursor_par = undoCursor(bv).par()->id();
414 int cursor_pos = undoCursor(bv).pos();
416 Undo * undo = new Undo(kind, inset_id,
417 before_number, behind_number,
418 cursor_par, cursor_pos, undopar);
420 undo_finished = false;
425 void setCursorParUndo(BufferView * bv)
427 setUndo(bv, Undo::FINISH, bv->text->cursor.par(),
428 bv->text->cursor.par()->next());
432 Paragraph * firstUndoParagraph(BufferView * bv, int inset_id)
434 Inset * inset = bv->buffer()->getInsetFromID(inset_id);
436 Paragraph * result = inset->getFirstParagraph(0);
440 return bv->text->ownerParagraph();
444 LyXCursor const & undoCursor(BufferView * bv)
446 if (bv->theLockingInset())
447 return bv->theLockingInset()->cursor(bv);
448 return bv->text->cursor;