]> git.lyx.org Git - lyx.git/blob - src/dociterator.C
Squash MSVC warning "local variable 'fd' used without having
[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()
127 {
128         BOOST_ASSERT(!empty());
129         return top().text();
130 }
131
132 LyXText const * DocIterator::text() const
133 {
134         BOOST_ASSERT(!empty());
135         return top().text();
136 }
137
138
139 Paragraph & DocIterator::paragraph()
140 {
141         if (!inTexted()) 
142                 lyxerr << *this << endl;
143         BOOST_ASSERT(inTexted());
144         return top().paragraph();
145 }
146
147
148 Paragraph const & DocIterator::paragraph() const
149 {
150         BOOST_ASSERT(inTexted());
151         return top().paragraph();
152 }
153
154
155 Row & DocIterator::textRow()
156 {
157         BOOST_ASSERT(!paragraph().rows().empty());
158         return paragraph().getRow(pos());
159 }
160
161
162 Row const & DocIterator::textRow() const
163 {
164         BOOST_ASSERT(!paragraph().rows().empty());
165         return paragraph().getRow(pos());
166 }
167
168
169 DocIterator::pit_type DocIterator::lastpit() const
170 {
171         return inMathed() ? 0 : text()->paragraphs().size() - 1;
172 }
173
174
175 DocIterator::pos_type DocIterator::lastpos() const
176 {
177         return inMathed() ? cell().size() : paragraph().size();
178 }
179
180
181 DocIterator::idx_type DocIterator::lastidx() const
182 {
183         return top().lastidx();
184 }
185
186
187 size_t DocIterator::nargs() const
188 {
189         // assume 1x1 grid for main text
190         return top().nargs();
191 }
192
193
194 size_t DocIterator::ncols() const
195 {
196         // assume 1x1 grid for main text
197         return top().ncols();
198 }
199
200
201 size_t DocIterator::nrows() const
202 {
203         // assume 1x1 grid for main text
204         return top().nrows();
205 }
206
207
208 DocIterator::row_type DocIterator::row() const
209 {
210         return top().row();
211 }
212
213
214 DocIterator::col_type DocIterator::col() const
215 {
216         return top().col();
217 }
218
219
220 MathArray const & DocIterator::cell() const
221 {
222         BOOST_ASSERT(inMathed());
223         return top().cell();
224 }
225
226
227 MathArray & DocIterator::cell()
228 {
229         BOOST_ASSERT(inMathed());
230         return top().cell();
231 }
232
233
234 bool DocIterator::inMathed() const
235 {
236         return !empty() && inset().inMathed();
237 }
238
239
240 bool DocIterator::inTexted() const
241 {
242         return !empty() && !inset().inMathed();
243 }
244
245
246 LyXText * DocIterator::innerText()
247 {
248         BOOST_ASSERT(!empty());
249         // Go up until first non-0 text is hit
250         // (innermost text is 0 in mathed)
251         for (int i = depth() - 1; i >= 0; --i)
252                 if (slices_[i].text())
253                         return slices_[i].text();
254         return 0;
255 }
256
257 LyXText const * DocIterator::innerText() const
258 {
259         BOOST_ASSERT(!empty());
260         // go up until first non-0 text is hit
261         // (innermost text is 0 in mathed)
262         for (int i = depth() - 1; i >= 0; --i)
263                 if (slices_[i].text())
264                         return slices_[i].text();
265         return 0;
266 }
267
268
269 InsetBase * DocIterator::innerInsetOfType(int code) const
270 {
271         for (int i = depth() - 1; i >= 0; --i)
272                 if (slices_[i].inset_->lyxCode() == code)
273                         return slices_[i].inset_;
274         return 0;
275 }
276
277
278 void DocIterator::forwardPos()
279 {
280         //this dog bites his tail
281         if (empty()) {
282                 push_back(CursorSlice(*inset_));
283                 return;
284         }
285
286         CursorSlice & tip = top();
287         //lyxerr << "XXX\n" << *this << endl;
288
289         // this is used twice and shows up in the profiler!
290         pos_type const lastp = lastpos();
291
292         // move into an inset to the right if possible
293         InsetBase * n = 0;
294
295         if (tip.pos() != lastp) {
296                 // this is impossible for pos() == size()
297                 if (inMathed()) {
298                         n = (tip.cell().begin() + tip.pos())->nucleus();
299                 } else {
300                         if (paragraph().isInset(tip.pos()))
301                                 n = paragraph().getInset(tip.pos());
302                 }
303         }
304
305         if (n && n->isActive()) {
306                 //lyxerr << "... descend" << endl;
307                 push_back(CursorSlice(*n));
308                 return;
309         }
310
311         // otherwise move on one position if possible
312         if (tip.pos() < lastp) {
313                 //lyxerr << "... next pos" << endl;
314                 ++tip.pos();
315                 return;
316         }
317         //lyxerr << "... no next pos" << endl;
318
319         // otherwise move on one paragraph if possible
320         if (tip.pit() < lastpit()) {
321                 //lyxerr << "... next par" << endl;
322                 ++tip.pit();
323                 tip.pos() = 0;
324                 return;
325         }
326         //lyxerr << "... no next pit" << endl;
327
328         // otherwise try to move on one cell if possible
329         if (tip.idx() < lastidx()) {
330                 //lyxerr << "... next idx" << endl;
331                 ++tip.idx();
332                 tip.pit() = 0;
333                 tip.pos() = 0;
334                 return;
335         }
336         //lyxerr << "... no next idx" << endl;
337
338         // otherwise leave inset and jump over inset as a whole
339         pop_back();
340         // 'top' is invalid now...
341         if (!empty())
342                 ++top().pos();
343 }
344
345
346 void DocIterator::forwardPosNoDescend()
347 {
348         CursorSlice & tip = top();
349         pos_type const lastp = lastpos();
350
351         //  move on one position if possible
352         if (tip.pos() < lastp) {
353                 //lyxerr << "... next pos" << endl;
354                 ++tip.pos();
355                 return;
356         }
357         //lyxerr << "... no next pos" << endl;
358
359         // otherwise move on one paragraph if possible
360         if (tip.pit() < lastpit()) {
361                 //lyxerr << "... next par" << endl;
362                 ++tip.pit();
363                 tip.pos() = 0;
364                 return;
365         }
366         //lyxerr << "... no next pit" << endl;
367
368         // otherwise try to move on one cell if possible
369         if (tip.idx() < lastidx()) {
370                 //lyxerr << "... next idx" << endl;
371                 ++tip.idx();
372                 tip.pit() = 0;
373                 tip.pos() = 0;
374                 return;
375         }
376         //lyxerr << "... no next idx" << endl;
377
378         // otherwise we can't move on
379 }
380
381
382 void DocIterator::forwardPar()
383 {
384         forwardPos();
385         while (!empty() && (!inTexted() || pos() != 0))
386                 forwardPos();
387 }
388
389
390 void DocIterator::forwardChar()
391 {
392         forwardPos();
393         while (!empty() && pos() == lastpos())
394                 forwardPos();
395 }
396
397
398 void DocIterator::forwardInset()
399 {
400         forwardPos();
401         while (!empty() && (pos() == lastpos() || nextInset() == 0))
402                 forwardPos();
403 }
404
405
406 void DocIterator::backwardChar()
407 {
408         backwardPos();
409         while (!empty() && pos() == lastpos())
410                 backwardPos();
411 }
412
413
414 void DocIterator::backwardPos()
415 {
416         //this dog bites his tail
417         if (empty()) {
418                 push_back(CursorSlice(*inset_));
419                 top().idx() = lastidx();
420                 top().pit() = lastpit();
421                 top().pos() = lastpos();
422                 return;
423         }
424
425         CursorSlice & tip = top();
426
427         if (tip.pos() != 0) {
428                 --tip.pos();
429         } else if (tip.pit() != 0) {
430                 --tip.pit();
431                 tip.pos() = lastpos();
432                 return;
433         } else if (tip.idx() != 0) {
434                 --tip.idx();
435                 tip.pit() = lastpit();
436                 tip.pos() = lastpos();
437                 return;
438         } else {
439                 pop_back();
440                 return;
441         }
442
443         // move into an inset to the left if possible
444         InsetBase * n = 0;
445
446         if (inMathed()) {
447                 n = (tip.cell().begin() + tip.pos())->nucleus();
448         } else {
449                 if (paragraph().isInset(tip.pos()))
450                         n = paragraph().getInset(tip.pos());
451         }
452
453         if (n && n->isActive()) {
454                 push_back(CursorSlice(*n));
455                 top().idx() = lastidx();
456                 top().pit() = lastpit();
457                 top().pos() = lastpos();
458         }
459 }
460
461
462 bool DocIterator::hasPart(DocIterator const & it) const
463 {
464         // it can't be a part if it is larger
465         if (it.depth() > depth())
466                 return false;
467
468         // as inset adresses are the 'last' level
469         return &it.top().inset() == &slices_[it.depth() - 1].inset();
470 }
471
472
473 std::ostream & operator<<(std::ostream & os, DocIterator const & dit)
474 {
475         for (size_t i = 0, n = dit.depth(); i != n; ++i)
476                 os << " " << dit[i] << "\n";
477         return os;
478 }
479
480
481
482 ///////////////////////////////////////////////////////
483
484 StableDocIterator::StableDocIterator(DocIterator const & dit)
485 {
486         data_ = dit.internalData();
487         for (size_t i = 0, n = data_.size(); i != n; ++i)
488                 data_[i].inset_ = 0;
489 }
490
491
492 DocIterator StableDocIterator::asDocIterator(InsetBase * inset) const
493 {
494         // this function re-creates the cache of inset pointers
495         //lyxerr << "converting:\n" << *this << endl;
496         DocIterator dit = DocIterator(*inset);
497         for (size_t i = 0, n = data_.size(); i != n; ++i) {
498                 if (inset == 0) {
499                         // FIXME
500                         lyxerr << BOOST_CURRENT_FUNCTION
501                                << " Should not happen, but does e.g. after C-n C-l C-z S-C-z"
502                                 << '\n' << "dit: " << dit << '\n'
503                                 << " lastpos: " << dit.lastpos() << endl;
504                         //break;
505                         BOOST_ASSERT(false);
506                 }
507                 dit.push_back(data_[i]);
508                 dit.top().inset_ = inset;
509                 if (i + 1 != n)
510                         inset = dit.nextInset();
511         }
512         //lyxerr << "convert:\n" << *this << " to:\n" << dit << endl;
513         return dit;
514 }
515
516
517 std::ostream & operator<<(std::ostream & os, StableDocIterator const & dit)
518 {
519         for (size_t i = 0, n = dit.data_.size(); i != n; ++i)
520                 os << " " << dit.data_[i] << "\n";
521         return os;
522 }