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