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