3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup
7 * \author Lars Gullik Bjønnes
10 * \author Jürgen Vigna
12 * Full author contact details are available in file CREDITS.
20 #include "buffer_funcs.h"
23 #include "BufferView.h"
25 #include "Paragraph.h"
26 #include "ParagraphList.h"
28 #include "mathed/MathSupport.h"
29 #include "mathed/MathData.h"
31 #include "insets/Inset.h"
44 /// The flag used by finishUndo().
48 std::ostream & operator<<(std::ostream & os, Undo const & undo)
50 return os << " from: " << undo.from << " end: " << undo.end
51 << " cell:\n" << undo.cell
52 << " cursor:\n" << undo.cursor;
56 bool samePar(StableDocIterator const & i1, StableDocIterator const & i2)
58 StableDocIterator tmpi2 = i2;
59 tmpi2.pos() = i1.pos();
64 void doRecordUndo(Undo::undo_kind kind,
65 DocIterator const & cell,
66 pit_type first_pit, pit_type last_pit,
67 DocIterator const & cur,
68 BufferParams const & bparams,
70 limited_stack<Undo> & stack)
72 if (first_pit > last_pit)
73 std::swap(first_pit, last_pit);
74 // create the position information of the Undo entry
81 undo.bparams = bparams ;
82 undo.isFullBuffer = isFullBuffer;
83 //lyxerr << "recordUndo: cur: " << cur << endl;
84 //lyxerr << "recordUndo: pos: " << cur.pos() << endl;
85 //lyxerr << "recordUndo: cell: " << cell << endl;
86 undo.from = first_pit;
87 undo.end = cell.lastpit() - last_pit;
89 // Undo::ATOMIC are always recorded (no overlapping there).
90 // As nobody wants all removed character appear one by one when undoing,
91 // we want combine 'similar' non-ATOMIC undo recordings to one.
93 && kind != Undo::ATOMIC
95 && samePar(stack.top().cell, undo.cell)
96 && stack.top().kind == undo.kind
97 && stack.top().from == undo.from
98 && stack.top().end == undo.end)
101 // fill in the real data to be saved
102 if (cell.inMathed()) {
103 // simply use the whole cell
104 undo.array = new MathData(cell.cell());
106 // some more effort needed here as 'the whole cell' of the
107 // main Text _is_ the whole document.
108 // record the relevant paragraphs
109 Text const * text = cell.text();
111 ParagraphList const & plist = text->paragraphs();
112 ParagraphList::const_iterator first = plist.begin();
113 advance(first, first_pit);
114 ParagraphList::const_iterator last = plist.begin();
115 advance(last, last_pit + 1);
116 undo.pars = new ParagraphList(first, last);
119 // push the undo entry to undo stack
121 //lyxerr << "undo record: " << stack.top() << std::endl;
123 // next time we'll try again to combine entries if possible
124 undo_finished = false;
128 void recordUndo(Undo::undo_kind kind,
129 Cursor & cur, pit_type first_pit, pit_type last_pit,
130 limited_stack<Undo> & stack)
132 BOOST_ASSERT(first_pit <= cur.lastpit());
133 BOOST_ASSERT(last_pit <= cur.lastpit());
135 doRecordUndo(kind, cur, first_pit, last_pit, cur,
136 cur.bv().buffer()->params(), false, stack);
141 // Returns false if no undo possible.
142 bool textUndoOrRedo(BufferView & bv,
143 limited_stack<Undo> & stack, limited_stack<Undo> & otherstack)
152 // Adjust undo stack and get hold of current undo data.
153 Undo undo = stack.top();
156 // We will store in otherstack the part of the document under 'undo'
157 Buffer * buf = bv.buffer();
158 DocIterator cell_dit = undo.cell.asDocIterator(&buf->inset());
160 doRecordUndo(Undo::ATOMIC, cell_dit,
161 undo.from, cell_dit.lastpit() - undo.end, bv.cursor(),
162 undo.bparams, undo.isFullBuffer,
165 // This does the actual undo/redo.
166 //lyxerr << "undo, performing: " << undo << std::endl;
167 DocIterator dit = undo.cell.asDocIterator(&buf->inset());
168 if (undo.isFullBuffer) {
169 BOOST_ASSERT(undo.pars);
170 // This is a full document
171 otherstack.top().bparams = buf->params();
172 buf->params() = undo.bparams;
173 std::swap(buf->paragraphs(), *undo.pars);
176 } else if (dit.inMathed()) {
177 // We stored the full cell here as there is not much to be
178 // gained by storing just 'a few' paragraphs (most if not
179 // all math inset cells have just one paragraph!)
180 //lyxerr << "undo.array: " << *undo.array <<endl;
181 BOOST_ASSERT(undo.array);
182 dit.cell().swap(*undo.array);
186 // Some finer machinery is needed here.
187 Text * text = dit.text();
189 BOOST_ASSERT(undo.pars);
190 ParagraphList & plist = text->paragraphs();
192 // remove new stuff between first and last
193 ParagraphList::iterator first = plist.begin();
194 advance(first, undo.from);
195 ParagraphList::iterator last = plist.begin();
196 advance(last, plist.size() - undo.end);
197 plist.erase(first, last);
199 // re-insert old stuff instead
200 first = plist.begin();
201 advance(first, undo.from);
203 // this ugly stuff is needed until we get rid of the
204 // inset_owner backpointer
205 ParagraphList::iterator pit = undo.pars->begin();
206 ParagraphList::iterator const end = undo.pars->end();
207 for (; pit != end; ++pit)
208 pit->setInsetOwner(dit.realInset());
209 plist.insert(first, undo.pars->begin(), undo.pars->end());
214 BOOST_ASSERT(undo.pars == 0);
215 BOOST_ASSERT(undo.array == 0);
218 Cursor & cur = bv.cursor();
219 cur.setCursor(undo.cursor.asDocIterator(&buf->inset()));
220 cur.selection() = false;
233 // Make sure the next operation will be stored.
234 undo_finished = true;
238 bool textUndo(BufferView & bv)
240 return textUndoOrRedo(bv, bv.buffer()->undostack(),
241 bv.buffer()->redostack());
245 bool textRedo(BufferView & bv)
247 return textUndoOrRedo(bv, bv.buffer()->redostack(),
248 bv.buffer()->undostack());
252 void recordUndo(Undo::undo_kind kind,
253 Cursor & cur, pit_type first, pit_type last)
255 Buffer * buf = cur.bv().buffer();
256 recordUndo(kind, cur, first, last, buf->undostack());
257 buf->redostack().clear();
258 //lyxerr << "undostack:\n";
259 //for (size_t i = 0, n = buf->undostack().size(); i != n && i < 6; ++i)
260 // lyxerr << " " << i << ": " << buf->undostack()[i] << std::endl;
264 void recordUndo(Cursor & cur, Undo::undo_kind kind)
266 recordUndo(kind, cur, cur.pit(), cur.pit());
270 void recordUndoInset(Cursor & cur, Undo::undo_kind kind)
274 Buffer * buf = cur.bv().buffer();
275 doRecordUndo(kind, c, c.pit(), c.pit(), cur,
276 buf->params(), false, buf->undostack());
280 void recordUndoSelection(Cursor & cur, Undo::undo_kind kind)
282 recordUndo(kind, cur, cur.selBegin().pit(), cur.selEnd().pit());
286 void recordUndo(Cursor & cur, Undo::undo_kind kind, pit_type from)
288 recordUndo(kind, cur, cur.pit(), from);
292 void recordUndo(Cursor & cur, Undo::undo_kind kind,
293 pit_type from, pit_type to)
295 recordUndo(kind, cur, from, to);
299 void recordUndoFullDocument(BufferView * bv)
301 Buffer * buf = bv->buffer();
304 doc_iterator_begin(buf->inset()),
305 0, buf->paragraphs().size() - 1,
311 undo_finished = false;