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