]> git.lyx.org Git - lyx.git/blob - src/dociterator.C
d884598300b1be9bdcfec31860672cf3c9d1654b
[lyx.git] / src / dociterator.C
1 /**
2  * \file dociterator.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author unknown
7  * \author Lars Gullik Bjønnes
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12
13 #include <config.h>
14
15 #include "dociterator.h"
16
17 #include "debug.h"
18 #include "lyxtext.h"
19 #include "lyxrow.h"
20 #include "paragraph.h"
21
22 #include "mathed/math_data.h"
23 #include "mathed/math_inset.h"
24
25 #include <boost/assert.hpp>
26
27 using std::endl;
28
29
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() : inset_(0)
33 {}
34
35
36 DocIterator doc_iterator_begin(InsetBase & inset)
37 {
38         DocIterator dit(inset);
39         dit.forwardPos();
40         return dit;
41 }
42
43
44 DocIterator doc_iterator_end(InsetBase & inset)
45 {
46         return DocIterator(inset);
47 }
48
49
50 DocIterator::DocIterator(InsetBase & inset) : inset_(&inset)
51 {}
52
53
54 InsetBase * DocIterator::nextInset()
55 {
56         BOOST_ASSERT(!empty());
57         if (pos() == lastpos())
58                 return 0;
59         if (inMathed())
60                 return nextAtom().nucleus();
61         return paragraph().isInset(pos()) ? paragraph().getInset(pos()) : 0;
62 }
63
64
65 InsetBase * DocIterator::prevInset()
66 {
67         BOOST_ASSERT(!empty());
68         if (pos() == 0)
69                 return 0;
70         if (inMathed())
71                 return prevAtom().nucleus();
72         return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0;
73 }
74
75
76 InsetBase const * DocIterator::prevInset() const
77 {
78         BOOST_ASSERT(!empty());
79         if (pos() == 0)
80                 return 0;
81         if (inMathed())
82                 return prevAtom().nucleus();
83         return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0;
84 }
85
86
87 MathAtom const & DocIterator::prevAtom() const
88 {
89         BOOST_ASSERT(!empty());
90         BOOST_ASSERT(pos() > 0);
91         return cell()[pos() - 1];
92 }
93
94
95 MathAtom & DocIterator::prevAtom()
96 {
97         BOOST_ASSERT(!empty());
98         BOOST_ASSERT(pos() > 0);
99         return cell()[pos() - 1];
100 }
101
102
103 MathAtom const & DocIterator::nextAtom() const
104 {
105         BOOST_ASSERT(!empty());
106         lyxerr << "lastpos: " << lastpos() << " next atom:\n" << *this << endl;
107         BOOST_ASSERT(pos() < lastpos());
108         return cell()[pos()];
109 }
110
111
112 MathAtom & DocIterator::nextAtom()
113 {
114         BOOST_ASSERT(!empty());
115         lyxerr << "lastpos: " << lastpos() << " next atom:\n" << *this << endl;
116         BOOST_ASSERT(pos() < lastpos());
117         return cell()[pos()];
118 }
119
120
121 LyXText * DocIterator::text() const
122 {
123         BOOST_ASSERT(!empty());
124         return top().text();
125 }
126
127
128 Paragraph & DocIterator::paragraph()
129 {
130         BOOST_ASSERT(inTexted());
131         return top().paragraph();
132 }
133
134
135 Paragraph const & DocIterator::paragraph() const
136 {
137         BOOST_ASSERT(inTexted());
138         return top().paragraph();
139 }
140
141
142 Row & DocIterator::textRow()
143 {
144         return *paragraph().getRow(pos());
145 }
146
147
148 Row const & DocIterator::textRow() const
149 {
150         return *paragraph().getRow(pos());
151 }
152
153
154 DocIterator::par_type DocIterator::lastpar() const
155 {
156         return inMathed() ? 0 : text()->paragraphs().size() - 1;
157 }
158
159
160 DocIterator::pos_type DocIterator::lastpos() const
161 {
162         return inMathed() ? cell().size() : paragraph().size();
163 }
164
165
166 DocIterator::row_type DocIterator::crow() const
167 {
168         return paragraph().row(pos());
169 }
170
171
172 DocIterator::row_type DocIterator::lastcrow() const
173 {
174         return paragraph().rows.size();
175 }
176
177
178 DocIterator::idx_type DocIterator::lastidx() const
179 {
180         return top().lastidx();
181 }
182
183
184 size_t DocIterator::nargs() const
185 {
186         // assume 1x1 grid for main text
187         return top().nargs();
188 }
189
190
191 size_t DocIterator::ncols() const
192 {
193         // assume 1x1 grid for main text
194         return top().ncols();
195 }
196
197
198 size_t DocIterator::nrows() const
199 {
200         // assume 1x1 grid for main text
201         return top().nrows();
202 }
203
204
205 DocIterator::row_type DocIterator::row() const
206 {
207         return top().row();
208 }
209
210
211 DocIterator::col_type DocIterator::col() const
212 {
213         return top().col();
214 }
215
216
217 MathArray const & DocIterator::cell() const
218 {
219         BOOST_ASSERT(inMathed());
220         return top().cell();
221 }
222
223
224 MathArray & DocIterator::cell()
225 {
226         BOOST_ASSERT(inMathed());
227         return top().cell();
228 }
229
230
231 bool DocIterator::inMathed() const
232 {
233         return !empty() && inset().inMathed();
234 }
235
236
237 bool DocIterator::inTexted() const
238 {
239         return !empty() && !inset().inMathed();
240 }
241
242
243 LyXText * DocIterator::innerText() const
244 {
245         BOOST_ASSERT(!empty());
246         // go up until first non-0 text is hit
247         // (innermost text is 0 in mathed)
248         for (int i = size() - 1; i >= 0; --i)
249                 if (operator[](i).text())
250                         return operator[](i).text();
251         return 0;
252 }
253
254
255 InsetBase * DocIterator::innerInsetOfType(int code) const
256 {
257         for (int i = size() - 1; i >= 0; --i)
258                 if (operator[](i).inset_->lyxCode() == code)
259                         return operator[](i).inset_;
260         return 0;
261 }
262
263
264 void DocIterator::forwardPos()
265 {
266         //this dog bites his tail
267         if (empty()) {
268                 push_back(CursorSlice(*inset_));
269                 return;
270         }
271
272         CursorSlice & top = back();
273         //lyxerr << "XXX\n" << *this << endl;
274
275         // this is used twice and shows up in the profiler!
276         pos_type const lastp = lastpos();
277
278         // move into an inset to the right if possible
279         InsetBase * n = 0;
280
281         if (top.pos() != lastp) {
282                 // this is impossible for pos() == size()
283                 if (inMathed()) {
284                         n = (top.cell().begin() + top.pos())->nucleus();
285                 } else {
286                         if (paragraph().isInset(top.pos()))
287                                 n = paragraph().getInset(top.pos());
288                 }
289         }
290
291         if (n && n->isActive()) {
292                 //lyxerr << "... descend" << endl;
293                 push_back(CursorSlice(*n));
294                 return;
295         }
296
297         // otherwise move on one position if possible
298         if (top.pos() < lastp) {
299                 //lyxerr << "... next pos" << endl;
300                 ++top.pos();
301                 return;
302         }
303         //lyxerr << "... no next pos" << endl;
304
305         // otherwise move on one paragraph if possible
306         if (top.par() < lastpar()) {
307                 //lyxerr << "... next par" << endl;
308                 ++top.par();
309                 top.pos() = 0;
310                 return;
311         }
312         //lyxerr << "... no next par" << endl;
313
314         // otherwise try to move on one cell if possible
315         if (top.idx() < lastidx()) {
316                 //lyxerr << "... next idx" << endl;
317                 ++top.idx();
318                 top.par() = 0;
319                 top.pos() = 0;
320                 return;
321         }
322         //lyxerr << "... no next idx" << endl;
323
324         // otherwise leave inset and jump over inset as a whole
325         pop_back();
326         // 'top' is invalid now...
327         if (size())
328                 ++back().pos();
329 }
330
331
332 void DocIterator::forwardPar()
333 {
334         forwardPos();
335         while (!empty() && (!inTexted() || pos() != 0))
336                 forwardPos();
337 }
338
339
340 void DocIterator::forwardChar()
341 {
342         forwardPos();
343         while (size() != 0 && pos() == lastpos())
344                 forwardPos();
345 }
346
347
348 void DocIterator::forwardInset()
349 {
350         forwardPos();
351         while (size() != 0 && (pos() == lastpos() || nextInset() == 0))
352                 forwardPos();
353 }
354
355
356 void DocIterator::backwardChar()
357 {
358         backwardPos();
359         while (size() != 0 && pos() == lastpos())
360                 backwardPos();
361 }
362
363
364 void DocIterator::backwardPos()
365 {
366         //this dog bites his tail
367         if (empty()) {
368                 push_back(CursorSlice(*inset_));
369                 back().idx() = lastidx();
370                 back().par() = lastpar();
371                 back().pos() = lastpos();
372                 return;
373         }
374
375         CursorSlice & top = back();
376
377         if (top.pos() != 0) {
378                 --top.pos();
379         } else if (top.par() != 0) {
380                 --top.par();
381                 top.pos() = lastpos();
382                 return;
383         } else if (top.idx() != 0) {
384                 --top.idx();
385                 top.par() = lastpar();
386                 top.pos() = lastpos();
387                 return;
388         } else {
389                 pop_back();
390                 return;
391         }
392
393         // move into an inset to the left if possible
394         InsetBase * n = 0;
395
396         if (inMathed()) {
397                 n = (top.cell().begin() + top.pos())->nucleus();
398         } else {
399                 if (paragraph().isInset(top.pos()))
400                         n = paragraph().getInset(top.pos());
401         }
402
403         if (n && n->isActive()) {
404                 push_back(CursorSlice(*n));
405                 back().idx() = lastidx();
406                 back().par() = lastpar();
407                 back().pos() = lastpos();
408         }
409 }
410
411
412 std::ostream & operator<<(std::ostream & os, DocIterator const & dit)
413 {
414         for (size_t i = 0, n = dit.size(); i != n; ++i)
415                 os << " " << dit.operator[](i) << "\n";
416         return os;
417 }
418
419
420
421 ///////////////////////////////////////////////////////
422
423 StableDocIterator::StableDocIterator(const DocIterator & dit)
424 {
425         data_ = dit;
426         for (size_t i = 0, n = data_.size(); i != n; ++i)
427                 data_[i].inset_ = 0;
428 }
429
430
431 DocIterator
432 StableDocIterator::asDocIterator(InsetBase * inset) const
433 {
434         // this function re-creates the cache of inset pointers
435         //lyxerr << "converting:\n" << *this << endl;
436         DocIterator dit = DocIterator(*inset);
437         for (size_t i = 0, n = data_.size(); i != n; ++i) {
438                 dit.push_back(data_[i]);
439                 dit.back().inset_ = inset;
440                 if (i + 1 != n)
441                         inset = dit.nextInset();
442         }
443         //lyxerr << "convert:\n" << *this << " to:\n" << dit << endl;
444         return dit;
445 }
446
447
448 std::ostream & operator<<(std::ostream & os, StableDocIterator const & dit)
449 {
450         for (size_t i = 0, n = dit.data_.size(); i != n; ++i)
451                 os << " " << dit.data_[i] << "\n";
452         return os;
453 }