]> git.lyx.org Git - lyx.git/blob - src/dociterator.C
264df011274a88580ff74a1a3171750d53e0fdd7
[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         BOOST_ASSERT(pos() < lastpos());
107         return cell()[pos()];
108 }
109
110
111 MathAtom & DocIterator::nextAtom()
112 {
113         BOOST_ASSERT(!empty());
114         BOOST_ASSERT(pos() < lastpos());
115         return cell()[pos()];
116 }
117
118
119 LyXText * DocIterator::text() const
120 {
121         BOOST_ASSERT(!empty());
122         return top().text();
123 }
124
125
126 Paragraph & DocIterator::paragraph()
127 {
128         BOOST_ASSERT(inTexted());
129         return top().paragraph();
130 }
131
132
133 Paragraph const & DocIterator::paragraph() const
134 {
135         BOOST_ASSERT(inTexted());
136         return top().paragraph();
137 }
138
139
140 Row & DocIterator::textRow()
141 {
142         return *paragraph().getRow(pos());
143 }
144
145
146 Row const & DocIterator::textRow() const
147 {
148         return *paragraph().getRow(pos());
149 }
150
151
152 DocIterator::par_type DocIterator::lastpar() const
153 {
154         return inMathed() ? 0 : text()->paragraphs().size() - 1;
155 }
156
157
158 DocIterator::pos_type DocIterator::lastpos() const
159 {
160         return inMathed() ? cell().size() : paragraph().size();
161 }
162
163
164 DocIterator::row_type DocIterator::crow() const
165 {
166         return paragraph().row(pos());
167 }
168
169
170 DocIterator::row_type DocIterator::lastcrow() const
171 {
172         return paragraph().rows.size();
173 }
174
175
176 DocIterator::idx_type DocIterator::lastidx() const
177 {
178         return top().lastidx();
179 }
180
181
182 size_t DocIterator::nargs() const
183 {
184         // assume 1x1 grid for main text
185         return top().nargs();
186 }
187
188
189 size_t DocIterator::ncols() const
190 {
191         // assume 1x1 grid for main text
192         return top().ncols();
193 }
194
195
196 size_t DocIterator::nrows() const
197 {
198         // assume 1x1 grid for main text
199         return top().nrows();
200 }
201
202
203 DocIterator::row_type DocIterator::row() const
204 {
205         return top().row();
206 }
207
208
209 DocIterator::col_type DocIterator::col() const
210 {
211         return top().col();
212 }
213
214
215 MathArray const & DocIterator::cell() const
216 {
217         BOOST_ASSERT(inMathed());
218         return top().cell();
219 }
220
221
222 MathArray & DocIterator::cell()
223 {
224         BOOST_ASSERT(inMathed());
225         return top().cell();
226 }
227
228
229 bool DocIterator::inMathed() const
230 {
231         return !empty() && inset().inMathed();
232 }
233
234
235 bool DocIterator::inTexted() const
236 {
237         return !empty() && !inset().inMathed();
238 }
239
240
241 LyXText * DocIterator::innerText() const
242 {
243         BOOST_ASSERT(!empty());
244         // go up until first non-0 text is hit
245         // (innermost text is 0 in mathed)
246         for (int i = size() - 1; i >= 0; --i)
247                 if (operator[](i).text())
248                         return operator[](i).text();
249         return 0;
250 }
251
252
253 InsetBase * DocIterator::innerInsetOfType(int code) const
254 {
255         for (int i = size() - 1; i >= 0; --i)
256                 if (operator[](i).inset_->lyxCode() == code)
257                         return operator[](i).inset_;
258         return 0;
259 }
260
261
262 void DocIterator::forwardPos()
263 {
264         //this dog bites his tail
265         if (empty()) {
266                 push_back(CursorSlice(*inset_));
267                 return;
268         }
269
270         CursorSlice & top = back();
271         //lyxerr << "XXX\n" << *this << endl;
272
273         // this is used twice and shows up in the profiler!
274         pos_type const lastp = lastpos();
275
276         // move into an inset to the right if possible
277         InsetBase * n = 0;
278
279         if (top.pos() != lastp) {
280                 // this is impossible for pos() == size()
281                 if (inMathed()) {
282                         n = (top.cell().begin() + top.pos())->nucleus();
283                 } else {
284                         if (paragraph().isInset(top.pos()))
285                                 n = paragraph().getInset(top.pos());
286                 }
287         }
288
289         if (n && n->isActive()) {
290                 //lyxerr << "... descend" << endl;
291                 push_back(CursorSlice(*n));
292                 return;
293         }
294
295         // otherwise move on one position if possible
296         if (top.pos() < lastp) {
297                 //lyxerr << "... next pos" << endl;
298                 ++top.pos();
299                 return;
300         }
301         //lyxerr << "... no next pos" << endl;
302
303         // otherwise move on one paragraph if possible
304         if (top.par() < lastpar()) {
305                 //lyxerr << "... next par" << endl;
306                 ++top.par();
307                 top.pos() = 0;
308                 return;
309         }
310         //lyxerr << "... no next par" << endl;
311
312         // otherwise try to move on one cell if possible
313         if (top.idx() < lastidx()) {
314                 //lyxerr << "... next idx" << endl;
315                 ++top.idx();
316                 top.par() = 0;
317                 top.pos() = 0;
318                 return;
319         }
320         //lyxerr << "... no next idx" << endl;
321
322         // otherwise leave inset and jump over inset as a whole
323         pop_back();
324         // 'top' is invalid now...
325         if (size())
326                 ++back().pos();
327 }
328
329
330 void DocIterator::forwardPar()
331 {
332         forwardPos();
333         while (!empty() && (!inTexted() || pos() != 0))
334                 forwardPos();
335 }
336
337
338 void DocIterator::forwardChar()
339 {
340         forwardPos();
341         while (size() != 0 && pos() == lastpos())
342                 forwardPos();
343 }
344
345
346 void DocIterator::forwardInset()
347 {
348         forwardPos();
349         while (size() != 0 && (pos() == lastpos() || nextInset() == 0))
350                 forwardPos();
351 }
352
353
354 void DocIterator::backwardChar()
355 {
356         backwardPos();
357         while (size() != 0 && pos() == lastpos())
358                 backwardPos();
359 }
360
361
362 void DocIterator::backwardPos()
363 {
364         //this dog bites his tail
365         if (empty()) {
366                 push_back(CursorSlice(*inset_));
367                 back().idx() = lastidx();
368                 back().par() = lastpar();
369                 back().pos() = lastpos();
370                 return;
371         }
372
373         CursorSlice & top = back();
374
375         if (top.pos() != 0) {
376                 --top.pos();
377         } else if (top.par() != 0) {
378                 --top.par();
379                 top.pos() = lastpos();
380                 return;
381         } else if (top.idx() != 0) {
382                 --top.idx();
383                 top.par() = lastpar();
384                 top.pos() = lastpos();
385                 return;
386         } else {
387                 pop_back();
388                 return;
389         }
390
391         // move into an inset to the left if possible
392         InsetBase * n = 0;
393
394         if (inMathed()) {
395                 n = (top.cell().begin() + top.pos())->nucleus();
396         } else {
397                 if (paragraph().isInset(top.pos()))
398                         n = paragraph().getInset(top.pos());
399         }
400
401         if (n && n->isActive()) {
402                 push_back(CursorSlice(*n));
403                 back().idx() = lastidx();
404                 back().par() = lastpar();
405                 back().pos() = lastpos();
406         }
407 }
408
409
410 std::ostream & operator<<(std::ostream & os, DocIterator const & dit)
411 {
412         for (size_t i = 0, n = dit.size(); i != n; ++i)
413                 os << " " << dit.operator[](i) << "\n";
414         return os;
415 }
416
417
418
419 ///////////////////////////////////////////////////////
420
421 StableDocIterator::StableDocIterator(const DocIterator & dit)
422 {
423         data_ = dit;
424         for (size_t i = 0, n = data_.size(); i != n; ++i)
425                 data_[i].inset_ = 0;
426 }
427
428
429 DocIterator
430 StableDocIterator::asDocIterator(InsetBase * inset) const
431 {
432         // this function re-creates the cache of inset pointers
433         //lyxerr << "converting:\n" << *this << endl;
434         DocIterator dit = DocIterator(*inset);
435         for (size_t i = 0, n = data_.size(); i != n; ++i) {
436                 dit.push_back(data_[i]);
437                 dit.back().inset_ = inset;
438                 if (i + 1 != n)
439                         inset = dit.nextInset();
440         }
441         //lyxerr << "convert:\n" << *this << " to:\n" << dit << endl;
442         return dit;
443 }
444
445
446 std::ostream & operator<<(std::ostream & os, StableDocIterator const & dit)
447 {
448         for (size_t i = 0, n = dit.data_.size(); i != n; ++i)
449                 os << " " << dit.data_[i] << "\n";
450         return os;
451 }