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...
24 using boost::optional;
34 ParPosition(ParagraphList::iterator p, ParagraphList const & pl);
36 ParagraphList::iterator pit;
38 ParagraphList const * plist;
40 optional<InsetList::iterator> it;
46 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
49 if (p != const_cast<ParagraphList&>(pl).end()) {
50 it.reset(p->insetlist.begin());
55 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
57 return pos1.pit == pos2.pit;
61 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
63 return !(pos1 == pos2);
71 struct ParIterator::Pimpl {
72 typedef vector<ParPosition> PosHolder;
76 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
79 pimpl_->positions.push_back(ParPosition(pit, pl));
83 ParIterator::~ParIterator()
87 ParIterator::ParIterator(ParIterator const & pi)
88 : pimpl_(new Pimpl(*pi.pimpl_))
92 void ParIterator::operator=(ParIterator const & pi)
95 pimpl_.swap(tmp.pimpl_);
99 ParIterator & ParIterator::operator++()
101 while (!pimpl_->positions.empty()) {
102 ParPosition & p = pimpl_->positions.back();
104 // Does the current inset contain more "cells" ?
107 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
108 if (plist && !plist->empty()) {
109 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
114 // The following line is needed because the value of
115 // p.it may be invalid if inset was added/removed to
116 // the paragraph pointed by the iterator
117 p.it.reset(p.pit->insetlist.begin());
119 // Try to find the next inset that contains paragraphs
120 InsetList::iterator end = p.pit->insetlist.end();
121 for (; *p.it != end; ++(*p.it)) {
122 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
123 if (plist && !plist->empty()) {
125 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
130 // Try to go to the next paragarph
131 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
132 || pimpl_->positions.size() == 1) {
140 // Drop end and move up in the stack.
141 pimpl_->positions.pop_back();
147 Paragraph & ParIterator::operator*() const
149 return *pimpl_->positions.back().pit;
153 ParagraphList::iterator ParIterator::pit() const
155 return pimpl_->positions.back().pit;
159 ParagraphList::iterator ParIterator::operator->() const
161 return pimpl_->positions.back().pit;
165 ParagraphList::iterator ParIterator::outerPar() const
167 return pimpl_->positions[0].pit;
171 size_t ParIterator::size() const
173 return pimpl_->positions.size();
177 ParagraphList & ParIterator::plist() const
179 return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
183 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
185 return iter1.pimpl_->positions == iter2.pimpl_->positions;
189 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
191 return !(iter1 == iter2);
200 struct ParConstIterator::Pimpl {
201 typedef vector<ParPosition> PosHolder;
206 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
207 ParagraphList const & pl)
210 pimpl_->positions.push_back(ParPosition(pit, pl));
214 ParConstIterator::~ParConstIterator()
218 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
219 : pimpl_(new Pimpl(*pi.pimpl_))
223 ParConstIterator & ParConstIterator::operator++()
225 while (!pimpl_->positions.empty()) {
226 ParPosition & p = pimpl_->positions.back();
228 // Does the current inset contain more "cells" ?
231 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
232 if (plist && !plist->empty()) {
233 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
238 // The following line is needed because the value of
239 // p.it may be invalid if inset was added/removed to
240 // the paragraph pointed by the iterator
241 p.it.reset(p.pit->insetlist.begin());
243 // Try to find the next inset that contains paragraphs
244 InsetList::iterator end = p.pit->insetlist.end();
245 for (; *p.it != end; ++(*p.it)) {
246 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
247 if (plist && !plist->empty()) {
249 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
254 // Try to go to the next paragarph
255 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
256 || pimpl_->positions.size() == 1) {
264 // Drop end and move up in the stack.
265 pimpl_->positions.pop_back();
272 Paragraph const & ParConstIterator::operator*() const
274 return *pimpl_->positions.back().pit;
278 ParagraphList::const_iterator ParConstIterator::pit() const
280 return pimpl_->positions.back().pit;
284 ParagraphList::const_iterator ParConstIterator::operator->() const
286 return pimpl_->positions.back().pit;
290 ParagraphList const & ParConstIterator::plist() const
292 return *pimpl_->positions.back().plist;
296 size_t ParConstIterator::size() const
298 return pimpl_->positions.size();
302 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
304 return iter1.pimpl_->positions == iter2.pimpl_->positions;
308 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
310 return !(iter1 == iter2);