]> git.lyx.org Git - lyx.git/blob - src/dociterator.C
d4d51819ef886f5430652566ea45b6494b6246d9
[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::backwardChar()
306 {
307         lyxerr << "not implemented" << endl;
308         BOOST_ASSERT(false);
309 }
310
311
312 void DocumentIterator::forwardPar()
313 {
314         CursorSlice & top = back();
315         lyxerr << "XXX " << *this << endl;
316
317         // move into an inset to the right if possible
318         InsetBase * n = 0;
319         if (top.pos() != lastpos()) {
320                 // this is impossible for pos() == size()
321                 if (inMathed()) {
322                         n = (top.cell().begin() + top.pos())->nucleus();
323                 } else {
324                         if (paragraph().isInset(top.pos()))
325                                 n = paragraph().getInset(top.pos());
326                 }
327         }
328
329         if (n && n->isActive()) {
330                 lyxerr << "... descend" << endl;
331                 push_back(CursorSlice(*n));
332                 return;
333         }
334
335         // otherwise move on one cell back if possible
336         if (top.pos() < lastpos()) {
337                 lyxerr << "... next pos" << endl;
338                 ++top.pos();
339                 return;
340         }
341
342         // otherwise move on one cell back if possible
343         if (top.par() < lastpar()) {
344                 lyxerr << "... next par" << endl;
345                 ++top.par();
346                 top.pos() = 0;
347                 return;
348         }
349
350         // otherwise try to move on one cell if possible
351         while (top.idx() < top.lastidx()) {
352                 lyxerr << "... next idx" 
353                         << " was: " << top.idx() << " max: " << top.lastidx() << endl;
354                 ++top.idx();
355                 top.par() = 0;
356                 top.pos() = 0;
357                 return;
358         }
359
360         // otherwise leave inset an jump over inset as a whole
361         pop_back();
362         // 'top' is invalid now...
363         if (size())
364                 ++back().pos();
365 }
366
367
368 std::ostream & operator<<(std::ostream & os, DocumentIterator const & dit)
369 {
370         for (size_t i = 0, n = dit.size(); i != n; ++i)
371                 os << " " << dit.operator[](i) << "\n";
372         return os;
373 }
374
375
376
377 ///////////////////////////////////////////////////////
378
379 StableDocumentIterator::StableDocumentIterator(const DocumentIterator & dit)
380 {
381         data_ = dit;
382         for (size_t i = 0, n = data_.size(); i != n; ++i)
383                 data_[i].inset_ = 0;
384 }
385
386
387 DocumentIterator
388 StableDocumentIterator::asDocumentIterator(InsetBase * inset) const
389 {
390         // this function re-creates the cache of inset pointers
391         //lyxerr << "converting:\n" << *this << endl;
392         DocumentIterator dit;
393         for (size_t i = 0, n = data_.size(); i != n; ++i) {
394                 dit.push_back(data_[i]);
395                 dit.back().inset_ = inset;
396                 if (i + 1 != n)
397                         inset = dit.nextInset();
398         }
399         //lyxerr << "convert:\n" << *this << " to:\n" << dit << endl;
400         return dit;
401 }
402
403
404 std::ostream & operator<<(std::ostream & os, StableDocumentIterator const & dit)
405 {
406         for (size_t i = 0, n = dit.data_.size(); i != n; ++i)
407                 os << " " << dit.data_[i] << "\n";
408         return os;
409 }
410