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 "insets/inset.h"
19 #include <boost/next_prior.hpp>
20 #include <boost/optional.hpp>
22 // it's conceptionally a stack, but undo needs random access...
26 using boost::optional;
36 ParPosition(ParagraphList::iterator p, ParagraphList const & pl);
38 ParagraphList::iterator pit;
40 ParagraphList const * plist;
42 optional<InsetList::iterator> it;
48 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
51 if (p != const_cast<ParagraphList&>(pl).end()) {
52 it.reset(p->insetlist.begin());
57 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
59 return pos1.pit == pos2.pit;
63 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
65 return !(pos1 == pos2);
73 struct ParIterator::Pimpl {
74 typedef vector<ParPosition> PosHolder;
78 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
81 pimpl_->positions.push_back(ParPosition(pit, pl));
85 ParIterator::~ParIterator()
89 ParIterator::ParIterator(ParIterator const & pi)
90 : pimpl_(new Pimpl(*pi.pimpl_))
94 void ParIterator::operator=(ParIterator const & pi)
97 pimpl_.swap(tmp.pimpl_);
101 ParIterator & ParIterator::operator++()
103 while (!pimpl_->positions.empty()) {
104 ParPosition & p = pimpl_->positions.back();
106 // Does the current inset contain more "cells" ?
109 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
110 if (plist && !plist->empty()) {
111 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
116 // The following line is needed because the value of
117 // p.it may be invalid if inset was added/removed to
118 // the paragraph pointed by the iterator
119 p.it.reset(p.pit->insetlist.begin());
121 // Try to find the next inset that contains paragraphs
122 InsetList::iterator end = p.pit->insetlist.end();
123 for (; *p.it != end; ++(*p.it)) {
124 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
125 if (plist && !plist->empty()) {
127 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
132 // Try to go to the next paragarph
133 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
134 || pimpl_->positions.size() == 1) {
142 // Drop end and move up in the stack.
143 pimpl_->positions.pop_back();
149 Paragraph & ParIterator::operator*() const
151 return *pimpl_->positions.back().pit;
155 ParagraphList::iterator ParIterator::pit() const
157 return pimpl_->positions.back().pit;
161 ParagraphList::iterator ParIterator::operator->() const
163 return pimpl_->positions.back().pit;
167 ParagraphList::iterator ParIterator::outerPar() const
169 return pimpl_->positions[0].pit;
173 size_t ParIterator::size() const
175 return pimpl_->positions.size();
179 ParagraphList & ParIterator::plist() const
181 return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
185 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
187 return iter1.pimpl_->positions == iter2.pimpl_->positions;
191 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
193 return !(iter1 == iter2);
202 struct ParConstIterator::Pimpl {
203 typedef vector<ParPosition> PosHolder;
208 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
209 ParagraphList const & pl)
212 pimpl_->positions.push_back(ParPosition(pit, pl));
216 ParConstIterator::~ParConstIterator()
220 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
221 : pimpl_(new Pimpl(*pi.pimpl_))
225 ParConstIterator & ParConstIterator::operator++()
227 while (!pimpl_->positions.empty()) {
228 ParPosition & p = pimpl_->positions.back();
230 // Does the current inset contain more "cells" ?
233 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
234 if (plist && !plist->empty()) {
235 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
240 // The following line is needed because the value of
241 // p.it may be invalid if inset was added/removed to
242 // the paragraph pointed by the iterator
243 p.it.reset(p.pit->insetlist.begin());
245 // Try to find the next inset that contains paragraphs
246 InsetList::iterator end = p.pit->insetlist.end();
247 for (; *p.it != end; ++(*p.it)) {
248 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
249 if (plist && !plist->empty()) {
251 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
256 // Try to go to the next paragarph
257 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
258 || pimpl_->positions.size() == 1) {
266 // Drop end and move up in the stack.
267 pimpl_->positions.pop_back();
274 Paragraph const & ParConstIterator::operator*() const
276 return *pimpl_->positions.back().pit;
280 ParagraphList::const_iterator ParConstIterator::pit() const
282 return pimpl_->positions.back().pit;
286 ParagraphList::const_iterator ParConstIterator::operator->() const
288 return pimpl_->positions.back().pit;
292 ParagraphList const & ParConstIterator::plist() const
294 return *pimpl_->positions.back().plist;
298 size_t ParConstIterator::size() const
300 return pimpl_->positions.size();
304 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
306 return iter1.pimpl_->positions == iter2.pimpl_->positions;
310 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
312 return !(iter1 == iter2);