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