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.
22 #include "BufferView.h"
23 #include "iterators.h"
25 #include "paragraph.h"
27 using lyx::paroffset_type;
32 /// Whether actions are not added to the undo stacks.
35 /// The flag used by finishUndo().
39 std::ostream & operator<<(std::ostream & os, Undo const & undo)
41 return os << " text: " << undo.text
42 << " index: " << undo.index
43 << " first: " << undo.first_par
44 << " from end: " << undo.end_par
45 << " cursor: " << undo.cursor_par
46 << "/" << undo.cursor_pos;
50 // translates LyXText pointer into offset count from document begin
51 ParIterator text2pit(Buffer & buf, LyXText * text, int & tcount)
54 ParIterator pit = buf.par_iterator_begin();
55 ParIterator end = buf.par_iterator_end();
57 for ( ; pit != end; ++pit, ++tcount)
58 if (pit.text(buf) == text)
60 lyxerr << "undo: should not happen" << std::endl;
65 // translates offset from buffer begin to ParIterator
66 ParIterator num2pit(Buffer & buf, int num)
68 ParIterator pit = buf.par_iterator_begin();
69 ParIterator end = buf.par_iterator_end();
71 for ( ; num && pit != end; ++pit, --num)
77 // don't crash early...
78 lyxerr << "undo: num2pit: num: " << num << std::endl;
80 return buf.par_iterator_begin();
84 void recordUndo(Undo::undo_kind kind,
85 LCursor & cur, paroffset_type first_par, paroffset_type last_par,
86 limited_stack<Undo> & stack)
89 DocumentIterator it = bufferBegin(cur.bv());
90 DocumentIterator et = bufferEnd();
92 for ( ; it != et; it.forwardPos(), ++count)
93 if (it.top() == cur.top())
94 lyxerr << "### found at " << count << std::endl;
97 if (first_par > last_par) {
98 paroffset_type t = first_par;
103 Buffer & buf = *cur.bv().buffer();
104 int const end_par = cur.lastpar() + 1 - last_par;
106 // Undo::ATOMIC are always recorded (no overlapping there).
107 // overlapping only with insert and delete inside one paragraph:
108 // nobody wants all removed character appear one by one when undoing.
109 if (!undo_finished && kind != Undo::ATOMIC) {
110 // Check whether storing is needed.
111 if (!buf.undostack().empty()
112 && buf.undostack().top().kind == kind
113 && buf.undostack().top().first_par == first_par
114 && buf.undostack().top().end_par == end_par) {
115 // No additonal undo recording needed -
116 // effectively, we combine undo recordings to one.
121 // push and fill the Undo entry
122 if (cur.inTexted()) {
124 LyXText * text = cur.text();
126 ParIterator pit = text2pit(buf, text, textnum);
127 Undo & undo = stack.top();
130 undo.index = pit.index();
131 undo.first_par = first_par;
132 undo.end_par = end_par;
133 undo.cursor_par = cur.par();
134 undo.cursor_pos = cur.pos();
136 //lyxerr << "undo record: " << stack.top() << std::endl;
138 // record the relevant paragraphs
139 ParagraphList & plist = text->paragraphs();
140 ParagraphList::iterator first = plist.begin();
141 advance(first, first_par);
142 ParagraphList::iterator last = plist.begin();
143 advance(last, last_par);
145 for (ParagraphList::iterator it = first; it != last; ++it)
146 undo.pars.push_back(*it);
147 undo.pars.push_back(*last);
149 BOOST_ASSERT(false); // not in mathed (yet)
151 Undo & undo = stack.top();
155 // and make sure that next time, we should be combining if possible
156 undo_finished = false;
160 // returns false if no undo possible
161 bool performUndoOrRedo(BufferView & bv, Undo const & undo)
163 Buffer & buf = *bv.buffer();
164 lyxerr << "undo, performing: " << undo << std::endl;
165 ParIterator pit = num2pit(buf, undo.text);
166 LyXText * text = pit.text(buf);
167 ParagraphList & plist = text->paragraphs();
169 // remove new stuff between first and last
171 ParagraphList::iterator first = plist.begin();
172 advance(first, undo.first_par);
173 ParagraphList::iterator last = plist.begin();
174 advance(last, plist.size() - undo.end_par);
175 plist.erase(first, ++last);
178 // re-insert old stuff instead
180 plist.assign(undo.pars.begin(), undo.pars.end());
182 ParagraphList::iterator first = plist.begin();
183 advance(first, undo.first_par);
184 plist.insert(first, undo.pars.begin(), undo.pars.end());
188 lyxerr << "undo, text: " << undo.text
189 << " inset: " << pit.inset()
190 << " index: " << undo.index
191 << " par: " << undo.cursor_par
192 << " pos: " << undo.cursor_pos
195 text->updateCounters();
197 // rebreak the entire lyxtext
199 text->redoParagraphs(buf.paragraphs().begin(), buf.paragraphs().end());
200 bv.cursor().resetAnchor();
202 ParIterator pit2 = num2pit(buf, undo.text);
203 advance(pit2, undo.cursor_par);
204 bv.setCursor(pit2, undo.cursor_pos);
211 // returns false if no undo possible
212 bool textUndoOrRedo(BufferView & bv,
213 limited_stack<Undo> & stack, limited_stack<Undo> & otherstack)
215 Buffer & buf = *bv.buffer();
222 Undo undo = stack.top();
227 otherstack.push(undo);
228 otherstack.top().pars.clear();
229 ParIterator pit = num2pit(buf, undo.text);
230 ParagraphList & plist = pit.plist();
231 if (undo.first_par + undo.end_par <= int(plist.size())) {
232 ParagraphList::iterator first = plist.begin();
233 advance(first, undo.first_par);
234 ParagraphList::iterator last = plist.begin();
235 advance(last, plist.size() - undo.end_par + 1);
236 otherstack.top().pars.insert(otherstack.top().pars.begin(), first, last);
238 otherstack.top().cursor_pos = bv.cursor().pos();
239 otherstack.top().cursor_par = bv.cursor().par();
240 lyxerr << " undo other: " << otherstack.top() << std::endl;
244 bool const ret = performUndoOrRedo(bv, undo);
254 // this is dangerous and for internal use only
261 // this is dangerous and for internal use only
268 // makes sure the next operation will be stored
269 undo_finished = true;
273 bool textUndo(BufferView & bv)
275 return textUndoOrRedo(bv, bv.buffer()->undostack(),
276 bv.buffer()->redostack());
280 bool textRedo(BufferView & bv)
282 return textUndoOrRedo(bv, bv.buffer()->redostack(),
283 bv.buffer()->undostack());
287 void recordUndo(Undo::undo_kind kind,
288 LCursor & cur, paroffset_type first, paroffset_type last)
292 Buffer * buf = cur.bv().buffer();
293 recordUndo(kind, cur, first, last, buf->undostack());
294 buf->redostack().clear();
298 void recordUndo(LCursor & cur, Undo::undo_kind kind)
300 recordUndo(kind, cur, cur.par(), cur.par());
304 void recordUndoSelection(LCursor & cur, Undo::undo_kind kind)
306 recordUndo(kind, cur, cur.selBegin().par(), cur.selEnd().par());
310 void recordUndo(LCursor & cur, Undo::undo_kind kind, paroffset_type from)
312 recordUndo(kind, cur, cur.par(), from);
316 void recordUndo(LCursor & cur, Undo::undo_kind kind,
317 paroffset_type from, paroffset_type to)
319 recordUndo(kind, cur, from, to);
323 void recordUndoFullDocument(LCursor &)
325 //recordUndo(Undo::ATOMIC,
326 // cur, 0, cur.bv().text()->paragraphs().size() - 1);