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"
15 #include "paragraph.h"
17 #include <boost/next_prior.hpp>
18 #include <boost/optional.hpp>
20 // it's conceptionally a stack, but undo needs random access...
25 using boost::optional;
35 ParPosition(ParagraphList::iterator p, ParagraphList const & pl);
37 ParagraphList::iterator pit;
39 ParagraphList const * plist;
41 optional<InsetList::iterator> it;
47 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
50 if (p != const_cast<ParagraphList&>(pl).end()) {
51 it.reset(p->insetlist.begin());
56 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
58 return pos1.pit == pos2.pit;
62 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
64 return !(pos1 == pos2);
72 struct ParIterator::Pimpl {
73 typedef vector<ParPosition> PosHolder;
77 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
80 pimpl_->positions.push_back(ParPosition(pit, pl));
84 ParIterator::~ParIterator()
88 ParIterator::ParIterator(ParIterator const & pi)
89 : pimpl_(new Pimpl(*pi.pimpl_))
93 void ParIterator::operator=(ParIterator const & pi)
96 pimpl_.swap(tmp.pimpl_);
100 ParIterator & ParIterator::operator++()
102 while (!pimpl_->positions.empty()) {
103 ParPosition & p = pimpl_->positions.back();
105 // Does the current inset contain more "cells" ?
108 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
109 if (plist && !plist->empty()) {
110 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
115 // The following line is needed because the value of
116 // p.it may be invalid if inset was added/removed to
117 // the paragraph pointed by the iterator
118 p.it.reset(p.pit->insetlist.begin());
120 // Try to find the next inset that contains paragraphs
121 InsetList::iterator end = p.pit->insetlist.end();
122 for (; *p.it != end; ++(*p.it)) {
123 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
124 if (plist && !plist->empty()) {
126 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
131 // Try to go to the next paragarph
132 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
133 || pimpl_->positions.size() == 1) {
141 // Drop end and move up in the stack.
142 pimpl_->positions.pop_back();
148 Paragraph & ParIterator::operator*() const
150 return *pimpl_->positions.back().pit;
154 ParagraphList::iterator ParIterator::pit() const
156 return pimpl_->positions.back().pit;
160 ParagraphList::iterator ParIterator::operator->() const
162 return pimpl_->positions.back().pit;
166 ParagraphList::iterator ParIterator::outerPar() const
168 return pimpl_->positions[0].pit;
172 size_t ParIterator::size() const
174 return pimpl_->positions.size();
178 ParagraphList & ParIterator::plist() const
180 return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
184 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
186 return iter1.pimpl_->positions == iter2.pimpl_->positions;
190 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
192 return !(iter1 == iter2);
201 struct ParConstIterator::Pimpl {
202 typedef vector<ParPosition> PosHolder;
207 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
208 ParagraphList const & pl)
211 pimpl_->positions.push_back(ParPosition(pit, pl));
215 ParConstIterator::~ParConstIterator()
219 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
220 : pimpl_(new Pimpl(*pi.pimpl_))
224 ParConstIterator & ParConstIterator::operator++()
226 while (!pimpl_->positions.empty()) {
227 ParPosition & p = pimpl_->positions.back();
229 // Does the current inset contain more "cells" ?
232 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
233 if (plist && !plist->empty()) {
234 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
239 // The following line is needed because the value of
240 // p.it may be invalid if inset was added/removed to
241 // the paragraph pointed by the iterator
242 p.it.reset(p.pit->insetlist.begin());
244 // Try to find the next inset that contains paragraphs
245 InsetList::iterator end = p.pit->insetlist.end();
246 for (; *p.it != end; ++(*p.it)) {
247 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
248 if (plist && !plist->empty()) {
250 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
255 // Try to go to the next paragarph
256 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
257 || pimpl_->positions.size() == 1) {
265 // Drop end and move up in the stack.
266 pimpl_->positions.pop_back();
273 Paragraph const & ParConstIterator::operator*() const
275 return *pimpl_->positions.back().pit;
279 ParagraphList::const_iterator ParConstIterator::pit() const
281 return pimpl_->positions.back().pit;
285 ParagraphList::const_iterator ParConstIterator::operator->() const
287 return pimpl_->positions.back().pit;
291 size_t ParConstIterator::size() const
293 return pimpl_->positions.size();
297 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
299 return iter1.pimpl_->positions == iter2.pimpl_->positions;
303 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
305 return !(iter1 == iter2);