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"
16 #include "PosIterator.h"
19 #include "BufferView.h"
20 #include "dispatchresult.h"
22 #include "insets/inset.h"
23 #include "insets/updatableinset.h"
24 #include "insets/insettext.h"
26 #include <boost/next_prior.hpp>
27 #include <boost/optional.hpp>
30 using boost::optional;
40 ParPosition(ParagraphList::iterator p, ParagraphList const & pl);
42 ParagraphList::iterator pit;
44 ParagraphList const * plist;
46 optional<InsetList::iterator> it;
52 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
55 if (p != const_cast<ParagraphList&>(pl).end()) {
56 it.reset(p->insetlist.begin());
61 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
63 return pos1.pit == pos2.pit;
67 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
69 return !(pos1 == pos2);
77 struct ParIterator::Pimpl {
78 typedef vector<ParPosition> PosHolder;
82 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
85 pimpl_->positions.push_back(ParPosition(pit, pl));
89 ParIterator::~ParIterator()
93 ParIterator::ParIterator(ParIterator const & pi)
94 : pimpl_(new Pimpl(*pi.pimpl_))
98 void ParIterator::operator=(ParIterator const & pi)
101 pimpl_.swap(tmp.pimpl_);
105 ParIterator & ParIterator::operator++()
107 while (!pimpl_->positions.empty()) {
108 ParPosition & p = pimpl_->positions.back();
110 // Does the current inset contain more "cells" ?
113 if (LyXText * text = (*p.it)->inset->getText(*p.index)) {
114 ParagraphList & plist = text->paragraphs();
115 if (!plist.empty()) {
116 pimpl_->positions.push_back(ParPosition(plist.begin(), plist));
122 // The following line is needed because the value of
123 // p.it may be invalid if inset was added/removed to
124 // the paragraph pointed by the iterator
125 p.it.reset(p.pit->insetlist.begin());
128 // Try to find the next inset that contains paragraphs
129 InsetList::iterator end = p.pit->insetlist.end();
130 for (; *p.it != end; ++(*p.it)) {
131 if (LyXText * text = (*p.it)->inset->getText(0)) {
132 ParagraphList & plist = text->paragraphs();
133 if (!plist.empty()) {
135 pimpl_->positions.push_back(ParPosition(plist.begin(), plist));
141 // Try to go to the next paragarph
142 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
143 || pimpl_->positions.size() == 1) {
151 // Drop end and move up in the stack.
152 pimpl_->positions.pop_back();
158 LyXText * ParIterator::text(Buffer & buf) const
160 //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl;
161 if (pimpl_->positions.size() <= 1)
164 ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2];
165 return (*pos.it)->inset->getText(*pos.index);
169 InsetOld * ParIterator::inset() const
171 //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl;
172 if (pimpl_->positions.size() <= 1)
175 ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2];
176 return (*pos.it)->inset;
180 int ParIterator::index() const
182 if (pimpl_->positions.size() <= 1)
185 return *(pimpl_->positions[pimpl_->positions.size() - 2].index);
189 Paragraph & ParIterator::operator*() const
191 return *pimpl_->positions.back().pit;
195 ParagraphList::iterator ParIterator::pit() const
197 return pimpl_->positions.back().pit;
201 ParagraphList::iterator ParIterator::operator->() const
203 return pimpl_->positions.back().pit;
207 ParagraphList::iterator ParIterator::outerPar() const
209 return pimpl_->positions[0].pit;
213 size_t ParIterator::size() const
215 return pimpl_->positions.size();
219 ParagraphList & ParIterator::plist() const
221 return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
225 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
227 return iter1.pimpl_->positions == iter2.pimpl_->positions;
231 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
233 return !(iter1 == iter2);
242 struct ParConstIterator::Pimpl {
243 typedef vector<ParPosition> PosHolder;
248 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
249 ParagraphList const & pl)
252 pimpl_->positions.push_back(ParPosition(pit, pl));
256 ParConstIterator::~ParConstIterator()
260 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
261 : pimpl_(new Pimpl(*pi.pimpl_))
265 ParConstIterator & ParConstIterator::operator++()
267 while (!pimpl_->positions.empty()) {
268 ParPosition & p = pimpl_->positions.back();
270 // Does the current inset contain more "cells" ?
273 if (LyXText * text = (*p.it)->inset->getText(*p.index)) {
274 ParagraphList & plist = text->paragraphs();
275 if (!plist.empty()) {
276 pimpl_->positions.push_back(ParPosition(plist.begin(), plist));
282 // The following line is needed because the value of
283 // p.it may be invalid if inset was added/removed to
284 // the paragraph pointed by the iterator
285 p.it.reset(p.pit->insetlist.begin());
288 // Try to find the next inset that contains paragraphs
289 InsetList::iterator end = p.pit->insetlist.end();
290 for (; *p.it != end; ++(*p.it)) {
291 if (LyXText * text = (*p.it)->inset->getText(*p.index)) {
292 ParagraphList & plist = text->paragraphs();
293 if (!plist.empty()) {
295 pimpl_->positions.push_back(ParPosition(plist.begin(), plist));
301 // Try to go to the next paragarph
302 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
303 || pimpl_->positions.size() == 1) {
311 // Drop end and move up in the stack.
312 pimpl_->positions.pop_back();
319 Paragraph const & ParConstIterator::operator*() const
321 return *pimpl_->positions.back().pit;
325 ParagraphList::const_iterator ParConstIterator::pit() const
327 return pimpl_->positions.back().pit;
331 ParagraphList::const_iterator ParConstIterator::operator->() const
333 return pimpl_->positions.back().pit;
337 ParagraphList const & ParConstIterator::plist() const
339 return *pimpl_->positions.back().plist;
343 size_t ParConstIterator::size() const
345 return pimpl_->positions.size();
349 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
351 return iter1.pimpl_->positions == iter2.pimpl_->positions;
355 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
357 return !(iter1 == iter2);
361 PosIterator ParIterator::asPosIterator(lyx::pos_type pos) const
365 int const last = size() - 1;
366 for (int i = 0; i < last; ++i) {
367 ParPosition & pp = pimpl_->positions[i];
369 PosIteratorItem(const_cast<ParagraphList *>(pp.plist),
370 pp.pit, (*pp.it)->pos, *pp.index + 1));
372 ParPosition const & pp = pimpl_->positions[last];
374 PosIteratorItem(const_cast<ParagraphList *>(pp.plist), pp.pit, pos, 0));
379 ParIterator::ParIterator(PosIterator const & pos)
382 int const size = pos.stack_.size();
384 for (int i = 0; i < size; ++i) {
385 PosIteratorItem const & it = pos.stack_[i];
386 ParPosition pp(it.pit, *it.pl);
388 InsetOld * inset = it.pit->getInset(it.pos);
390 InsetList::iterator beg = it.pit->insetlist.begin();
391 InsetList::iterator end = it.pit->insetlist.end();
392 for ( ; beg != end && beg->inset != inset; ++beg)
395 pp.index.reset(it.index - 1);
397 pimpl_->positions.push_back(pp);
402 void ParIterator::lockPath(BufferView * bv) const
404 bv->cursor() = LCursor(bv);
405 int last = size() - 1;
406 #warning this seems to create just one entry for InsetTabulars
407 for (int i = 0; i < last; ++i)
408 (*pimpl_->positions[i].it)->inset->edit(bv, true);