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