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 bool labelsUpdateNeeded = false;
168 DocIterator dit = undo.cell.asDocIterator(&buf->inset());
169 if (undo.isFullBuffer) {
170 BOOST_ASSERT(undo.pars);
171 // This is a full document
172 otherstack.top().bparams = buf->params();
173 buf->params() = undo.bparams;
174 std::swap(buf->paragraphs(), *undo.pars);
177 } else if (dit.inMathed()) {
178 // We stored the full cell here as there is not much to be
179 // gained by storing just 'a few' paragraphs (most if not
180 // all math inset cells have just one paragraph!)
181 //lyxerr << "undo.array: " << *undo.array <<endl;
182 BOOST_ASSERT(undo.array);
183 dit.cell().swap(*undo.array);
187 // Some finer machinery is needed here.
188 Text * text = dit.text();
190 BOOST_ASSERT(undo.pars);
191 ParagraphList & plist = text->paragraphs();
193 // remove new stuff between first and last
194 ParagraphList::iterator first = plist.begin();
195 advance(first, undo.from);
196 ParagraphList::iterator last = plist.begin();
197 advance(last, plist.size() - undo.end);
198 plist.erase(first, last);
200 // re-insert old stuff instead
201 first = plist.begin();
202 advance(first, undo.from);
204 // this ugly stuff is needed until we get rid of the
205 // inset_owner backpointer
206 ParagraphList::iterator pit = undo.pars->begin();
207 ParagraphList::iterator const end = undo.pars->end();
208 for (; pit != end; ++pit)
209 pit->setInsetOwner(dit.realInset());
210 plist.insert(first, undo.pars->begin(), undo.pars->end());
213 labelsUpdateNeeded = true;
215 BOOST_ASSERT(undo.pars == 0);
216 BOOST_ASSERT(undo.array == 0);
219 Cursor & cur = bv.cursor();
220 cur.setCursor(undo.cursor.asDocIterator(&buf->inset()));
221 cur.selection() = false;
225 if (labelsUpdateNeeded)
236 // Make sure the next operation will be stored.
237 undo_finished = true;
241 bool textUndo(BufferView & bv)
243 return textUndoOrRedo(bv, bv.buffer()->undostack(),
244 bv.buffer()->redostack());
248 bool textRedo(BufferView & bv)
250 return textUndoOrRedo(bv, bv.buffer()->redostack(),
251 bv.buffer()->undostack());
255 void recordUndo(Undo::undo_kind kind,
256 Cursor & cur, pit_type first, pit_type last)
258 Buffer * buf = cur.bv().buffer();
259 recordUndo(kind, cur, first, last, buf->undostack());
260 buf->redostack().clear();
261 //lyxerr << "undostack:\n";
262 //for (size_t i = 0, n = buf->undostack().size(); i != n && i < 6; ++i)
263 // lyxerr << " " << i << ": " << buf->undostack()[i] << std::endl;
267 void recordUndo(Cursor & cur, Undo::undo_kind kind)
269 recordUndo(kind, cur, cur.pit(), cur.pit());
273 void recordUndoInset(Cursor & cur, Undo::undo_kind kind)
277 Buffer * buf = cur.bv().buffer();
278 doRecordUndo(kind, c, c.pit(), c.pit(), cur,
279 buf->params(), false, buf->undostack());
283 void recordUndoSelection(Cursor & cur, Undo::undo_kind kind)
285 recordUndo(kind, cur, cur.selBegin().pit(), cur.selEnd().pit());
289 void recordUndo(Cursor & cur, Undo::undo_kind kind, pit_type from)
291 recordUndo(kind, cur, cur.pit(), from);
295 void recordUndo(Cursor & cur, Undo::undo_kind kind,
296 pit_type from, pit_type to)
298 recordUndo(kind, cur, from, to);
302 void recordUndoFullDocument(BufferView * bv)
304 Buffer * buf = bv->buffer();
307 doc_iterator_begin(buf->inset()),
308 0, buf->paragraphs().size() - 1,
314 undo_finished = false;