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