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