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