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 "funcrequest.h"
20 #include "dispatchresult.h"
24 #include "insets/inset.h"
25 #include "insets/updatableinset.h"
26 #include "insets/insettext.h"
28 #include <boost/next_prior.hpp>
29 #include <boost/optional.hpp>
32 using boost::optional;
42 ParPosition(ParagraphList::iterator p, ParagraphList const & pl);
44 ParagraphList::iterator pit;
46 ParagraphList const * plist;
48 optional<InsetList::iterator> it;
54 ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
57 if (p != const_cast<ParagraphList&>(pl).end()) {
58 it.reset(p->insetlist.begin());
63 bool operator==(ParPosition const & pos1, ParPosition const & pos2)
65 return pos1.pit == pos2.pit;
69 bool operator!=(ParPosition const & pos1, ParPosition const & pos2)
71 return !(pos1 == pos2);
79 struct ParIterator::Pimpl {
80 typedef vector<ParPosition> PosHolder;
84 ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl)
87 pimpl_->positions.push_back(ParPosition(pit, pl));
91 ParIterator::~ParIterator()
95 ParIterator::ParIterator(ParIterator const & pi)
96 : pimpl_(new Pimpl(*pi.pimpl_))
100 void ParIterator::operator=(ParIterator const & pi)
103 pimpl_.swap(tmp.pimpl_);
107 ParIterator & ParIterator::operator++()
109 while (!pimpl_->positions.empty()) {
110 ParPosition & p = pimpl_->positions.back();
112 // Does the current inset contain more "cells" ?
115 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
116 if (plist && !plist->empty()) {
117 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());
127 // Try to find the next inset that contains paragraphs
128 InsetList::iterator end = p.pit->insetlist.end();
129 for (; *p.it != end; ++(*p.it)) {
130 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
131 if (plist && !plist->empty()) {
133 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
138 // Try to go to the next paragarph
139 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
140 || pimpl_->positions.size() == 1) {
148 // Drop end and move up in the stack.
149 pimpl_->positions.pop_back();
155 LyXText * ParIterator::text() const
157 //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl;
158 if (pimpl_->positions.size() <= 1)
161 ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2];
162 return (*pos.it)->inset->getText(*pos.index);
166 InsetOld * ParIterator::inset() const
168 //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl;
169 if (pimpl_->positions.size() <= 1)
172 ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2];
173 return (*pos.it)->inset;
177 int ParIterator::index() const
179 if (pimpl_->positions.size() <= 1)
182 return *(pimpl_->positions[pimpl_->positions.size() - 2].index);
186 void ParIterator::asCursor(Cursor & cursor) const
188 cursor.data_.clear();
189 for (size_t i = 1, n = size(); i < n; ++i) {
190 ParPosition const & pos = pimpl_->positions[i - 1];
192 item.inset_ = (*pos.it)->inset;
193 item.idx_ = (*pos.index);
194 item.text_ = (*pos.it)->inset->getText(*pos.index);
197 cursor.data_.push_back(item);
202 Paragraph & ParIterator::operator*() const
204 return *pimpl_->positions.back().pit;
208 ParagraphList::iterator ParIterator::pit() const
210 return pimpl_->positions.back().pit;
214 ParagraphList::iterator ParIterator::operator->() const
216 return pimpl_->positions.back().pit;
220 ParagraphList::iterator ParIterator::outerPar() const
222 return pimpl_->positions[0].pit;
226 size_t ParIterator::size() const
228 return pimpl_->positions.size();
232 ParagraphList & ParIterator::plist() const
234 return *const_cast<ParagraphList*>(pimpl_->positions.back().plist);
238 bool operator==(ParIterator const & iter1, ParIterator const & iter2)
240 return iter1.pimpl_->positions == iter2.pimpl_->positions;
244 bool operator!=(ParIterator const & iter1, ParIterator const & iter2)
246 return !(iter1 == iter2);
255 struct ParConstIterator::Pimpl {
256 typedef vector<ParPosition> PosHolder;
261 ParConstIterator::ParConstIterator(ParagraphList::iterator pit,
262 ParagraphList const & pl)
265 pimpl_->positions.push_back(ParPosition(pit, pl));
269 ParConstIterator::~ParConstIterator()
273 ParConstIterator::ParConstIterator(ParConstIterator const & pi)
274 : pimpl_(new Pimpl(*pi.pimpl_))
278 ParConstIterator & ParConstIterator::operator++()
280 while (!pimpl_->positions.empty()) {
281 ParPosition & p = pimpl_->positions.back();
283 // Does the current inset contain more "cells" ?
286 ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index);
287 if (plist && !plist->empty()) {
288 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
293 // The following line is needed because the value of
294 // p.it may be invalid if inset was added/removed to
295 // the paragraph pointed by the iterator
296 p.it.reset(p.pit->insetlist.begin());
298 // Try to find the next inset that contains paragraphs
299 InsetList::iterator end = p.pit->insetlist.end();
300 for (; *p.it != end; ++(*p.it)) {
301 ParagraphList * plist = (*p.it)->inset->getParagraphs(0);
302 if (plist && !plist->empty()) {
304 pimpl_->positions.push_back(ParPosition(plist->begin(), *plist));
309 // Try to go to the next paragarph
310 if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
311 || pimpl_->positions.size() == 1) {
319 // Drop end and move up in the stack.
320 pimpl_->positions.pop_back();
327 Paragraph const & ParConstIterator::operator*() const
329 return *pimpl_->positions.back().pit;
333 ParagraphList::const_iterator ParConstIterator::pit() const
335 return pimpl_->positions.back().pit;
339 ParagraphList::const_iterator ParConstIterator::operator->() const
341 return pimpl_->positions.back().pit;
345 ParagraphList const & ParConstIterator::plist() const
347 return *pimpl_->positions.back().plist;
351 size_t ParConstIterator::size() const
353 return pimpl_->positions.size();
357 bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2)
359 return iter1.pimpl_->positions == iter2.pimpl_->positions;
363 bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2)
365 return !(iter1 == iter2);
369 PosIterator ParIterator::asPosIterator(lyx::pos_type pos) const
373 int const last = size() - 1;
374 for (int i = 0; i < last; ++i) {
375 ParPosition & pp = pimpl_->positions[i];
376 p.stack_.push(PosIteratorItem(const_cast<ParagraphList *>(pp.plist), pp.pit, (*pp.it)->pos, *pp.index + 1));
378 ParPosition const & pp = pimpl_->positions[last];
379 p.stack_.push(PosIteratorItem(const_cast<ParagraphList *>(pp.plist),
385 void ParIterator::lockPath(BufferView * bv) const
388 int last = size() - 1;
389 for (int i = 0; i < last; ++i) {
390 UpdatableInset * outer = dynamic_cast<UpdatableInset *>((*pimpl_->positions[i].it)->inset);
391 FuncRequest cmd(bv, LFUN_INSET_EDIT);
392 outer->dispatch(cmd);
393 LyXText * txt = outer->getText(*pimpl_->positions[i].index);
394 InsetText * inner = txt->inset_owner;
395 // deep vodoo magic: on a table, the edit call locks the first
396 // cell and further lock calls get lost there.
397 // We have to unlock it to then lock the correct one.
398 if (outer != inner) {
399 outer->insetUnlock(bv);
400 outer->lockInsetInInset(bv, inner);
401 inner->dispatch(FuncRequest(bv, LFUN_INSET_EDIT));