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