/* \file iterators.C * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author unknown * \author Lars Gullik Bjønnes * * Full author contact details are available in file CREDITS. */ #include #include "iterators.h" #include "paragraph.h" #include "PosIterator.h" #include "cursor.h" #include "BufferView.h" #include "funcrequest.h" #include "dispatchresult.h" #include "insets/inset.h" #include "insets/updatableinset.h" #include "insets/insettext.h" #include #include using boost::next; using boost::optional; using std::vector; /// /// ParPosition /// class ParPosition { public: /// ParPosition(ParagraphList::iterator p, ParagraphList const & pl); /// ParagraphList::iterator pit; /// ParagraphList const * plist; /// optional it; /// optional index; }; ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl) : pit(p), plist(&pl) { if (p != const_cast(pl).end()) { it.reset(p->insetlist.begin()); } } bool operator==(ParPosition const & pos1, ParPosition const & pos2) { return pos1.pit == pos2.pit; } bool operator!=(ParPosition const & pos1, ParPosition const & pos2) { return !(pos1 == pos2); } /// /// ParIterator /// struct ParIterator::Pimpl { typedef vector PosHolder; PosHolder positions; }; ParIterator::ParIterator(ParagraphList::iterator pit, ParagraphList const & pl) : pimpl_(new Pimpl) { pimpl_->positions.push_back(ParPosition(pit, pl)); } ParIterator::~ParIterator() {} ParIterator::ParIterator(ParIterator const & pi) : pimpl_(new Pimpl(*pi.pimpl_)) {} void ParIterator::operator=(ParIterator const & pi) { ParIterator tmp(pi); pimpl_.swap(tmp.pimpl_); } ParIterator & ParIterator::operator++() { while (!pimpl_->positions.empty()) { ParPosition & p = pimpl_->positions.back(); // Does the current inset contain more "cells" ? if (p.index) { ++(*p.index); ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index); if (plist && !plist->empty()) { pimpl_->positions.push_back(ParPosition(plist->begin(), *plist)); return *this; } ++(*p.it); } else // The following line is needed because the value of // p.it may be invalid if inset was added/removed to // the paragraph pointed by the iterator p.it.reset(p.pit->insetlist.begin()); // Try to find the next inset that contains paragraphs InsetList::iterator end = p.pit->insetlist.end(); for (; *p.it != end; ++(*p.it)) { ParagraphList * plist = (*p.it)->inset->getParagraphs(0); if (plist && !plist->empty()) { p.index.reset(0); pimpl_->positions.push_back(ParPosition(plist->begin(), *plist)); return *this; } } // Try to go to the next paragarph if (next(p.pit) != const_cast(p.plist)->end() || pimpl_->positions.size() == 1) { ++p.pit; p.index.reset(); p.it.reset(); return *this; } // Drop end and move up in the stack. pimpl_->positions.pop_back(); } return *this; } LyXText * ParIterator::text() const { //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl; if (pimpl_->positions.size() <= 1) return 0; ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2]; return (*pos.it)->inset->getText(*pos.index); } InsetOld * ParIterator::inset() const { //lyxerr << "positions.size: " << pimpl_->positions.size() << std::endl; if (pimpl_->positions.size() <= 1) return 0; ParPosition const & pos = pimpl_->positions[pimpl_->positions.size() - 2]; return (*pos.it)->inset; } int ParIterator::index() const { if (pimpl_->positions.size() <= 1) return 0; return *(pimpl_->positions[pimpl_->positions.size() - 2].index); } void ParIterator::asCursor(Cursor & cursor) const { cursor.data_.clear(); for (size_t i = 1, n = size(); i < n; ++i) { ParPosition const & pos = pimpl_->positions[i - 1]; CursorItem item; item.inset_ = (*pos.it)->inset; item.idx_ = (*pos.index); item.text_ = (*pos.it)->inset->getText(*pos.index); item.par_ = 0; item.pos_ = 0; cursor.data_.push_back(item); } } Paragraph & ParIterator::operator*() const { return *pimpl_->positions.back().pit; } ParagraphList::iterator ParIterator::pit() const { return pimpl_->positions.back().pit; } ParagraphList::iterator ParIterator::operator->() const { return pimpl_->positions.back().pit; } ParagraphList::iterator ParIterator::outerPar() const { return pimpl_->positions[0].pit; } size_t ParIterator::size() const { return pimpl_->positions.size(); } ParagraphList & ParIterator::plist() const { return *const_cast(pimpl_->positions.back().plist); } bool operator==(ParIterator const & iter1, ParIterator const & iter2) { return iter1.pimpl_->positions == iter2.pimpl_->positions; } bool operator!=(ParIterator const & iter1, ParIterator const & iter2) { return !(iter1 == iter2); } /// /// ParConstIterator /// struct ParConstIterator::Pimpl { typedef vector PosHolder; PosHolder positions; }; ParConstIterator::ParConstIterator(ParagraphList::iterator pit, ParagraphList const & pl) : pimpl_(new Pimpl) { pimpl_->positions.push_back(ParPosition(pit, pl)); } ParConstIterator::~ParConstIterator() {} ParConstIterator::ParConstIterator(ParConstIterator const & pi) : pimpl_(new Pimpl(*pi.pimpl_)) {} ParConstIterator & ParConstIterator::operator++() { while (!pimpl_->positions.empty()) { ParPosition & p = pimpl_->positions.back(); // Does the current inset contain more "cells" ? if (p.index) { ++(*p.index); ParagraphList * plist = (*p.it)->inset->getParagraphs(*p.index); if (plist && !plist->empty()) { pimpl_->positions.push_back(ParPosition(plist->begin(), *plist)); return *this; } ++(*p.it); } else // The following line is needed because the value of // p.it may be invalid if inset was added/removed to // the paragraph pointed by the iterator p.it.reset(p.pit->insetlist.begin()); // Try to find the next inset that contains paragraphs InsetList::iterator end = p.pit->insetlist.end(); for (; *p.it != end; ++(*p.it)) { ParagraphList * plist = (*p.it)->inset->getParagraphs(0); if (plist && !plist->empty()) { p.index.reset(0); pimpl_->positions.push_back(ParPosition(plist->begin(), *plist)); return *this; } } // Try to go to the next paragarph if (next(p.pit) != const_cast(p.plist)->end() || pimpl_->positions.size() == 1) { ++p.pit; p.index.reset(); p.it.reset(); return *this; } // Drop end and move up in the stack. pimpl_->positions.pop_back(); } return *this; } Paragraph const & ParConstIterator::operator*() const { return *pimpl_->positions.back().pit; } ParagraphList::const_iterator ParConstIterator::pit() const { return pimpl_->positions.back().pit; } ParagraphList::const_iterator ParConstIterator::operator->() const { return pimpl_->positions.back().pit; } ParagraphList const & ParConstIterator::plist() const { return *pimpl_->positions.back().plist; } size_t ParConstIterator::size() const { return pimpl_->positions.size(); } bool operator==(ParConstIterator const & iter1, ParConstIterator const & iter2) { return iter1.pimpl_->positions == iter2.pimpl_->positions; } bool operator!=(ParConstIterator const & iter1, ParConstIterator const & iter2) { return !(iter1 == iter2); } PosIterator ParIterator::asPosIterator(lyx::pos_type pos) const { PosIterator p; int const last = size() - 1; for (int i = 0; i < last; ++i) { ParPosition & pp = pimpl_->positions[i]; p.stack_.push(PosIteratorItem(const_cast(pp.plist), pp.pit, (*pp.it)->pos, *pp.index + 1)); } ParPosition const & pp = pimpl_->positions[last]; p.stack_.push(PosIteratorItem(const_cast(pp.plist), pp.pit, pos, 0)); return p; } void ParIterator::lockPath(BufferView * bv) const { bv->insetUnlock(); int last = size() - 1; for (int i = 0; i < last; ++i) { UpdatableInset * outer = dynamic_cast((*pimpl_->positions[i].it)->inset); FuncRequest cmd(bv, LFUN_INSET_EDIT); outer->dispatch(cmd); LyXText * txt = outer->getText(*pimpl_->positions[i].index); InsetText * inner = txt->inset_owner; // deep vodoo magic: on a table, the edit call locks the first // cell and further lock calls get lost there. // We have to unlock it to then lock the correct one. if (outer != inner) { outer->insetUnlock(bv); outer->lockInsetInInset(bv, inner); inner->dispatch(FuncRequest(bv, LFUN_INSET_EDIT)); } } }