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"
18 #include "BufferView.h"
19 #include "dispatchresult.h"
21 #include "insets/inset.h"
22 #include "insets/updatableinset.h"
23 #include "insets/insettext.h"
25 #include <boost/next_prior.hpp>
26 #include <boost/optional.hpp>
29 using boost::optional;
39 ParPosition(ParagraphList::iterator p, ParagraphList const & pl);
41 ParagraphList::iterator pit;
43 ParagraphList const * plist;
45 optional<InsetList::iterator> it;
51 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
54 if (p != const_cast<ParagraphList&>(pl).end()) {
55 it.reset(p->insetlist.begin());
60 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
62 return pos1.pit == pos2.pit;
66 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
68 return !(pos1 == pos2);
76 struct ParIterator::Pimpl {
77 typedef vector<ParPosition> PosHolder;
81 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
84 pimpl_->positions.push_back(ParPosition(pit, pl));
88 ParIterator::~ParIterator()
92 ParIterator::ParIterator(ParIterator const & pi)
93 : pimpl_(new Pimpl(*pi.pimpl_))
97 void ParIterator::operator=(ParIterator const & pi)
100 pimpl_.swap(tmp.pimpl_);
104 ParIterator & ParIterator::operator++()
106 while (!pimpl_->positions.empty()) {
107 ParPosition & p = pimpl_->positions.back();
109 // Does the current inset contain more "cells" ?
112 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
113 if (plist && !plist->empty()) {
114 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
119 // The following line is needed because the value of
120 // p.it may be invalid if inset was added/removed to
121 // the paragraph pointed by the iterator
122 p.it.reset(p.pit->insetlist.begin());
124 // Try to find the next inset that contains paragraphs
125 InsetList::iterator end = p.pit->insetlist.end();
126 for (; *p.it != end; ++(*p.it)) {
127 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
128 if (plist && !plist->empty()) {
130 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
135 // Try to go to the next paragarph
136 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
137 || pimpl_->positions.size() == 1) {
145 // Drop end and move up in the stack.
146 pimpl_->positions.pop_back();
152 LyXText * ParIterator::text(BufferView * bv) const
154 //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl;
155 if (pimpl_->positions.size() <= 1)
158 ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2];
159 return (*pos.it)->inset->getText(*pos.index);
163 InsetOld * ParIterator::inset() const
165 //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl;
166 if (pimpl_->positions.size() <= 1)
169 ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2];
170 return (*pos.it)->inset;
174 int ParIterator::index() const
176 if (pimpl_->positions.size() <= 1)
179 return *(pimpl_->positions[pimpl_->positions.size() - 2].index);
183 Paragraph & ParIterator::operator*() const
185 return *pimpl_->positions.back().pit;
189 ParagraphList::iterator ParIterator::pit() const
191 return pimpl_->positions.back().pit;
195 ParagraphList::iterator ParIterator::operator->() const
197 return pimpl_->positions.back().pit;
201 ParagraphList::iterator ParIterator::outerPar() const
203 return pimpl_->positions[0].pit;
207 size_t ParIterator::size() const
209 return pimpl_->positions.size();
213 ParagraphList & ParIterator::plist() const
215 return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
219 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
221 return iter1.pimpl_->positions == iter2.pimpl_->positions;
225 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
227 return !(iter1 == iter2);
236 struct ParConstIterator::Pimpl {
237 typedef vector<ParPosition> PosHolder;
242 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
243 ParagraphList const & pl)
246 pimpl_->positions.push_back(ParPosition(pit, pl));
250 ParConstIterator::~ParConstIterator()
254 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
255 : pimpl_(new Pimpl(*pi.pimpl_))
259 ParConstIterator & ParConstIterator::operator++()
261 while (!pimpl_->positions.empty()) {
262 ParPosition & p = pimpl_->positions.back();
264 // Does the current inset contain more "cells" ?
267 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
268 if (plist && !plist->empty()) {
269 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
274 // The following line is needed because the value of
275 // p.it may be invalid if inset was added/removed to
276 // the paragraph pointed by the iterator
277 p.it.reset(p.pit->insetlist.begin());
279 // Try to find the next inset that contains paragraphs
280 InsetList::iterator end = p.pit->insetlist.end();
281 for (; *p.it != end; ++(*p.it)) {
282 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
283 if (plist && !plist->empty()) {
285 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
290 // Try to go to the next paragarph
291 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
292 || pimpl_->positions.size() == 1) {
300 // Drop end and move up in the stack.
301 pimpl_->positions.pop_back();
308 Paragraph const & ParConstIterator::operator*() const
310 return *pimpl_->positions.back().pit;
314 ParagraphList::const_iterator ParConstIterator::pit() const
316 return pimpl_->positions.back().pit;
320 ParagraphList::const_iterator ParConstIterator::operator->() const
322 return pimpl_->positions.back().pit;
326 ParagraphList const & ParConstIterator::plist() const
328 return *pimpl_->positions.back().plist;
332 size_t ParConstIterator::size() const
334 return pimpl_->positions.size();
338 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
340 return iter1.pimpl_->positions == iter2.pimpl_->positions;
344 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
346 return !(iter1 == iter2);
350 PosIterator ParIterator::asPosIterator(lyx::pos_type pos) const
354 int const last = size() - 1;
355 for (int i = 0; i < last; ++i) {
356 ParPosition & pp = pimpl_->positions[i];
357 p.stack_.push_back(PosIteratorItem(const_cast<ParagraphList *>(pp.plist), pp.pit, (*pp.it)->pos, *pp.index + 1));
359 ParPosition const & pp = pimpl_->positions[last];
360 p.stack_.push_back(PosIteratorItem(const_cast<ParagraphList *>(pp.plist), pp.pit, pos, 0));
365 ParIterator::ParIterator(PosIterator const & pos)
368 int const size = pos.stack_.size();
370 for (int i = 0; i < size; ++i) {
371 PosIteratorItem const & it = pos.stack_[i];
372 ParPosition pp(it.pit, *it.pl);
374 InsetOld * inset = it.pit->getInset(it.pos);
376 InsetList::iterator beg = it.pit->insetlist.begin();
377 InsetList::iterator end = it.pit->insetlist.end();
378 for (; beg != end && beg->inset != inset; ++beg);
380 pp.index.reset(it.index - 1);
382 pimpl_->positions.push_back(pp);
387 void ParIterator::lockPath(BufferView * bv) const
390 int last = size() - 1;
391 for (int i = 0; i < last; ++i) {
392 UpdatableInset * outer =
393 dynamic_cast<UpdatableInset *>((*pimpl_->positions[i].it)->inset);
394 outer->edit(bv, true);
395 LyXText * txt = outer->getText(*pimpl_->positions[i].index);
396 InsetText * inner = txt->inset_owner;
397 // deep voodoo magic: on a table, the edit call locks the first
398 // cell and further lock calls get lost there.
399 // We have to unlock it to then lock the correct one.
400 if (outer != inner) {
401 outer->insetUnlock(bv);
402 outer->lockInsetInInset(bv, inner);
403 inner->edit(bv, true);