3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Lars Gullik Bjønnes
9 * Full author contact details are available in file CREDITS.
15 #include "dociterator.h"
20 #include "paragraph.h"
22 #include "mathed/math_data.h"
23 #include "mathed/math_inset.h"
25 #include <boost/assert.hpp>
30 // We could be able to get rid of this if only every BufferView were
31 // associated to a buffer on construction.
32 DocIterator::DocIterator()
37 DocIterator::DocIterator(InsetBase & inset)
42 DocIterator doc_iterator_begin(InsetBase & inset)
44 DocIterator dit(inset);
50 DocIterator doc_iterator_end(InsetBase & inset)
52 return DocIterator(inset);
56 InsetBase * DocIterator::nextInset()
58 BOOST_ASSERT(!empty());
59 if (pos() == lastpos())
62 return nextAtom().nucleus();
63 return paragraph().isInset(pos()) ? paragraph().getInset(pos()) : 0;
67 InsetBase * DocIterator::prevInset()
69 BOOST_ASSERT(!empty());
73 return prevAtom().nucleus();
74 return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0;
78 InsetBase const * DocIterator::prevInset() const
80 BOOST_ASSERT(!empty());
84 return prevAtom().nucleus();
85 return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0;
89 MathAtom const & DocIterator::prevAtom() const
91 BOOST_ASSERT(!empty());
92 BOOST_ASSERT(pos() > 0);
93 return cell()[pos() - 1];
97 MathAtom & DocIterator::prevAtom()
99 BOOST_ASSERT(!empty());
100 BOOST_ASSERT(pos() > 0);
101 return cell()[pos() - 1];
105 MathAtom const & DocIterator::nextAtom() const
107 BOOST_ASSERT(!empty());
108 //lyxerr << "lastpos: " << lastpos() << " next atom:\n" << *this << endl;
109 BOOST_ASSERT(pos() < lastpos());
110 return cell()[pos()];
114 MathAtom & DocIterator::nextAtom()
116 BOOST_ASSERT(!empty());
117 //lyxerr << "lastpos: " << lastpos() << " next atom:\n" << *this << endl;
118 BOOST_ASSERT(pos() < lastpos());
119 return cell()[pos()];
123 LyXText * DocIterator::text() const
125 BOOST_ASSERT(!empty());
130 Paragraph & DocIterator::paragraph()
132 BOOST_ASSERT(inTexted());
133 return top().paragraph();
137 Paragraph const & DocIterator::paragraph() const
139 BOOST_ASSERT(inTexted());
140 return top().paragraph();
144 Row & DocIterator::textRow()
146 return *paragraph().getRow(pos());
150 Row const & DocIterator::textRow() const
152 return *paragraph().getRow(pos());
156 DocIterator::par_type DocIterator::lastpar() const
158 return inMathed() ? 0 : text()->paragraphs().size() - 1;
162 DocIterator::pos_type DocIterator::lastpos() const
164 return inMathed() ? cell().size() : paragraph().size();
168 DocIterator::row_type DocIterator::crow() const
170 return paragraph().row(pos());
174 DocIterator::row_type DocIterator::lastcrow() const
176 return paragraph().rows.size();
180 DocIterator::idx_type DocIterator::lastidx() const
182 return top().lastidx();
186 size_t DocIterator::nargs() const
188 // assume 1x1 grid for main text
189 return top().nargs();
193 size_t DocIterator::ncols() const
195 // assume 1x1 grid for main text
196 return top().ncols();
200 size_t DocIterator::nrows() const
202 // assume 1x1 grid for main text
203 return top().nrows();
207 DocIterator::row_type DocIterator::row() const
213 DocIterator::col_type DocIterator::col() const
219 MathArray const & DocIterator::cell() const
221 BOOST_ASSERT(inMathed());
226 MathArray & DocIterator::cell()
228 BOOST_ASSERT(inMathed());
233 bool DocIterator::inMathed() const
235 return !empty() && inset().inMathed();
239 bool DocIterator::inTexted() const
241 return !empty() && !inset().inMathed();
245 LyXText * DocIterator::innerText() const
247 BOOST_ASSERT(!empty());
248 // go up until first non-0 text is hit
249 // (innermost text is 0 in mathed)
250 for (int i = size() - 1; i >= 0; --i)
251 if (operator[](i).text())
252 return operator[](i).text();
257 InsetBase * DocIterator::innerInsetOfType(int code) const
259 for (int i = size() - 1; i >= 0; --i)
260 if (operator[](i).inset_->lyxCode() == code)
261 return operator[](i).inset_;
266 void DocIterator::forwardPos()
268 //this dog bites his tail
270 push_back(CursorSlice(*inset_));
274 CursorSlice & top = back();
275 //lyxerr << "XXX\n" << *this << endl;
277 // this is used twice and shows up in the profiler!
278 pos_type const lastp = lastpos();
280 // move into an inset to the right if possible
283 if (top.pos() != lastp) {
284 // this is impossible for pos() == size()
286 n = (top.cell().begin() + top.pos())->nucleus();
288 if (paragraph().isInset(top.pos()))
289 n = paragraph().getInset(top.pos());
293 if (n && n->isActive()) {
294 //lyxerr << "... descend" << endl;
295 push_back(CursorSlice(*n));
299 // otherwise move on one position if possible
300 if (top.pos() < lastp) {
301 //lyxerr << "... next pos" << endl;
305 //lyxerr << "... no next pos" << endl;
307 // otherwise move on one paragraph if possible
308 if (top.par() < lastpar()) {
309 //lyxerr << "... next par" << endl;
314 //lyxerr << "... no next par" << endl;
316 // otherwise try to move on one cell if possible
317 if (top.idx() < lastidx()) {
318 //lyxerr << "... next idx" << endl;
324 //lyxerr << "... no next idx" << endl;
326 // otherwise leave inset and jump over inset as a whole
328 // 'top' is invalid now...
334 void DocIterator::forwardPar()
337 while (!empty() && (!inTexted() || pos() != 0))
342 void DocIterator::forwardChar()
345 while (size() != 0 && pos() == lastpos())
350 void DocIterator::forwardInset()
353 while (size() != 0 && (pos() == lastpos() || nextInset() == 0))
358 void DocIterator::backwardChar()
361 while (size() != 0 && pos() == lastpos())
366 void DocIterator::backwardPos()
368 //this dog bites his tail
370 push_back(CursorSlice(*inset_));
371 back().idx() = lastidx();
372 back().par() = lastpar();
373 back().pos() = lastpos();
377 CursorSlice & top = back();
379 if (top.pos() != 0) {
381 } else if (top.par() != 0) {
383 top.pos() = lastpos();
385 } else if (top.idx() != 0) {
387 top.par() = lastpar();
388 top.pos() = lastpos();
395 // move into an inset to the left if possible
399 n = (top.cell().begin() + top.pos())->nucleus();
401 if (paragraph().isInset(top.pos()))
402 n = paragraph().getInset(top.pos());
405 if (n && n->isActive()) {
406 push_back(CursorSlice(*n));
407 back().idx() = lastidx();
408 back().par() = lastpar();
409 back().pos() = lastpos();
414 std::ostream & operator<<(std::ostream & os, DocIterator const & dit)
416 for (size_t i = 0, n = dit.size(); i != n; ++i)
417 os << " " << dit.operator[](i) << "\n";
423 ///////////////////////////////////////////////////////
425 StableDocIterator::StableDocIterator(const DocIterator & dit)
428 for (size_t i = 0, n = data_.size(); i != n; ++i)
434 StableDocIterator::asDocIterator(InsetBase * inset) const
436 // this function re-creates the cache of inset pointers
437 //lyxerr << "converting:\n" << *this << endl;
438 DocIterator dit = DocIterator(*inset);
439 for (size_t i = 0, n = data_.size(); i != n; ++i) {
440 dit.push_back(data_[i]);
441 dit.back().inset_ = inset;
443 inset = dit.nextInset();
445 //lyxerr << "convert:\n" << *this << " to:\n" << dit << endl;
450 std::ostream & operator<<(std::ostream & os, StableDocIterator const & dit)
452 for (size_t i = 0, n = dit.data_.size(); i != n; ++i)
453 os << " " << dit.data_[i] << "\n";