+/* \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 <config.h>
#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 <boost/next_prior.hpp>
+#include <boost/optional.hpp>
+
+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<InsetList::iterator> it;
+ ///
+ optional<int> index;
+};
+
+
+ParPosition::ParPosition(ParagraphList::iterator p, ParagraphList const & pl)
+ : pit(p), plist(&pl)
+{
+ if (p != const_cast<ParagraphList&>(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<ParPosition> 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 (!positions.empty()) {
- ParPosition & p = positions.back();
+ while (!pimpl_->positions.empty()) {
+ ParPosition & p = pimpl_->positions.back();
// Does the current inset contain more "cells" ?
- if (p.index >= 0) {
- ++p.index;
- Paragraph * par = (*p.it)->getFirstParagraph(p.index);
- if (par) {
- positions.push_back(ParPosition(par));
+ 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;
+ ++(*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 = p.par->inset_iterator_begin();
+ p.it.reset(p.pit->insetlist.begin());
// Try to find the next inset that contains paragraphs
- for ( ; p.it != p.par->inset_iterator_end(); ++p.it) {
- Paragraph * par = (*p.it)->getFirstParagraph(0);
- if (par) {
- p.index = 0;
- positions.push_back(ParPosition(par));
+ 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 (p.par->next()) {
- p = ParPosition(p.par->next());
+ if (next(p.pit) != const_cast<ParagraphList*>(p.plist)->end()
+ || pimpl_->positions.size() == 1) {
+ ++p.pit;
+ p.index.reset();
+ p.it.reset();
+
return *this;
}
- positions.pop_back();
+ // 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<ParagraphList*>(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<ParPosition> 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<ParagraphList*>(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<ParagraphList *>(pp.plist), pp.pit, (*pp.it)->pos, *pp.index + 1));
+ }
+ ParPosition const & pp = pimpl_->positions[last];
+ p.stack_.push(PosIteratorItem(const_cast<ParagraphList *>(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<UpdatableInset *>((*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));
+ }
+ }
+}