]> git.lyx.org Git - lyx.git/blob - src/iterators.C
fix undo crash
[lyx.git] / src / iterators.C
1 /* \file iterators.C
2  * This file is part of LyX, the document processor.
3  * Licence details can be found in the file COPYING.
4  *
5  * \author unknown
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11
12 #include <config.h>
13
14 #include "iterators.h"
15 #include "paragraph.h"
16 #include "PosIterator.h"
17 #include "cursor.h"
18 #include "buffer.h"
19 #include "BufferView.h"
20 #include "dispatchresult.h"
21
22 #include "insets/inset.h"
23 #include "insets/updatableinset.h"
24 #include "insets/insettext.h"
25
26 #include <boost/next_prior.hpp>
27
28 using boost::next;
29
30 ///
31 /// ParPosition
32 ///
33
34
35 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
36         : pit(p), plist(&pl)
37 {
38         if (p != const_cast<ParagraphList&>(pl).end()) {
39                 it.reset(p->insetlist.begin());
40         }
41 }
42
43
44 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
45 {
46         return pos1.pit == pos2.pit;
47 }
48
49
50 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
51 {
52         return !(pos1 == pos2);
53 }
54
55
56 ///
57 /// ParIterator
58 ///
59
60 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
61 {
62         positions_.push_back(ParPosition(pit, pl));
63 }
64
65
66 ParIterator::~ParIterator()
67 {}
68
69
70 ParIterator::ParIterator(ParIterator const & pi)
71         : positions_(pi.positions_)
72 {}
73
74
75 void ParIterator::operator=(ParIterator const & pi)
76 {
77         ParIterator tmp(pi);
78         swap(positions_ , tmp.positions_);
79 }
80
81
82 ParIterator & ParIterator::operator++()
83 {
84         while (!positions_.empty()) {
85                 ParPosition & p = positions_.back();
86
87                 // Does the current inset contain more "cells" ?
88                 if (p.index) {
89                         ++(*p.index);
90                         if (LyXText * text = (*p.it)->inset->getText(*p.index)) {
91                                 ParagraphList & plist = text->paragraphs();
92                                 if (!plist.empty()) {
93                                         positions_.push_back(ParPosition(plist.begin(), plist));
94                                         return *this;
95                                 }
96                         }
97                         ++(*p.it);
98                 } else {
99                         // The following line is needed because the value of
100                         // p.it may be invalid if inset was added/removed to
101                         // the paragraph pointed by the iterator
102                         p.it.reset(p.pit->insetlist.begin());
103                 }
104
105                 // Try to find the next inset that contains paragraphs
106                 InsetList::iterator end = p.pit->insetlist.end();
107                 for (; *p.it != end; ++(*p.it)) {
108                         if (LyXText * text = (*p.it)->inset->getText(0)) {
109                                 ParagraphList & plist = text->paragraphs();
110                                 if (!plist.empty()) {
111                                         p.index.reset(0);
112                                         positions_.push_back(ParPosition(plist.begin(), plist));
113                                         return *this;
114                                 }
115                         }
116                 }
117
118                 // Try to go to the next paragarph
119                 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
120                     || positions_.size() == 1) {
121                         ++p.pit;
122                         p.index.reset();
123                         p.it.reset();
124
125                         return *this;
126                 }
127
128                 // Drop end and move up in the stack.
129                 positions_.pop_back();
130         }
131         return *this;
132 }
133
134
135 LyXText * ParIterator::text(Buffer & buf) const
136 {
137         //lyxerr << "positions.size: " << positions.size() << std::endl;
138         if (positions_.size() <= 1)
139                 return &buf.text();
140
141         ParPosition const & pos = positions_[positions_.size() - 2];
142         return (*pos.it)->inset->getText(*pos.index);
143 }
144
145
146 InsetBase * ParIterator::inset() const
147 {
148         //lyxerr << "positions.size: " << positions.size() << std::endl;
149         if (positions_.size() <= 1)
150                 return 0;
151
152         ParPosition const & pos = positions_[positions_.size() - 2];
153         return (*pos.it)->inset;
154 }
155
156
157 int ParIterator::index() const
158 {
159         if (positions_.size() <= 1)
160                 return 0;
161
162         return *(positions_[positions_.size() - 2].index);
163 }
164
165
166 Paragraph & ParIterator::operator*() const
167 {
168         return *positions_.back().pit;
169 }
170
171
172 ParagraphList::iterator ParIterator::pit() const
173 {
174         return positions_.back().pit;
175 }
176
177
178 ParagraphList::iterator ParIterator::operator->() const
179 {
180         return positions_.back().pit;
181 }
182
183
184 ParagraphList::iterator ParIterator::outerPar() const
185 {
186         return positions_[0].pit;
187 }
188
189
190 size_t ParIterator::size() const
191 {
192         return positions_.size();
193 }
194
195
196 ParagraphList & ParIterator::plist() const
197 {
198         return *const_cast<ParagraphList*>(positions_.back().plist);
199 }
200
201
202 ParIterator::ParIterator(PosIterator const & pos)
203 {
204         int const size = pos.stack_.size();
205
206         for (int i = 0; i < size; ++i) {
207                 PosIteratorItem const & it = pos.stack_[i];
208                 ParPosition pp(it.pit, *it.pl);
209                 if (i < size - 1) {
210                         InsetBase * inset = it.pit->getInset(it.pos);
211                         BOOST_ASSERT(inset);
212                         InsetList::iterator beg = it.pit->insetlist.begin();
213                         InsetList::iterator end = it.pit->insetlist.end();
214                         for ( ; beg != end && beg->inset != inset; ++beg)
215                                 ;
216                         pp.it.reset(beg);
217                         pp.index.reset(it.index - 1);
218                 }
219                 positions_.push_back(pp);
220         }
221 }
222
223
224 void ParIterator::lockPath(BufferView * bv) const
225 {
226         LCursor & cur = bv->cursor();
227         cur.reset();
228         int const last = size() - 1;
229         for (int i = 0; i < last; ++i)
230                 (*positions_[i].it)->inset->edit(cur, true);
231         cur.resetAnchor();
232 }
233
234
235 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
236 {
237         return iter1.positions() == iter2.positions();
238 }
239
240
241 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
242 {
243         return !(iter1 == iter2);
244 }
245
246
247 ///
248 /// ParConstIterator
249 ///
250
251
252 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
253                                    ParagraphList const & pl)
254 {
255         positions_.push_back(ParPosition(pit, pl));
256 }
257
258
259 ParConstIterator::~ParConstIterator()
260 {}
261
262
263 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
264         : positions_(pi.positions_)
265 {}
266
267
268 ParConstIterator & ParConstIterator::operator++()
269 {
270         while (!positions_.empty()) {
271                 ParPosition & p = positions_.back();
272
273                 // Does the current inset contain more "cells" ?
274                 if (p.index) {
275                         ++(*p.index);
276                         if (LyXText * text = (*p.it)->inset->getText(*p.index)) {
277                                 ParagraphList & plist = text->paragraphs();
278                                 if (!plist.empty()) {
279                                         positions_.push_back(ParPosition(plist.begin(), plist));
280                                         return *this;
281                                 }
282                         }
283                         ++(*p.it);
284                 } else {
285                         // The following line is needed because the value of
286                         // p.it may be invalid if inset was added/removed to
287                         // the paragraph pointed by the iterator
288                         p.it.reset(p.pit->insetlist.begin());
289                 }
290
291                 // Try to find the next inset that contains paragraphs
292                 InsetList::iterator end = p.pit->insetlist.end();
293                 for (; *p.it != end; ++(*p.it)) {
294                         if (LyXText * text = (*p.it)->inset->getText(0)) {
295                                 ParagraphList & plist = text->paragraphs();
296                                 if (!plist.empty()) {
297                                         p.index.reset(0);
298                                         positions_.push_back(ParPosition(plist.begin(), plist));
299                                         return *this;
300                                 }
301                         }
302                 }
303
304                 // Try to go to the next paragarph
305                 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
306                     || positions_.size() == 1) {
307                         ++p.pit;
308                         p.index.reset();
309                         p.it.reset();
310
311                         return *this;
312                 }
313
314                 // Drop end and move up in the stack.
315                 positions_.pop_back();
316         }
317
318         return *this;
319 }
320
321
322 Paragraph const & ParConstIterator::operator*() const
323 {
324         return *positions_.back().pit;
325 }
326
327
328 ParagraphList::const_iterator ParConstIterator::pit() const
329 {
330         return positions_.back().pit;
331 }
332
333
334 ParagraphList::const_iterator ParConstIterator::operator->() const
335 {
336         return positions_.back().pit;
337 }
338
339
340 ParagraphList const & ParConstIterator::plist() const
341 {
342         return *positions_.back().plist;
343 }
344
345
346 size_t ParConstIterator::size() const
347 {
348         return positions_.size();
349 }
350
351
352 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
353 {
354         return iter1.positions() == iter2.positions();
355 }
356
357
358 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
359 {
360         return !(iter1 == iter2);
361 }