2 * This file is part of LyX, the document processor.
3 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * Full author contact details are available in file CREDITS.
14 #include "iterators.h"
16 #include <boost/next_prior.hpp>
17 #include <boost/optional.hpp>
19 // it's conceptionally a stack, but undo needs random access...
23 using boost::optional;
33 ParPosition(ParagraphList::iterator p, ParagraphList const & pl);
35 ParagraphList::iterator pit;
37 ParagraphList const * plist;
39 optional<InsetList::iterator> it;
45 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
48 if (p != const_cast<ParagraphList&>(pl).end()) {
49 it.reset(p->insetlist.begin());
54 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
56 return pos1.pit == pos2.pit;
60 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
62 return !(pos1 == pos2);
70 struct ParIterator::Pimpl {
71 typedef vector<ParPosition> PosHolder;
75 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
78 pimpl_->positions.push_back(ParPosition(pit, pl));
82 ParIterator::~ParIterator()
86 ParIterator::ParIterator(ParIterator const & pi)
87 : pimpl_(new Pimpl(*pi.pimpl_))
91 void ParIterator::operator=(ParIterator const & pi)
94 pimpl_.swap(tmp.pimpl_);
98 ParIterator & ParIterator::operator++()
100 while (!pimpl_->positions.empty()) {
101 ParPosition & p = pimpl_->positions.back();
103 // Does the current inset contain more "cells" ?
106 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
107 if (plist && !plist->empty()) {
108 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
113 // The following line is needed because the value of
114 // p.it may be invalid if inset was added/removed to
115 // the paragraph pointed by the iterator
116 p.it.reset(p.pit->insetlist.begin());
118 // Try to find the next inset that contains paragraphs
119 InsetList::iterator end = p.pit->insetlist.end();
120 for (; *p.it != end; ++(*p.it)) {
121 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
122 if (plist && !plist->empty()) {
124 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
129 // Try to go to the next paragarph
130 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
131 || pimpl_->positions.size() == 1) {
139 // Drop end and move up in the stack.
140 pimpl_->positions.pop_back();
146 Paragraph & ParIterator::operator*() const
148 return *pimpl_->positions.back().pit;
152 ParagraphList::iterator ParIterator::pit() const
154 return pimpl_->positions.back().pit;
158 ParagraphList::iterator ParIterator::operator->() const
160 return pimpl_->positions.back().pit;
164 ParagraphList::iterator ParIterator::outerPar() const
166 return pimpl_->positions[0].pit;
170 size_t ParIterator::size() const
172 return pimpl_->positions.size();
176 ParagraphList & ParIterator::plist() const
178 return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
182 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
184 return iter1.pimpl_->positions == iter2.pimpl_->positions;
188 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
190 return !(iter1 == iter2);
199 struct ParConstIterator::Pimpl {
200 typedef vector<ParPosition> PosHolder;
205 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
206 ParagraphList const & pl)
209 pimpl_->positions.push_back(ParPosition(pit, pl));
213 ParConstIterator::~ParConstIterator()
217 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
218 : pimpl_(new Pimpl(*pi.pimpl_))
222 ParConstIterator & ParConstIterator::operator++()
224 while (!pimpl_->positions.empty()) {
225 ParPosition & p = pimpl_->positions.back();
227 // Does the current inset contain more "cells" ?
230 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
231 if (plist && !plist->empty()) {
232 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
237 // The following line is needed because the value of
238 // p.it may be invalid if inset was added/removed to
239 // the paragraph pointed by the iterator
240 p.it.reset(p.pit->insetlist.begin());
242 // Try to find the next inset that contains paragraphs
243 InsetList::iterator end = p.pit->insetlist.end();
244 for (; *p.it != end; ++(*p.it)) {
245 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
246 if (plist && !plist->empty()) {
248 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
253 // Try to go to the next paragarph
254 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
255 || pimpl_->positions.size() == 1) {
263 // Drop end and move up in the stack.
264 pimpl_->positions.pop_back();
271 Paragraph const & ParConstIterator::operator*() const
273 return *pimpl_->positions.back().pit;
277 ParagraphList::const_iterator ParConstIterator::pit() const
279 return pimpl_->positions.back().pit;
283 ParagraphList::const_iterator ParConstIterator::operator->() const
285 return pimpl_->positions.back().pit;
289 ParagraphList const & ParConstIterator::plist() const
291 return *pimpl_->positions.back().plist;
295 size_t ParConstIterator::size() const
297 return pimpl_->positions.size();
301 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
303 return iter1.pimpl_->positions == iter2.pimpl_->positions;
307 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
309 return !(iter1 == iter2);