]> git.lyx.org Git - lyx.git/blob - src/Cursor.cpp
New XHTML math options. Format change.
[lyx.git] / src / Cursor.cpp
1 /**
2  * \file Cursor.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author Alfredo Braunstein
8  * \author Dov Feldstern
9  * \author André Pönitz
10  * \author Stefan Schimanski
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "Bidi.h"
18 #include "Buffer.h"
19 #include "BufferView.h"
20 #include "CoordCache.h"
21 #include "Cursor.h"
22 #include "CutAndPaste.h"
23 #include "DispatchResult.h"
24 #include "Encoding.h"
25 #include "Font.h"
26 #include "FuncCode.h"
27 #include "FuncRequest.h"
28 #include "Language.h"
29 #include "LyXAction.h"
30 #include "LyXRC.h"
31 #include "Paragraph.h"
32 #include "ParIterator.h"
33 #include "Row.h"
34 #include "Text.h"
35 #include "TextMetrics.h"
36 #include "TocBackend.h"
37
38 #include "support/lassert.h"
39 #include "support/debug.h"
40 #include "support/docstream.h"
41
42 #include "insets/InsetTabular.h"
43 #include "insets/InsetText.h"
44
45 #include "mathed/InsetMath.h"
46 #include "mathed/InsetMathBrace.h"
47 #include "mathed/InsetMathScript.h"
48 #include "mathed/MacroTable.h"
49 #include "mathed/MathData.h"
50 #include "mathed/MathMacro.h"
51
52 #include <boost/bind.hpp>
53
54 #include <sstream>
55 #include <limits>
56 #include <map>
57
58 using namespace std;
59
60 namespace lyx {
61
62 namespace {
63
64 bool positionable(DocIterator const & cursor, DocIterator const & anchor)
65 {
66         // avoid deeper nested insets when selecting
67         if (cursor.depth() > anchor.depth())
68                 return false;
69
70         // anchor might be deeper, should have same path then
71         for (size_t i = 0; i < cursor.depth(); ++i)
72                 if (&cursor[i].inset() != &anchor[i].inset())
73                         return false;
74
75         // position should be ok.
76         return true;
77 }
78
79
80 // Find position closest to (x, y) in cell given by iter.
81 // Used only in mathed
82 DocIterator bruteFind2(Cursor const & c, int x, int y)
83 {
84         double best_dist = numeric_limits<double>::max();
85
86         DocIterator result;
87
88         DocIterator it = c;
89         it.top().pos() = 0;
90         DocIterator et = c;
91         et.top().pos() = et.top().asInsetMath()->cell(et.top().idx()).size();
92         for (size_t i = 0;; ++i) {
93                 int xo;
94                 int yo;
95                 Inset const * inset = &it.inset();
96                 map<Inset const *, Geometry> const & data =
97                         c.bv().coordCache().getInsets().getData();
98                 map<Inset const *, Geometry>::const_iterator I = data.find(inset);
99
100                 // FIXME: in the case where the inset is not in the cache, this
101                 // means that no part of it is visible on screen. In this case
102                 // we don't do elaborate search and we just return the forwarded
103                 // DocIterator at its beginning.
104                 if (I == data.end()) {
105                         it.top().pos() = 0;
106                         return it;
107                 }
108
109                 Point o = I->second.pos;
110                 inset->cursorPos(c.bv(), it.top(), c.boundary(), xo, yo);
111                 // Convert to absolute
112                 xo += o.x_;
113                 yo += o.y_;
114                 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
115                 // '<=' in order to take the last possible position
116                 // this is important for clicking behind \sum in e.g. '\sum_i a'
117                 LYXERR(Debug::DEBUG, "i: " << i << " d: " << d
118                         << " best: " << best_dist);
119                 if (d <= best_dist) {
120                         best_dist = d;
121                         result = it;
122                 }
123                 if (it == et)
124                         break;
125                 it.forwardPos();
126         }
127         return result;
128 }
129
130
131 /*
132 /// moves position closest to (x, y) in given box
133 bool bruteFind(Cursor & cursor,
134         int x, int y, int xlow, int xhigh, int ylow, int yhigh)
135 {
136         LASSERT(!cursor.empty(), return false);
137         Inset & inset = cursor[0].inset();
138         BufferView & bv = cursor.bv();
139
140         CoordCache::InnerParPosCache const & cache =
141                 bv.coordCache().getParPos().find(cursor.bottom().text())->second;
142         // Get an iterator on the first paragraph in the cache
143         DocIterator it(inset);
144         it.push_back(CursorSlice(inset));
145         it.pit() = cache.begin()->first;
146         // Get an iterator after the last paragraph in the cache
147         DocIterator et(inset);
148         et.push_back(CursorSlice(inset));
149         et.pit() = boost::prior(cache.end())->first;
150         if (et.pit() >= et.lastpit())
151                 et = doc_iterator_end(inset);
152         else
153                 ++et.pit();
154
155         double best_dist = numeric_limits<double>::max();;
156         DocIterator best_cursor = et;
157
158         for ( ; it != et; it.forwardPos(true)) {
159                 // avoid invalid nesting when selecting
160                 if (!cursor.selection() || positionable(it, cursor.anchor_)) {
161                         Point p = bv.getPos(it, false);
162                         int xo = p.x_;
163                         int yo = p.y_;
164                         if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
165                                 double const dx = xo - x;
166                                 double const dy = yo - y;
167                                 double const d = dx * dx + dy * dy;
168                                 // '<=' in order to take the last possible position
169                                 // this is important for clicking behind \sum in e.g. '\sum_i a'
170                                 if (d <= best_dist) {
171                                         //      lyxerr << "*" << endl;
172                                         best_dist   = d;
173                                         best_cursor = it;
174                                 }
175                         }
176                 }
177         }
178
179         if (best_cursor != et) {
180                 cursor.setCursor(best_cursor);
181                 return true;
182         }
183
184         return false;
185 }
186 */
187
188
189 /// moves position closest to (x, y) in given box
190 bool bruteFind3(Cursor & cur, int x, int y, bool up)
191 {
192         BufferView & bv = cur.bv();
193         int ylow  = up ? 0 : y + 1;
194         int yhigh = up ? y - 1 : bv.workHeight();
195         int xlow = 0;
196         int xhigh = bv.workWidth();
197
198 // FIXME: bit more work needed to get 'from' and 'to' right.
199         pit_type from = cur.bottom().pit();
200         //pit_type to = cur.bottom().pit();
201         //lyxerr << "Pit start: " << from << endl;
202
203         //lyxerr << "bruteFind3: x: " << x << " y: " << y
204         //      << " xlow: " << xlow << " xhigh: " << xhigh
205         //      << " ylow: " << ylow << " yhigh: " << yhigh
206         //      << endl;
207         DocIterator it = doc_iterator_begin(cur.buffer());
208         it.pit() = from;
209         DocIterator et = doc_iterator_end(cur.buffer());
210
211         double best_dist = numeric_limits<double>::max();
212         DocIterator best_cursor = et;
213
214         for ( ; it != et; it.forwardPos()) {
215                 // avoid invalid nesting when selecting
216                 if (bv.cursorStatus(it) == CUR_INSIDE
217                                 && (!cur.selection() || positionable(it, cur.realAnchor()))) {
218                         // If this function is ever used again, check whether this
219                         // is the same as "bv.getPos(it, false)" with boundary = false.
220                         Point p = bv.getPos(it);
221                         int xo = p.x_;
222                         int yo = p.y_;
223                         if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
224                                 double const dx = xo - x;
225                                 double const dy = yo - y;
226                                 double const d = dx * dx + dy * dy;
227                                 //lyxerr << "itx: " << xo << " ity: " << yo << " d: " << d
228                                 //      << " dx: " << dx << " dy: " << dy
229                                 //      << " idx: " << it.idx() << " pos: " << it.pos()
230                                 //      << " it:\n" << it
231                                 //      << endl;
232                                 // '<=' in order to take the last possible position
233                                 // this is important for clicking behind \sum in e.g. '\sum_i a'
234                                 if (d <= best_dist) {
235                                         //lyxerr << "*" << endl;
236                                         best_dist   = d;
237                                         best_cursor = it;
238                                 }
239                         }
240                 }
241         }
242
243         //lyxerr << "best_dist: " << best_dist << " cur:\n" << best_cursor << endl;
244         if (best_cursor == et)
245                 return false;
246         cur.setCursor(best_cursor);
247         return true;
248 }
249
250 } // namespace anon
251
252
253 // be careful: this is called from the bv's constructor, too, so
254 // bv functions are not yet available!
255 Cursor::Cursor(BufferView & bv)
256         : DocIterator(&bv.buffer()), bv_(&bv), anchor_(),
257           x_target_(-1), textTargetOffset_(0),
258           selection_(false), mark_(false), word_selection_(false),
259           logicalpos_(false), current_font(inherit_font)
260 {}
261
262
263 void Cursor::reset()
264 {
265         clear();
266         push_back(CursorSlice(buffer()->inset()));
267         anchor_ = doc_iterator_begin(buffer());
268         anchor_.clear();
269         clearTargetX();
270         selection_ = false;
271         mark_ = false;
272 }
273
274
275 // this (intentionally) does neither touch anchor nor selection status
276 void Cursor::setCursor(DocIterator const & cur)
277 {
278         DocIterator::operator=(cur);
279 }
280
281
282 bool Cursor::getStatus(FuncRequest const & cmd, FuncStatus & status) const
283 {
284         Cursor cur = *this;
285
286         // Try to fix cursor in case it is broken.
287         cur.fixIfBroken();
288
289         // Is this a function that acts on inset at point?
290         Inset * inset = cur.nextInset();
291         if (lyxaction.funcHasFlag(cmd.action(), LyXAction::AtPoint)
292             && inset && inset->getStatus(cur, cmd, status))
293                 return true;
294
295         // This is, of course, a mess. Better create a new doc iterator and use
296         // this in Inset::getStatus. This might require an additional
297         // BufferView * arg, though (which should be avoided)
298         //Cursor safe = *this;
299         bool res = false;
300         for ( ; cur.depth(); cur.pop()) {
301                 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
302                 LASSERT(cur.idx() <= cur.lastidx(), /**/);
303                 LASSERT(cur.pit() <= cur.lastpit(), /**/);
304                 LASSERT(cur.pos() <= cur.lastpos(), /**/);
305
306                 // The inset's getStatus() will return 'true' if it made
307                 // a definitive decision on whether it want to handle the
308                 // request or not. The result of this decision is put into
309                 // the 'status' parameter.
310                 if (cur.inset().getStatus(cur, cmd, status)) {
311                         res = true;
312                         break;
313                 }
314         }
315         return res;
316 }
317
318
319 void Cursor::saveBeforeDispatchPosXY()
320 {
321         getPos(beforeDispatchPosX_, beforeDispatchPosY_);
322 }
323
324
325 void Cursor::dispatch(FuncRequest const & cmd0)
326 {
327         LYXERR(Debug::DEBUG, "cmd: " << cmd0 << '\n' << *this);
328         if (empty())
329                 return;
330
331         fixIfBroken();
332         FuncRequest cmd = cmd0;
333         Cursor safe = *this;
334
335         buffer()->undo().beginUndoGroup();
336         
337         // Is this a function that acts on inset at point?
338         if (lyxaction.funcHasFlag(cmd.action(), LyXAction::AtPoint)
339             && nextInset()) {
340                 disp_.dispatched(true);
341                 disp_.update(Update::FitCursor | Update::Force);
342                 FuncRequest tmpcmd = cmd;
343                 LYXERR(Debug::DEBUG, "Cursor::dispatch: (AtPoint) cmd: "
344                         << cmd0 << endl << *this);
345                 nextInset()->dispatch(*this, tmpcmd);
346                 if (disp_.dispatched()) {
347                         buffer()->undo().endUndoGroup();
348                         return;
349                 }
350         }
351
352         // store some values to be used inside of the handlers
353         beforeDispatchCursor_ = *this;
354         for (; depth(); pop(), boundary(false)) {
355                 LYXERR(Debug::DEBUG, "Cursor::dispatch: cmd: "
356                         << cmd0 << endl << *this);
357                 LASSERT(pos() <= lastpos(), /**/);
358                 LASSERT(idx() <= lastidx(), /**/);
359                 LASSERT(pit() <= lastpit(), /**/);
360
361                 // The common case is 'LFUN handled, need update', so make the
362                 // LFUN handler's life easier by assuming this as default value.
363                 // The handler can reset the update and val flags if necessary.
364                 disp_.update(Update::FitCursor | Update::Force);
365                 disp_.dispatched(true);
366                 inset().dispatch(*this, cmd);
367                 if (disp_.dispatched())
368                         break;
369         }
370         
371         // it completely to get a 'bomb early' behaviour in case this
372         // object will be used again.
373         if (!disp_.dispatched()) {
374                 LYXERR(Debug::DEBUG, "RESTORING OLD CURSOR!");
375                 // We might have invalidated the cursor when removing an empty
376                 // paragraph while the cursor could not be moved out the inset
377                 // while we initially thought we could. This might happen when
378                 // a multiline inset becomes an inline inset when the second 
379                 // paragraph is removed.
380                 if (safe.pit() > safe.lastpit()) {
381                         safe.pit() = safe.lastpit();
382                         safe.pos() = safe.lastpos();
383                 }
384                 operator=(safe);
385                 disp_.update(Update::None);
386                 disp_.dispatched(false);
387         } else {
388                 // restore the previous one because nested Cursor::dispatch calls
389                 // are possible which would change it
390                 beforeDispatchCursor_ = safe.beforeDispatchCursor_;
391         }
392         buffer()->undo().endUndoGroup();
393 }
394
395
396 DispatchResult const & Cursor::result() const
397 {
398         return disp_;
399 }
400
401
402 BufferView & Cursor::bv() const
403 {
404         LASSERT(bv_, /**/);
405         return *bv_;
406 }
407
408
409 void Cursor::pop()
410 {
411         LASSERT(depth() >= 1, /**/);
412         pop_back();
413 }
414
415
416 void Cursor::push(Inset & p)
417 {
418         push_back(CursorSlice(p));
419         p.setBuffer(*buffer());
420 }
421
422
423 void Cursor::pushBackward(Inset & p)
424 {
425         LASSERT(!empty(), return);
426         //lyxerr << "Entering inset " << t << " front" << endl;
427         push(p);
428         p.idxFirst(*this);
429 }
430
431
432 bool Cursor::popBackward()
433 {
434         LASSERT(!empty(), return false);
435         if (depth() == 1)
436                 return false;
437         pop();
438         return true;
439 }
440
441
442 bool Cursor::popForward()
443 {
444         LASSERT(!empty(), return false);
445         //lyxerr << "Leaving inset from in back" << endl;
446         const pos_type lp = (depth() > 1) ? (*this)[depth() - 2].lastpos() : 0;
447         if (depth() == 1)
448                 return false;
449         pop();
450         pos() += lastpos() - lp + 1;
451         return true;
452 }
453
454
455 int Cursor::currentMode()
456 {
457         LASSERT(!empty(), /**/);
458         for (int i = depth() - 1; i >= 0; --i) {
459                 int res = operator[](i).inset().currentMode();
460                 bool locked_mode = operator[](i).inset().lockedMode();
461                 // Also return UNDECIDED_MODE when the mode is locked,
462                 // as in this case it is treated the same as TEXT_MODE
463                 if (res != Inset::UNDECIDED_MODE || locked_mode)
464                         return res;
465         }
466         return Inset::TEXT_MODE;
467 }
468
469
470 void Cursor::getPos(int & x, int & y) const
471 {
472         Point p = bv().getPos(*this);
473         x = p.x_;
474         y = p.y_;
475 }
476
477
478 Row const & Cursor::textRow() const
479 {
480         CursorSlice const & cs = innerTextSlice();
481         ParagraphMetrics const & pm = bv().parMetrics(cs.text(), cs.pit());
482         LASSERT(!pm.rows().empty(), /**/);
483         return pm.getRow(pos(), boundary());
484 }
485
486
487 void Cursor::resetAnchor()
488 {
489         anchor_ = *this;
490 }
491
492
493 void Cursor::setCursorToAnchor()
494 {
495         if (selection()) {
496                 DocIterator normal = anchor_;
497                 while (depth() < normal.depth())
498                         normal.pop_back();
499                 if (depth() < anchor_.depth() && top() <= anchor_[depth() - 1])
500                         ++normal.pos();
501                 setCursor(normal);
502         }
503 }
504
505
506 bool Cursor::posBackward()
507 {
508         if (pos() == 0)
509                 return false;
510         --pos();
511         return true;
512 }
513
514
515 bool Cursor::posForward()
516 {
517         if (pos() == lastpos())
518                 return false;
519         ++pos();
520         return true;
521 }
522
523
524 bool Cursor::posVisRight(bool skip_inset)
525 {
526         Cursor new_cur = *this; // where we will move to
527         pos_type left_pos; // position visually left of current cursor
528         pos_type right_pos; // position visually right of current cursor
529         bool new_pos_is_RTL; // is new position we're moving to RTL?
530
531         getSurroundingPos(left_pos, right_pos);
532
533         LYXERR(Debug::RTL, left_pos <<"|"<< right_pos << " (pos: "<< pos() <<")");
534
535         // Are we at an inset?
536         new_cur.pos() = right_pos;
537         new_cur.boundary(false);
538         if (!skip_inset &&
539                 text()->checkAndActivateInsetVisual(new_cur, right_pos >= pos(), false)) {
540                 // we actually move the cursor at the end of this function, for now
541                 // we just keep track of the new position in new_cur...
542                 LYXERR(Debug::RTL, "entering inset at: " << new_cur.pos());
543         }
544
545         // Are we already at rightmost pos in row?
546         else if (text()->empty() || right_pos == -1) {
547                 
548                 new_cur = *this;
549                 if (!new_cur.posVisToNewRow(false)) {
550                         LYXERR(Debug::RTL, "not moving!");
551                         return false;
552                 }
553                 
554                 // we actually move the cursor at the end of this function, for now 
555                 // just keep track of the new position in new_cur...
556                 LYXERR(Debug::RTL, "right edge, moving: " << int(new_cur.pit()) << "," 
557                         << int(new_cur.pos()) << "," << (new_cur.boundary() ? 1 : 0));
558
559         }
560         // normal movement to the right
561         else {
562                 new_cur = *this;
563                 // Recall, if the cursor is at position 'x', that means *before* 
564                 // the character at position 'x'. In RTL, "before" means "to the 
565                 // right of", in LTR, "to the left of". So currently our situation
566                 // is this: the position to our right is 'right_pos' (i.e., we're 
567                 // currently to the left of 'right_pos'). In order to move to the 
568                 // right, it depends whether or not the character at 'right_pos' is RTL.
569                 new_pos_is_RTL = paragraph().getFontSettings(
570                         buffer()->params(), right_pos).isVisibleRightToLeft();
571                 // If the character at 'right_pos' *is* LTR, then in order to move to
572                 // the right of it, we need to be *after* 'right_pos', i.e., move to
573                 // position 'right_pos' + 1.
574                 if (!new_pos_is_RTL) {
575                         new_cur.pos() = right_pos + 1;
576                         // set the boundary to true in two situations:
577                         if (
578                         // 1. if new_pos is now lastpos, and we're in an RTL paragraph
579                         // (this means that we're moving right to the end of an LTR chunk
580                         // which is at the end of an RTL paragraph);
581                                 (new_cur.pos() == lastpos()
582                                  && paragraph().isRTL(buffer()->params()))
583                         // 2. if the position *after* right_pos is RTL (we want to be 
584                         // *after* right_pos, not before right_pos + 1!)
585                                 || paragraph().getFontSettings(buffer()->params(),
586                                                 new_cur.pos()).isVisibleRightToLeft()
587                         )
588                                 new_cur.boundary(true);
589                         else // set the boundary to false
590                                 new_cur.boundary(false);
591                 }
592                 // Otherwise (if the character at position 'right_pos' is RTL), then
593                 // moving to the right of it is as easy as setting the new position
594                 // to 'right_pos'.
595                 else {
596                         new_cur.pos() = right_pos;
597                         new_cur.boundary(false);
598                 }
599         
600         }
601
602         bool moved = (new_cur.pos() != pos()
603                                   || new_cur.pit() != pit()
604                                   || new_cur.boundary() != boundary()
605                                   || &new_cur.inset() != &inset());
606         
607         if (moved) {
608                 LYXERR(Debug::RTL, "moving to: " << new_cur.pos() 
609                         << (new_cur.boundary() ? " (boundary)" : ""));
610                 *this = new_cur;
611         }
612
613         return moved;
614 }
615
616
617 bool Cursor::posVisLeft(bool skip_inset)
618 {
619         Cursor new_cur = *this; // where we will move to
620         pos_type left_pos; // position visually left of current cursor
621         pos_type right_pos; // position visually right of current cursor
622         bool new_pos_is_RTL; // is new position we're moving to RTL?
623
624         getSurroundingPos(left_pos, right_pos);
625
626         LYXERR(Debug::RTL, left_pos <<"|"<< right_pos << " (pos: "<< pos() <<")");
627
628         // Are we at an inset?
629         new_cur.pos() = left_pos;
630         new_cur.boundary(false);
631         if (!skip_inset && 
632                 text()->checkAndActivateInsetVisual(new_cur, left_pos >= pos(), true)) {
633                 // we actually move the cursor at the end of this function, for now 
634                 // we just keep track of the new position in new_cur...
635                 LYXERR(Debug::RTL, "entering inset at: " << new_cur.pos());
636         }
637
638         // Are we already at leftmost pos in row?
639         else if (text()->empty() || left_pos == -1) {
640                 
641                 new_cur = *this;
642                 if (!new_cur.posVisToNewRow(true)) {
643                         LYXERR(Debug::RTL, "not moving!");
644                         return false;
645                 }
646                 
647                 // we actually move the cursor at the end of this function, for now 
648                 // just keep track of the new position in new_cur...
649                 LYXERR(Debug::RTL, "left edge, moving: " << int(new_cur.pit()) << "," 
650                         << int(new_cur.pos()) << "," << (new_cur.boundary() ? 1 : 0));
651
652         }
653         // normal movement to the left
654         else {
655                 new_cur = *this;
656                 // Recall, if the cursor is at position 'x', that means *before* 
657                 // the character at position 'x'. In RTL, "before" means "to the 
658                 // right of", in LTR, "to the left of". So currently our situation
659                 // is this: the position to our left is 'left_pos' (i.e., we're 
660                 // currently to the right of 'left_pos'). In order to move to the 
661                 // left, it depends whether or not the character at 'left_pos' is RTL.
662                 new_pos_is_RTL = paragraph().getFontSettings(
663                         buffer()->params(), left_pos).isVisibleRightToLeft();
664                 // If the character at 'left_pos' *is* RTL, then in order to move to
665                 // the left of it, we need to be *after* 'left_pos', i.e., move to
666                 // position 'left_pos' + 1.
667                 if (new_pos_is_RTL) {
668                         new_cur.pos() = left_pos + 1;
669                         // set the boundary to true in two situations:
670                         if (
671                         // 1. if new_pos is now lastpos and we're in an LTR paragraph
672                         // (this means that we're moving left to the end of an RTL chunk
673                         // which is at the end of an LTR paragraph);
674                                 (new_cur.pos() == lastpos()
675                                  && !paragraph().isRTL(buffer()->params()))
676                         // 2. if the position *after* left_pos is not RTL (we want to be 
677                         // *after* left_pos, not before left_pos + 1!)
678                                 || !paragraph().getFontSettings(buffer()->params(),
679                                                 new_cur.pos()).isVisibleRightToLeft()
680                         )
681                                 new_cur.boundary(true);
682                         else // set the boundary to false
683                                 new_cur.boundary(false);
684                 }
685                 // Otherwise (if the character at position 'left_pos' is LTR), then
686                 // moving to the left of it is as easy as setting the new position
687                 // to 'left_pos'.
688                 else {
689                         new_cur.pos() = left_pos;
690                         new_cur.boundary(false);
691                 }
692         
693         }
694
695         bool moved = (new_cur.pos() != pos() 
696                                   || new_cur.pit() != pit()
697                                   || new_cur.boundary() != boundary());
698
699         if (moved) {
700                 LYXERR(Debug::RTL, "moving to: " << new_cur.pos() 
701                         << (new_cur.boundary() ? " (boundary)" : ""));
702                 *this = new_cur;
703         }
704                 
705         return moved;
706 }
707
708
709 void Cursor::getSurroundingPos(pos_type & left_pos, pos_type & right_pos)
710 {
711         // preparing bidi tables
712         Paragraph const & par = paragraph();
713         Buffer const & buf = *buffer();
714         Row const & row = textRow();
715         Bidi bidi;
716         bidi.computeTables(par, buf, row);
717
718         LYXERR(Debug::RTL, "bidi: " << row.pos() << "--" << row.endpos());
719
720         // The cursor is painted *before* the character at pos(), or, if 'boundary'
721         // is true, *after* the character at (pos() - 1). So we already have one
722         // known position around the cursor:
723         pos_type const known_pos = boundary() && pos() > 0 ? pos() - 1 : pos();
724         
725         // edge case: if we're at the end of the paragraph, things are a little 
726         // different (because lastpos is a position which does not really "exist" 
727         // --- there's no character there yet).
728         if (known_pos == lastpos()) {
729                 if (par.isRTL(buf.params())) {
730                         left_pos = -1;
731                         right_pos = bidi.vis2log(row.pos());
732                 } else { 
733                         // LTR paragraph
734                         right_pos = -1;
735                         left_pos = bidi.vis2log(row.endpos() - 1);
736                 }
737                 return;
738         }
739         
740         // Whether 'known_pos' is to the left or to the right of the cursor depends
741         // on whether it is an RTL or LTR character...
742         bool const cur_is_RTL = 
743                 par.getFontSettings(buf.params(), known_pos).isVisibleRightToLeft();
744         // ... in the following manner:
745         // For an RTL character, "before" means "to the right" and "after" means
746         // "to the left"; and for LTR, it's the reverse. So, 'known_pos' is to the
747         // right of the cursor if (RTL && boundary) or (!RTL && !boundary):
748         bool const known_pos_on_right = cur_is_RTL == boundary();
749
750         // So we now know one of the positions surrounding the cursor. Let's 
751         // determine the other one:     
752         if (known_pos_on_right) {
753                 right_pos = known_pos;
754                 // *visual* position of 'left_pos':
755                 pos_type v_left_pos = bidi.log2vis(right_pos) - 1;
756                 // If the position we just identified as 'left_pos' is a "skipped 
757                 // separator" (a separator which is at the logical end of a row,
758                 // except for the last row in a paragraph; such separators are not
759                 // painted, so they "are not really there"; note that in bidi text,
760                 // such a separator could appear visually in the middle of a row),
761                 // set 'left_pos' to the *next* position to the left.
762                 if (bidi.inRange(v_left_pos) 
763                                 && bidi.vis2log(v_left_pos) + 1 == row.endpos() 
764                                 && row.endpos() < lastpos()
765                                 && par.isSeparator(bidi.vis2log(v_left_pos)))
766                         --v_left_pos;
767
768                 // calculate the logical position of 'left_pos', if in row
769                 if (!bidi.inRange(v_left_pos))
770                         left_pos = -1;
771                 else
772                         left_pos = bidi.vis2log(v_left_pos);
773                 // If the position we identified as 'right_pos' is a "skipped 
774                 // separator", set 'right_pos' to the *next* position to the right.
775                 if (right_pos + 1 == row.endpos() && row.endpos() < lastpos() 
776                                 && par.isSeparator(right_pos)) {
777                         pos_type const v_right_pos = bidi.log2vis(right_pos) + 1;
778                         if (!bidi.inRange(v_right_pos))
779                                 right_pos = -1;
780                         else
781                                 right_pos = bidi.vis2log(v_right_pos);
782                 }
783         } else { 
784                 // known_pos is on the left
785                 left_pos = known_pos;
786                 // *visual* position of 'right_pos'
787                 pos_type v_right_pos = bidi.log2vis(left_pos) + 1;
788                 // If the position we just identified as 'right_pos' is a "skipped 
789                 // separator", set 'right_pos' to the *next* position to the right.
790                 if (bidi.inRange(v_right_pos) 
791                                 && bidi.vis2log(v_right_pos) + 1 == row.endpos() 
792                                 && row.endpos() < lastpos()
793                                 && par.isSeparator(bidi.vis2log(v_right_pos)))
794                         ++v_right_pos;
795
796                 // calculate the logical position of 'right_pos', if in row
797                 if (!bidi.inRange(v_right_pos)) 
798                         right_pos = -1;
799                 else
800                         right_pos = bidi.vis2log(v_right_pos);
801                 // If the position we identified as 'left_pos' is a "skipped 
802                 // separator", set 'left_pos' to the *next* position to the left.
803                 if (left_pos + 1 == row.endpos() && row.endpos() < lastpos() 
804                                 && par.isSeparator(left_pos)) {
805                         pos_type const v_left_pos = bidi.log2vis(left_pos) - 1;
806                         if (!bidi.inRange(v_left_pos))
807                                 left_pos = -1;
808                         else
809                                 left_pos = bidi.vis2log(v_left_pos);
810                 }
811         }
812         return;
813 }
814
815
816 bool Cursor::posVisToNewRow(bool movingLeft)
817 {
818         Paragraph const & par = paragraph();
819         Buffer const & buf = *buffer();
820         Row const & row = textRow();
821         bool par_is_LTR = !par.isRTL(buf.params());
822
823         // Inside a table, determining whether to move to the next or previous row
824         // should be done based on the table's direction. 
825         int s = depth() - 1;
826         if (s >= 1 && (*this)[s].inset().asInsetTabular()) {
827                 par_is_LTR = !(*this)[s].inset().asInsetTabular()->isRightToLeft(*this);
828                 LYXERR(Debug::RTL, "Inside table! par_is_LTR=" << (par_is_LTR ? 1 : 0));
829         }
830         
831         // if moving left in an LTR paragraph or moving right in an RTL one, 
832         // move to previous row
833         if (par_is_LTR == movingLeft) {
834                 if (row.pos() == 0) { // we're at first row in paragraph
835                         if (pit() == 0) // no previous paragraph! don't move
836                                 return false;
837                         // move to last pos in previous par
838                         --pit();
839                         pos() = lastpos();
840                         boundary(false);
841                 } else { // move to previous row in this par
842                         pos() = row.pos() - 1; // this is guaranteed to be in previous row
843                         boundary(false);
844                 }
845         }
846         // if moving left in an RTL paragraph or moving right in an LTR one, 
847         // move to next row
848         else {
849                 if (row.endpos() == lastpos()) { // we're at last row in paragraph
850                         if (pit() == lastpit()) // last paragraph! don't move
851                                 return false;
852                         // move to first row in next par
853                         ++pit();
854                         pos() = 0;
855                         boundary(false);
856                 } else { // move to next row in this par
857                         pos() = row.endpos();
858                         boundary(false);
859                 }
860         }
861         
862         // make sure we're at left-/right-most pos in new row
863         posVisToRowExtremity(!movingLeft);
864
865         return true;
866 }
867
868
869 void Cursor::posVisToRowExtremity(bool left)  
870 {
871         // prepare bidi tables
872         Paragraph const & par = paragraph();
873         Buffer const & buf = *buffer();
874         Row const & row = textRow();
875         Bidi bidi;
876         bidi.computeTables(par, buf, row);
877
878         LYXERR(Debug::RTL, "entering extremity: " << pit() << "," << pos() << ","
879                 << (boundary() ? 1 : 0));
880
881         if (left) { // move to leftmost position
882                 // if this is an RTL paragraph, and we're at the last row in the
883                 // paragraph, move to lastpos
884                 if (par.isRTL(buf.params()) && row.endpos() == lastpos())
885                         pos() = lastpos();
886                 else {
887                         pos() = bidi.vis2log(row.pos());
888
889                         // Moving to the leftmost position in the row, the cursor should
890                         // normally be placed to the *left* of the leftmost position.
891                         // A very common exception, though, is if the leftmost character 
892                         // also happens to be the separator at the (logical) end of the row
893                         // --- in this case, the separator is positioned beyond the left 
894                         // margin, and we don't want to move the cursor there (moving to 
895                         // the left of the separator is equivalent to moving to the next
896                         // line). So, in this case we actually want to place the cursor 
897                         // to the *right* of the leftmost position (the separator). 
898                         // Another exception is if we're moving to the logically last 
899                         // position in the row, which is *not* a separator: this means
900                         // that the entire row has no separators (if there were any, the 
901                         // row would have been broken there); and therefore in this case
902                         // we also move to the *right* of the last position (this indicates
903                         // to the user that there is no space after this position, and is 
904                         // consistent with the behavior in the middle of a row --- moving
905                         // right or left moves to the next/previous character; if we were
906                         // to move to the *left* of this position, that would simulate 
907                         // a separator which is not really there!). 
908                         // Finally, there is an exception to the previous exception: if 
909                         // this non-separator-but-last-position-in-row is an inset, then
910                         // we *do* want to stay to the left of it anyway: this is the 
911                         // "boundary" which we simulate at insets.
912                         // Another exception is when row.endpos() is 0.
913                         
914                         // do we want to be to the right of pos?
915                         // as explained above, if at last pos in row, stay to the right
916                         bool const right_of_pos = row.endpos() > 0
917                                 && pos() == row.endpos() - 1 && !par.isInset(pos());
918
919                         // Now we know if we want to be to the left or to the right of pos,
920                         // let's make sure we are where we want to be.
921                         bool const new_pos_is_RTL = 
922                                 par.getFontSettings(buf.params(), pos()).isVisibleRightToLeft();
923
924                         if (new_pos_is_RTL != right_of_pos) {
925                                 ++pos();
926                                 boundary(true);
927                         }
928                 }
929         } else { 
930                 // move to rightmost position
931                 // if this is an LTR paragraph, and we're at the last row in the
932                 // paragraph, move to lastpos
933                 if (!par.isRTL(buf.params()) && row.endpos() == lastpos())
934                         pos() = lastpos();
935                 else {
936                         pos() = row.endpos() > 0 ? bidi.vis2log(row.endpos() - 1) : 0;
937
938                         // Moving to the rightmost position in the row, the cursor should
939                         // normally be placed to the *right* of the rightmost position.
940                         // A very common exception, though, is if the rightmost character 
941                         // also happens to be the separator at the (logical) end of the row
942                         // --- in this case, the separator is positioned beyond the right 
943                         // margin, and we don't want to move the cursor there (moving to 
944                         // the right of the separator is equivalent to moving to the next
945                         // line). So, in this case we actually want to place the cursor 
946                         // to the *left* of the rightmost position (the separator). 
947                         // Another exception is if we're moving to the logically last 
948                         // position in the row, which is *not* a separator: this means
949                         // that the entire row has no separators (if there were any, the 
950                         // row would have been broken there); and therefore in this case
951                         // we also move to the *left* of the last position (this indicates
952                         // to the user that there is no space after this position, and is 
953                         // consistent with the behavior in the middle of a row --- moving
954                         // right or left moves to the next/previous character; if we were
955                         // to move to the *right* of this position, that would simulate 
956                         // a separator which is not really there!). 
957                         // Finally, there is an exception to the previous exception: if 
958                         // this non-separator-but-last-position-in-row is an inset, then
959                         // we *do* want to stay to the right of it anyway: this is the 
960                         // "boundary" which we simulate at insets.
961                         // Another exception is when row.endpos() is 0.
962                         
963                         // do we want to be to the left of pos?
964                         // as explained above, if at last pos in row, stay to the left,
965                         // unless the last position is the same as the first.
966                         bool const left_of_pos = row.endpos() > 0
967                                 && pos() == row.endpos() - 1 && !par.isInset(pos());
968
969                         // Now we know if we want to be to the left or to the right of pos,
970                         // let's make sure we are where we want to be.
971                         bool const new_pos_is_RTL = 
972                                 par.getFontSettings(buf.params(), pos()).isVisibleRightToLeft();
973
974                         if (new_pos_is_RTL == left_of_pos) {
975                                 ++pos();
976                                 boundary(true);
977                         }
978                 }
979         }
980         LYXERR(Debug::RTL, "leaving extremity: " << pit() << "," << pos() << ","
981                 << (boundary() ? 1 : 0));
982 }
983
984
985 CursorSlice Cursor::normalAnchor() const
986 {
987         if (!selection())
988                 return top();
989         LASSERT(anchor_.depth() >= depth(), /**/);
990         CursorSlice normal = anchor_[depth() - 1];
991         if (depth() < anchor_.depth() && top() <= normal) {
992                 // anchor is behind cursor -> move anchor behind the inset
993                 ++normal.pos();
994         }
995         return normal;
996 }
997
998
999 DocIterator & Cursor::realAnchor()
1000 {
1001         return anchor_;
1002 }
1003
1004
1005 CursorSlice Cursor::selBegin() const
1006 {
1007         if (!selection())
1008                 return top();
1009         return normalAnchor() < top() ? normalAnchor() : top();
1010 }
1011
1012
1013 CursorSlice Cursor::selEnd() const
1014 {
1015         if (!selection())
1016                 return top();
1017         return normalAnchor() > top() ? normalAnchor() : top();
1018 }
1019
1020
1021 DocIterator Cursor::selectionBegin() const
1022 {
1023         if (!selection())
1024                 return *this;
1025
1026         DocIterator di;
1027         // FIXME: This is a work-around for the problem that
1028         // CursorSlice doesn't keep track of the boundary.
1029         if (normalAnchor() == top())
1030                 di = anchor_.boundary() > boundary() ? anchor_ : *this;
1031         else
1032                 di = normalAnchor() < top() ? anchor_ : *this;
1033         di.resize(depth());
1034         return di;
1035 }
1036
1037
1038 DocIterator Cursor::selectionEnd() const
1039 {
1040         if (!selection())
1041                 return *this;
1042
1043         DocIterator di;
1044         // FIXME: This is a work-around for the problem that
1045         // CursorSlice doesn't keep track of the boundary.
1046         if (normalAnchor() == top())
1047                 di = anchor_.boundary() < boundary() ? anchor_ : *this;
1048         else
1049                 di = normalAnchor() > top() ? anchor_ : *this;
1050
1051         if (di.depth() > depth()) {
1052                 di.resize(depth());
1053                 ++di.pos();
1054         }
1055         return di;
1056 }
1057
1058
1059 void Cursor::setSelection()
1060 {
1061         setSelection(true);
1062         // A selection with no contents is not a selection
1063         // FIXME: doesnt look ok
1064         if (idx() == normalAnchor().idx() && 
1065             pit() == normalAnchor().pit() && 
1066             pos() == normalAnchor().pos())
1067                 setSelection(false);
1068 }
1069
1070
1071 void Cursor::setSelection(DocIterator const & where, int n)
1072 {
1073         setCursor(where);
1074         setSelection(true);
1075         anchor_ = where;
1076         pos() += n;
1077 }
1078
1079
1080 void Cursor::clearSelection()
1081 {
1082         setSelection(false);
1083         setWordSelection(false);
1084         setMark(false);
1085         resetAnchor();
1086 }
1087
1088
1089 void Cursor::setTargetX(int x)
1090 {
1091         x_target_ = x;
1092         textTargetOffset_ = 0;
1093 }
1094
1095
1096 int Cursor::x_target() const
1097 {
1098         return x_target_;
1099 }
1100
1101
1102 void Cursor::clearTargetX()
1103 {
1104         x_target_ = -1;
1105         textTargetOffset_ = 0;
1106 }
1107
1108
1109 void Cursor::updateTextTargetOffset()
1110 {
1111         int x;
1112         int y;
1113         getPos(x, y);
1114         textTargetOffset_ = x - x_target_;
1115 }
1116
1117
1118 void Cursor::info(odocstream & os) const
1119 {
1120         for (int i = 1, n = depth(); i < n; ++i) {
1121                 operator[](i).inset().infoize(os);
1122                 os << "  ";
1123         }
1124         if (pos() != 0) {
1125                 Inset const * inset = prevInset();
1126                 // prevInset() can return 0 in certain case.
1127                 if (inset)
1128                         prevInset()->infoize2(os);
1129         }
1130         // overwite old message
1131         os << "                    ";
1132 }
1133
1134
1135 bool Cursor::selHandle(bool sel)
1136 {
1137         //lyxerr << "Cursor::selHandle" << endl;
1138         if (mark())
1139                 sel = true;
1140         if (sel == selection())
1141                 return false;
1142
1143         if (!sel)
1144                 cap::saveSelection(*this);
1145
1146         resetAnchor();
1147         setSelection(sel);
1148         return true;
1149 }
1150
1151
1152 ostream & operator<<(ostream & os, Cursor const & cur)
1153 {
1154         os << "\n cursor:                                | anchor:\n";
1155         for (size_t i = 0, n = cur.depth(); i != n; ++i) {
1156                 os << " " << cur[i] << " | ";
1157                 if (i < cur.anchor_.depth())
1158                         os << cur.anchor_[i];
1159                 else
1160                         os << "-------------------------------";
1161                 os << "\n";
1162         }
1163         for (size_t i = cur.depth(), n = cur.anchor_.depth(); i < n; ++i) {
1164                 os << "------------------------------- | " << cur.anchor_[i] << "\n";
1165         }
1166         os << " selection: " << cur.selection_
1167            << " x_target: " << cur.x_target_ << endl;
1168         return os;
1169 }
1170
1171
1172 LyXErr & operator<<(LyXErr & os, Cursor const & cur)
1173 {
1174         os.stream() << cur;
1175         return os;
1176 }
1177
1178
1179 } // namespace lyx
1180
1181
1182 ///////////////////////////////////////////////////////////////////
1183 //
1184 // FIXME: Look here
1185 // The part below is the non-integrated rest of the original math
1186 // cursor. This should be either generalized for texted or moved
1187 // back to mathed (in most cases to InsetMathNest).
1188 //
1189 ///////////////////////////////////////////////////////////////////
1190
1191 #include "mathed/InsetMathChar.h"
1192 #include "mathed/InsetMathGrid.h"
1193 #include "mathed/InsetMathScript.h"
1194 #include "mathed/InsetMathUnknown.h"
1195 #include "mathed/MathFactory.h"
1196 #include "mathed/MathStream.h"
1197 #include "mathed/MathSupport.h"
1198
1199
1200 namespace lyx {
1201
1202 //#define FILEDEBUG 1
1203
1204
1205 bool Cursor::isInside(Inset const * p) const
1206 {
1207         for (size_t i = 0; i != depth(); ++i)
1208                 if (&operator[](i).inset() == p)
1209                         return true;
1210         return false;
1211 }
1212
1213
1214 void Cursor::leaveInset(Inset const & inset)
1215 {
1216         for (size_t i = 0; i != depth(); ++i) {
1217                 if (&operator[](i).inset() == &inset) {
1218                         resize(i);
1219                         return;
1220                 }
1221         }
1222 }
1223
1224
1225 bool Cursor::openable(MathAtom const & t) const
1226 {
1227         if (!t->isActive())
1228                 return false;
1229
1230         if (t->lock())
1231                 return false;
1232
1233         if (!selection())
1234                 return true;
1235
1236         // we can't move into anything new during selection
1237         if (depth() >= anchor_.depth())
1238                 return false;
1239         if (t.nucleus() != &anchor_[depth()].inset())
1240                 return false;
1241
1242         return true;
1243 }
1244
1245
1246 void Cursor::setScreenPos(int x, int /*y*/)
1247 {
1248         setTargetX(x);
1249         //bruteFind(*this, x, y, 0, bv().workWidth(), 0, bv().workHeight());
1250 }
1251
1252
1253
1254 void Cursor::plainErase()
1255 {
1256         cell().erase(pos());
1257 }
1258
1259
1260 void Cursor::markInsert()
1261 {
1262         insert(char_type(0));
1263 }
1264
1265
1266 void Cursor::markErase()
1267 {
1268         cell().erase(pos());
1269 }
1270
1271
1272 void Cursor::plainInsert(MathAtom const & t)
1273 {
1274         cell().insert(pos(), t);
1275         ++pos();
1276         inset().setBuffer(bv_->buffer());
1277         inset().initView();
1278 }
1279
1280
1281 void Cursor::insert(docstring const & str)
1282 {
1283         for_each(str.begin(), str.end(),
1284                  boost::bind(static_cast<void(Cursor::*)(char_type)>
1285                              (&Cursor::insert), this, _1));
1286 }
1287
1288
1289 void Cursor::insert(char_type c)
1290 {
1291         //lyxerr << "Cursor::insert char '" << c << "'" << endl;
1292         LASSERT(!empty(), /**/);
1293         if (inMathed()) {
1294                 cap::selClearOrDel(*this);
1295                 insert(new InsetMathChar(c));
1296         } else {
1297                 text()->insertChar(*this, c);
1298         }
1299 }
1300
1301
1302 void Cursor::insert(MathAtom const & t)
1303 {
1304         //lyxerr << "Cursor::insert MathAtom '" << t << "'" << endl;
1305         macroModeClose();
1306         cap::selClearOrDel(*this);
1307         plainInsert(t);
1308 }
1309
1310
1311 void Cursor::insert(Inset * inset0)
1312 {
1313         LASSERT(inset0, /**/);
1314         if (inMathed())
1315                 insert(MathAtom(inset0));
1316         else {
1317                 text()->insertInset(*this, inset0);
1318                 inset0->setBuffer(bv_->buffer());
1319                 inset0->initView();
1320         }
1321 }
1322
1323
1324 void Cursor::niceInsert(docstring const & t, Parse::flags f, bool enter)
1325 {
1326         MathData ar(buffer());
1327         asArray(t, ar, f);
1328         if (ar.size() == 1 && (enter || selection()))
1329                 niceInsert(ar[0]);
1330         else
1331                 insert(ar);
1332 }
1333
1334
1335 void Cursor::niceInsert(MathAtom const & t)
1336 {
1337         macroModeClose();
1338         docstring const safe = cap::grabAndEraseSelection(*this);
1339         plainInsert(t);
1340         // If possible, enter the new inset and move the contents of the selection
1341         if (t->isActive()) {
1342                 posBackward();
1343                 // be careful here: don't use 'pushBackward(t)' as this we need to
1344                 // push the clone, not the original
1345                 pushBackward(*nextInset());
1346                 // We may not use niceInsert here (recursion)
1347                 MathData ar(buffer());
1348                 asArray(safe, ar);
1349                 insert(ar);
1350         }
1351 }
1352
1353
1354 void Cursor::insert(MathData const & ar)
1355 {
1356         macroModeClose();
1357         if (selection())
1358                 cap::eraseSelection(*this);
1359         cell().insert(pos(), ar);
1360         pos() += ar.size();
1361         // FIXME audit setBuffer/updateBuffer calls
1362         inset().setBuffer(bv_->buffer());
1363 }
1364
1365
1366 bool Cursor::backspace()
1367 {
1368         autocorrect() = false;
1369
1370         if (selection()) {
1371                 cap::eraseSelection(*this);
1372                 return true;
1373         }
1374
1375         if (pos() == 0) {
1376                 // If empty cell, and not part of a big cell
1377                 if (lastpos() == 0 && inset().nargs() == 1) {
1378                         popBackward();
1379                         // Directly delete empty cell: [|[]] => [|]
1380                         if (inMathed()) {
1381                                 plainErase();
1382                                 resetAnchor();
1383                                 return true;
1384                         }
1385                         // [|], can not delete from inside
1386                         return false;
1387                 } else {
1388                         if (inMathed())
1389                                 pullArg();
1390                         else
1391                                 popBackward();
1392                         return true;
1393                 }
1394         }
1395
1396         if (inMacroMode()) {
1397                 InsetMathUnknown * p = activeMacro();
1398                 if (p->name().size() > 1) {
1399                         p->setName(p->name().substr(0, p->name().size() - 1));
1400                         return true;
1401                 }
1402         }
1403
1404         if (pos() != 0 && prevAtom()->nargs() > 0) {
1405                 // let's require two backspaces for 'big stuff' and
1406                 // highlight on the first
1407                 resetAnchor();
1408                 setSelection(true);
1409                 --pos();
1410         } else {
1411                 --pos();
1412                 plainErase();
1413         }
1414         return true;
1415 }
1416
1417
1418 bool Cursor::erase()
1419 {
1420         autocorrect() = false;
1421         if (inMacroMode())
1422                 return true;
1423
1424         if (selection()) {
1425                 cap::eraseSelection(*this);
1426                 return true;
1427         }
1428
1429         // delete empty cells if possible
1430         if (pos() == lastpos() && inset().idxDelete(idx()))
1431                 return true;
1432
1433         // special behaviour when in last position of cell
1434         if (pos() == lastpos()) {
1435                 bool one_cell = inset().nargs() == 1;
1436                 if (one_cell && lastpos() == 0) {
1437                         popBackward();
1438                         // Directly delete empty cell: [|[]] => [|]
1439                         if (inMathed()) {
1440                                 plainErase();
1441                                 resetAnchor();
1442                                 return true;
1443                         }
1444                         // [|], can not delete from inside
1445                         return false;
1446                 }
1447                 // remove markup
1448                 if (!one_cell)
1449                         inset().idxGlue(idx());
1450                 return true;
1451         }
1452
1453         // 'clever' UI hack: only erase large items if previously slected
1454         if (pos() != lastpos() && nextAtom()->nargs() > 0) {
1455                 resetAnchor();
1456                 setSelection(true);
1457                 ++pos();
1458         } else {
1459                 plainErase();
1460         }
1461
1462         return true;
1463 }
1464
1465
1466 bool Cursor::up()
1467 {
1468         macroModeClose();
1469         DocIterator save = *this;
1470         FuncRequest cmd(selection() ? LFUN_UP_SELECT : LFUN_UP, docstring());
1471         this->dispatch(cmd);
1472         if (disp_.dispatched())
1473                 return true;
1474         setCursor(save);
1475         autocorrect() = false;
1476         return false;
1477 }
1478
1479
1480 bool Cursor::down()
1481 {
1482         macroModeClose();
1483         DocIterator save = *this;
1484         FuncRequest cmd(selection() ? LFUN_DOWN_SELECT : LFUN_DOWN, docstring());
1485         this->dispatch(cmd);
1486         if (disp_.dispatched())
1487                 return true;
1488         setCursor(save);
1489         autocorrect() = false;
1490         return false;
1491 }
1492
1493
1494 bool Cursor::macroModeClose()
1495 {
1496         if (!inMacroMode())
1497                 return false;
1498         InsetMathUnknown * p = activeMacro();
1499         p->finalize();
1500         MathData selection(buffer());
1501         asArray(p->selection(), selection);
1502         docstring const s = p->name();
1503         --pos();
1504         cell().erase(pos());
1505
1506         // do nothing if the macro name is empty
1507         if (s == "\\")
1508                 return false;
1509
1510         // trigger updates of macros, at least, if no full
1511         // updates take place anyway
1512         updateFlags(Update::Force);
1513
1514         docstring const name = s.substr(1);
1515         InsetMathNest * const in = inset().asInsetMath()->asNestInset();
1516         if (in && in->interpretString(*this, s))
1517                 return true;
1518         MathAtom atom = buffer()->getMacro(name, *this, false) ?
1519                 MathAtom(new MathMacro(buffer(), name)) : createInsetMath(name, buffer());
1520
1521         // try to put argument into macro, if we just inserted a macro
1522         bool macroArg = false;
1523         MathMacro * atomAsMacro = atom.nucleus()->asMacro();
1524         if (atomAsMacro) {
1525                 // macros here are still unfolded (in init mode in fact). So
1526                 // we have to resolve the macro here manually and check its arity
1527                 // to put the selection behind it if arity > 0.
1528                 MacroData const * data = buffer()->getMacro(atomAsMacro->name());
1529                 if (selection.size() > 0 && data && data->numargs() - data->optionals() > 0) {
1530                         macroArg = true;
1531                         atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 1);
1532                 } else
1533                         // non-greedy case. Do not touch the arguments behind
1534                         atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 0);
1535         }
1536
1537         // insert remembered selection into first argument of a non-macro
1538         else if (atom.nucleus()->nargs() > 0)
1539                 atom.nucleus()->cell(0).append(selection);
1540         
1541         plainInsert(atom);
1542
1543         // finally put the macro argument behind, if needed
1544         if (macroArg) {
1545                 if (selection.size() > 1 || selection[0]->asScriptInset())
1546                         plainInsert(MathAtom(new InsetMathBrace(selection)));
1547                 else
1548                         insert(selection);
1549         }
1550         
1551         return true;
1552 }
1553
1554
1555 docstring Cursor::macroName()
1556 {
1557         return inMacroMode() ? activeMacro()->name() : docstring();
1558 }
1559
1560
1561 void Cursor::handleNest(MathAtom const & a, int c)
1562 {
1563         //lyxerr << "Cursor::handleNest: " << c << endl;
1564         MathAtom t = a;
1565         asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c));
1566         insert(t);
1567         posBackward();
1568         pushBackward(*nextInset());
1569 }
1570
1571
1572 int Cursor::targetX() const
1573 {
1574         if (x_target() != -1)
1575                 return x_target();
1576         int x = 0;
1577         int y = 0;
1578         getPos(x, y);
1579         return x;
1580 }
1581
1582
1583 int Cursor::textTargetOffset() const
1584 {
1585         return textTargetOffset_;
1586 }
1587
1588
1589 void Cursor::setTargetX()
1590 {
1591         int x;
1592         int y;
1593         getPos(x, y);
1594         setTargetX(x);
1595 }
1596
1597
1598 bool Cursor::inMacroMode() const
1599 {
1600         if (!inMathed())
1601                 return false;
1602         if (pos() == 0)
1603                 return false;
1604         InsetMathUnknown const * p = prevAtom()->asUnknownInset();
1605         return p && !p->final();
1606 }
1607
1608
1609 InsetMathUnknown * Cursor::activeMacro()
1610 {
1611         return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
1612 }
1613
1614
1615 InsetMathUnknown const * Cursor::activeMacro() const
1616 {
1617         return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
1618 }
1619
1620
1621 void Cursor::pullArg()
1622 {
1623         // FIXME: Look here
1624         MathData ar = cell();
1625         if (popBackward() && inMathed()) {
1626                 plainErase();
1627                 cell().insert(pos(), ar);
1628                 resetAnchor();
1629         } else {
1630                 //formula()->mutateToText();
1631         }
1632 }
1633
1634
1635 void Cursor::touch()
1636 {
1637         // FIXME: look here
1638 #if 0
1639         DocIterator::const_iterator it = begin();
1640         DocIterator::const_iterator et = end();
1641         for ( ; it != et; ++it)
1642                 it->cell().touch();
1643 #endif
1644 }
1645
1646
1647 void Cursor::normalize()
1648 {
1649         if (idx() > lastidx()) {
1650                 lyxerr << "this should not really happen - 1: "
1651                        << idx() << ' ' << nargs()
1652                        << " in: " << &inset() << endl;
1653                 idx() = lastidx();
1654         }
1655
1656         if (pos() > lastpos()) {
1657                 lyxerr << "this should not really happen - 2: "
1658                         << pos() << ' ' << lastpos() <<  " in idx: " << idx()
1659                        << " in atom: '";
1660                 odocstringstream os;
1661                 WriteStream wi(os, false, true, WriteStream::wsDefault);
1662                 inset().asInsetMath()->write(wi);
1663                 lyxerr << to_utf8(os.str()) << endl;
1664                 pos() = lastpos();
1665         }
1666 }
1667
1668
1669 bool Cursor::upDownInMath(bool up)
1670 {
1671         // Be warned: The 'logic' implemented in this function is highly
1672         // fragile. A distance of one pixel or a '<' vs '<=' _really
1673         // matters. So fiddle around with it only if you think you know
1674         // what you are doing!
1675         int xo = 0;
1676         int yo = 0;
1677         getPos(xo, yo);
1678         xo = beforeDispatchPosX_;
1679
1680         // check if we had something else in mind, if not, this is the future
1681         // target
1682         if (x_target_ == -1)
1683                 setTargetX(xo);
1684         else if (inset().asInsetText() && xo - textTargetOffset() != x_target()) {
1685                 // In text mode inside the line (not left or right) possibly set a new target_x,
1686                 // but only if we are somewhere else than the previous target-offset.
1687                 
1688                 // We want to keep the x-target on subsequent up/down movements
1689                 // that cross beyond the end of short lines. Thus a special
1690                 // handling when the cursor is at the end of line: Use the new
1691                 // x-target only if the old one was before the end of line
1692                 // or the old one was after the beginning of the line
1693                 bool inRTL = isWithinRtlParagraph(*this);
1694                 bool left;
1695                 bool right;
1696                 if (inRTL) {
1697                         left = pos() == textRow().endpos();
1698                         right = pos() == textRow().pos();
1699                 } else {
1700                         left = pos() == textRow().pos();
1701                         right = pos() == textRow().endpos();
1702                 }
1703                 if ((!left && !right) ||
1704                                 (left && !right && xo < x_target_) ||
1705                                 (!left && right && x_target_ < xo))
1706                         setTargetX(xo);
1707                 else
1708                         xo = targetX();
1709         } else
1710                 xo = targetX();
1711
1712         // try neigbouring script insets
1713         Cursor old = *this;
1714         if (inMathed() && !selection()) {
1715                 // try left
1716                 if (pos() != 0) {
1717                         InsetMathScript const * p = prevAtom()->asScriptInset();
1718                         if (p && p->has(up)) {
1719                                 --pos();
1720                                 push(*const_cast<InsetMathScript*>(p));
1721                                 idx() = p->idxOfScript(up);
1722                                 pos() = lastpos();
1723                                 
1724                                 // we went in the right direction? Otherwise don't jump into the script
1725                                 int x;
1726                                 int y;
1727                                 getPos(x, y);
1728                                 int oy = beforeDispatchPosY_;
1729                                 if ((!up && y <= oy) ||
1730                                                 (up && y >= oy))
1731                                         operator=(old);
1732                                 else
1733                                         return true;
1734                         }
1735                 }
1736                 
1737                 // try right
1738                 if (pos() != lastpos()) {
1739                         InsetMathScript const * p = nextAtom()->asScriptInset();
1740                         if (p && p->has(up)) {
1741                                 push(*const_cast<InsetMathScript*>(p));
1742                                 idx() = p->idxOfScript(up);
1743                                 pos() = 0;
1744                                 
1745                                 // we went in the right direction? Otherwise don't jump into the script
1746                                 int x;
1747                                 int y;
1748                                 getPos(x, y);
1749                                 int oy = beforeDispatchPosY_;
1750                                 if ((!up && y <= oy) ||
1751                                                 (up && y >= oy))
1752                                         operator=(old);
1753                                 else
1754                                         return true;
1755                         }
1756                 }
1757         }
1758                 
1759         // try to find an inset that knows better then we,
1760         if (inset().idxUpDown(*this, up)) {
1761                 //lyxerr << "idxUpDown triggered" << endl;
1762                 // try to find best position within this inset
1763                 if (!selection())
1764                         setCursor(bruteFind2(*this, xo, yo));
1765                 return true;
1766         }
1767         
1768         // any improvement going just out of inset?
1769         if (popBackward() && inMathed()) {
1770                 //lyxerr << "updown: popBackward succeeded" << endl;
1771                 int xnew;
1772                 int ynew;
1773                 int yold = beforeDispatchPosY_;
1774                 getPos(xnew, ynew);
1775                 if (up ? ynew < yold : ynew > yold)
1776                         return true;
1777         }
1778         
1779         // no success, we are probably at the document top or bottom
1780         operator=(old);
1781         return false;
1782 }
1783
1784
1785 bool Cursor::atFirstOrLastRow(bool up)
1786 {
1787         TextMetrics const & tm = bv_->textMetrics(text());
1788         ParagraphMetrics const & pm = tm.parMetrics(pit());
1789         
1790         int row;
1791         if (pos() && boundary())
1792                 row = pm.pos2row(pos() - 1);
1793         else
1794                 row = pm.pos2row(pos());
1795         
1796         if (up) {
1797                 if (pit() == 0 && row == 0)
1798                         return true;
1799         } else {
1800                 if (pit() + 1 >= int(text()->paragraphs().size()) &&
1801                                 row + 1 >= int(pm.rows().size()))
1802                         return true;
1803         }
1804         return false;
1805 }
1806
1807 bool Cursor::upDownInText(bool up, bool & updateNeeded)
1808 {
1809         LASSERT(text(), /**/);
1810
1811         // where are we?
1812         int xo = 0;
1813         int yo = 0;
1814         getPos(xo, yo);
1815         xo = beforeDispatchPosX_;
1816
1817         // update the targetX - this is here before the "return false"
1818         // to set a new target which can be used by InsetTexts above
1819         // if we cannot move up/down inside this inset anymore
1820         if (x_target_ == -1)
1821                 setTargetX(xo);
1822         else if (xo - textTargetOffset() != x_target() &&
1823                                          depth() == beforeDispatchCursor_.depth()) {
1824                 // In text mode inside the line (not left or right) possibly set a new target_x,
1825                 // but only if we are somewhere else than the previous target-offset.
1826                 
1827                 // We want to keep the x-target on subsequent up/down movements
1828                 // that cross beyond the end of short lines. Thus a special
1829                 // handling when the cursor is at the end of line: Use the new
1830                 // x-target only if the old one was before the end of line
1831                 // or the old one was after the beginning of the line
1832                 bool inRTL = isWithinRtlParagraph(*this);
1833                 bool left;
1834                 bool right;
1835                 if (inRTL) {
1836                         left = pos() == textRow().endpos();
1837                         right = pos() == textRow().pos();
1838                 } else {
1839                         left = pos() == textRow().pos();
1840                         right = pos() == textRow().endpos();
1841                 }
1842                 if ((!left && !right) ||
1843                                 (left && !right && xo < x_target_) ||
1844                                 (!left && right && x_target_ < xo))
1845                         setTargetX(xo);
1846                 else
1847                         xo = targetX();
1848         } else
1849                 xo = targetX();
1850                 
1851         // first get the current line
1852         TextMetrics & tm = bv_->textMetrics(text());
1853         ParagraphMetrics const & pm = tm.parMetrics(pit());
1854         int row;
1855         if (pos() && boundary())
1856                 row = pm.pos2row(pos() - 1);
1857         else
1858                 row = pm.pos2row(pos());
1859                 
1860         if (atFirstOrLastRow(up)) {
1861                 // Is there a place for the cursor to go ? If yes, we
1862                 // can execute the DEPM, otherwise we should keep the
1863                 // paragraph to host the cursor.
1864                 Cursor dummy = *this;
1865                 bool valid_destination = false;
1866                 for(; dummy.depth(); dummy.pop())
1867                         if (!dummy.atFirstOrLastRow(up)) {
1868                                 valid_destination = true;
1869                                 break;
1870                         }
1871
1872                 // will a next dispatch follow and if there is a new 
1873                 // dispatch will it move the cursor out ?
1874                 if (depth() > 1 && valid_destination) {
1875                         // The cursor hasn't changed yet. This happens when
1876                         // you e.g. move out of an inset. And to give the 
1877                         // DEPM the possibility of doing something we must
1878                         // provide it with two different cursors. (Lgb, vfr)
1879                         dummy = *this;
1880                         dummy.pos() = dummy.pos() == 0 ? dummy.lastpos() : 0;
1881                         dummy.pit() = dummy.pit() == 0 ? dummy.lastpit() : 0;
1882
1883                         updateNeeded |= bv().checkDepm(dummy, *this);
1884                         updateTextTargetOffset();
1885                 }
1886                 return false;
1887         }
1888
1889         // with and without selection are handled differently
1890         if (!selection()) {
1891                 int yo = bv().getPos(*this).y_;
1892                 Cursor old = *this;
1893                 // To next/previous row
1894                 if (up)
1895                         tm.editXY(*this, xo, yo - textRow().ascent() - 1);
1896                 else
1897                         tm.editXY(*this, xo, yo + textRow().descent() + 1);
1898                 clearSelection();
1899                 
1900                 // This happens when you move out of an inset.  
1901                 // And to give the DEPM the possibility of doing  
1902                 // something we must provide it with two different  
1903                 // cursors. (Lgb)  
1904                 Cursor dummy = *this;
1905                 if (dummy == old)
1906                         ++dummy.pos();
1907                 if (bv().checkDepm(dummy, old)) {
1908                         updateNeeded = true;
1909                         // Make sure that cur gets back whatever happened to dummy(Lgb) 
1910                         operator=(dummy);
1911                 }
1912         } else {
1913                 // if there is a selection, we stay out of any inset,
1914                 // and just jump to the right position:
1915                 Cursor old = *this;
1916                 int next_row = row;
1917                 if (up) {
1918                         if (row > 0) {
1919                                 --next_row;
1920                         } else if (pit() > 0) {
1921                                 --pit();
1922                                 TextMetrics & tm = bv_->textMetrics(text());
1923                                 if (!tm.contains(pit()))
1924                                         tm.newParMetricsUp();
1925                                 ParagraphMetrics const & pmcur = tm.parMetrics(pit());
1926                                 next_row = pmcur.rows().size() - 1;
1927                         }
1928                 } else {
1929                         if (row + 1 < int(pm.rows().size())) {
1930                                 ++next_row;
1931                         } else if (pit() + 1 < int(text()->paragraphs().size())) {
1932                                 ++pit();
1933                                 TextMetrics & tm = bv_->textMetrics(text());
1934                                 if (!tm.contains(pit()))
1935                                         tm.newParMetricsDown();
1936                                 next_row = 0;
1937                         }
1938                 }
1939                 top().pos() = min(tm.x2pos(pit(), next_row, xo), top().lastpos());
1940
1941                 int const xpos = tm.x2pos(pit(), next_row, xo);
1942                 bool const at_end_row = xpos == tm.x2pos(pit(), next_row, tm.width());
1943                 bool const at_beg_row = xpos == tm.x2pos(pit(), next_row, 0);
1944
1945                 if (at_end_row && at_beg_row)
1946                         // make sure the cursor ends up on this row
1947                         boundary(false);
1948                 else
1949                         boundary(at_end_row);
1950
1951                 updateNeeded |= bv().checkDepm(*this, old);
1952         }
1953
1954         updateTextTargetOffset();
1955         return true;
1956 }       
1957
1958
1959 void Cursor::handleFont(string const & font)
1960 {
1961         LYXERR(Debug::DEBUG, font);
1962         docstring safe;
1963         if (selection()) {
1964                 macroModeClose();
1965                 safe = cap::grabAndEraseSelection(*this);
1966         }
1967
1968         recordUndoInset();
1969
1970         if (lastpos() != 0) {
1971                 // something left in the cell
1972                 if (pos() == 0) {
1973                         // cursor in first position
1974                         popBackward();
1975                 } else if (pos() == lastpos()) {
1976                         // cursor in last position
1977                         popForward();
1978                 } else {
1979                         // cursor in between. split cell
1980                         MathData::iterator bt = cell().begin();
1981                         MathAtom at = createInsetMath(from_utf8(font), buffer());
1982                         at.nucleus()->cell(0) = MathData(buffer(), bt, bt + pos());
1983                         cell().erase(bt, bt + pos());
1984                         popBackward();
1985                         plainInsert(at);
1986                 }
1987         } else {
1988                 // nothing left in the cell
1989                 popBackward();
1990                 plainErase();
1991                 resetAnchor();
1992         }
1993         insert(safe);
1994 }
1995
1996
1997 void Cursor::message(docstring const & msg) const
1998 {
1999         disp_.setMessage(msg);
2000 }
2001
2002
2003 void Cursor::errorMessage(docstring const & msg) const
2004 {
2005         disp_.setMessage(msg);
2006         disp_.setError(true);
2007 }
2008
2009
2010 static docstring parbreak(InsetCode code)
2011 {
2012         odocstringstream os;
2013         os << '\n';
2014         // only add blank line if we're not in an ERT or Listings inset
2015         if (code != ERT_CODE && code != LISTINGS_CODE)
2016                 os << '\n';
2017         return os.str();
2018 }
2019
2020
2021 docstring Cursor::selectionAsString(bool with_label) const
2022 {
2023         if (!selection())
2024                 return docstring();
2025
2026         if (inMathed())
2027                 return cap::grabSelection(*this);
2028
2029         int const label = with_label
2030                 ? AS_STR_LABEL | AS_STR_INSETS : AS_STR_INSETS;
2031
2032         idx_type const startidx = selBegin().idx();
2033         idx_type const endidx = selEnd().idx();
2034         if (startidx != endidx) {
2035                 // multicell selection
2036                 InsetTabular * table = inset().asInsetTabular();
2037                 LASSERT(table, return docstring());
2038                 return table->asString(startidx, endidx);
2039         }
2040
2041         ParagraphList const & pars = text()->paragraphs();
2042
2043         pit_type const startpit = selBegin().pit();
2044         pit_type const endpit = selEnd().pit();
2045         size_t const startpos = selBegin().pos();
2046         size_t const endpos = selEnd().pos();
2047
2048         if (startpit == endpit)
2049                 return pars[startpit].asString(startpos, endpos, label);
2050
2051         // First paragraph in selection
2052         docstring result = pars[startpit].
2053                 asString(startpos, pars[startpit].size(), label)
2054                 + parbreak(inset().lyxCode());
2055
2056         // The paragraphs in between (if any)
2057         for (pit_type pit = startpit + 1; pit != endpit; ++pit) {
2058                 Paragraph const & par = pars[pit];
2059                 result += par.asString(0, par.size(), label)
2060                         + parbreak(inset().lyxCode());
2061         }
2062
2063         // Last paragraph in selection
2064         result += pars[endpit].asString(0, endpos, label);
2065
2066         return result;
2067 }
2068
2069
2070 docstring Cursor::currentState() const
2071 {
2072         if (inMathed()) {
2073                 odocstringstream os;
2074                 info(os);
2075                 return os.str();
2076         }
2077
2078         if (inTexted())
2079                 return text()->currentState(*this);
2080
2081         return docstring();
2082 }
2083
2084
2085 docstring Cursor::getPossibleLabel() const
2086 {
2087         return inMathed() ? from_ascii("eq:") : text()->getPossibleLabel(*this);
2088 }
2089
2090
2091 Encoding const * Cursor::getEncoding() const
2092 {
2093         if (empty())
2094                 return 0;
2095         CursorSlice const & sl = innerTextSlice();
2096         Text const & text = *sl.text();
2097         Font font = text.getPar(sl.pit()).getFont(
2098                 bv().buffer().params(), sl.pos(), text.outerFont(sl.pit()));
2099         return font.language()->encoding();
2100 }
2101
2102
2103 void Cursor::undispatched()
2104 {
2105         disp_.dispatched(false);
2106 }
2107
2108
2109 void Cursor::dispatched()
2110 {
2111         disp_.dispatched(true);
2112 }
2113
2114
2115 void Cursor::updateFlags(Update::flags f)
2116 {
2117         disp_.update(f);
2118 }
2119
2120
2121 void Cursor::noUpdate()
2122 {
2123         disp_.update(Update::None);
2124 }
2125
2126
2127 Font Cursor::getFont() const
2128 {
2129         // The logic here should more or less match to the Cursor::setCurrentFont
2130         // logic, i.e. the cursor height should give a hint what will happen
2131         // if a character is entered.
2132         
2133         // HACK. far from being perfect...
2134
2135         CursorSlice const & sl = innerTextSlice();
2136         Text const & text = *sl.text();
2137         Paragraph const & par = text.getPar(sl.pit());
2138         
2139         // on boundary, so we are really at the character before
2140         pos_type pos = sl.pos();
2141         if (pos > 0 && boundary())
2142                 --pos;
2143         
2144         // on space? Take the font before (only for RTL boundary stay)
2145         if (pos > 0) {
2146                 TextMetrics const & tm = bv().textMetrics(&text);
2147                 if (pos == sl.lastpos()
2148                         || (par.isSeparator(pos) 
2149                         && !tm.isRTLBoundary(sl.pit(), pos)))
2150                         --pos;
2151         }
2152         
2153         // get font at the position
2154         Font font = par.getFont(buffer()->params(), pos,
2155                 text.outerFont(sl.pit()));
2156
2157         return font;
2158 }
2159
2160
2161 bool Cursor::fixIfBroken()
2162 {
2163         bool const broken_cursor = DocIterator::fixIfBroken();
2164         bool const broken_anchor = anchor_.fixIfBroken();
2165         
2166         if (broken_cursor || broken_anchor) {
2167                 clearSelection();
2168                 return true;
2169         }
2170         return false;
2171 }
2172
2173
2174 bool notifyCursorLeavesOrEnters(Cursor const & old, Cursor & cur)
2175 {
2176         // find inset in common
2177         size_type i;
2178         for (i = 0; i < old.depth() && i < cur.depth(); ++i) {
2179                 if (&old[i].inset() != &cur[i].inset())
2180                         break;
2181         }
2182
2183         // update words if we just moved to another paragraph
2184         if (i == old.depth() && i == cur.depth()
2185             && !cur.buffer()->isClean()
2186             && cur.inTexted() && old.inTexted()
2187             && cur.pit() != old.pit()) {
2188                 old.paragraph().updateWords();
2189         }
2190
2191         // notify everything on top of the common part in old cursor,
2192         // but stop if the inset claims the cursor to be invalid now
2193         for (size_type j = i; j < old.depth(); ++j) {
2194                 Cursor inset_pos = old;
2195                 inset_pos.cutOff(j);
2196                 if (old[j].inset().notifyCursorLeaves(inset_pos, cur))
2197                         return true;
2198         }
2199
2200         // notify everything on top of the common part in new cursor,
2201         // but stop if the inset claims the cursor to be invalid now
2202         for (; i < cur.depth(); ++i) {
2203                 if (cur[i].inset().notifyCursorEnters(cur))
2204                         return true;
2205         }
2206         
2207         return false;
2208 }
2209
2210
2211 void Cursor::setCurrentFont()
2212 {
2213         CursorSlice const & cs = innerTextSlice();
2214         Paragraph const & par = cs.paragraph();
2215         pos_type cpit = cs.pit();
2216         pos_type cpos = cs.pos();
2217         Text const & ctext = *cs.text();
2218         TextMetrics const & tm = bv().textMetrics(&ctext);
2219
2220         // are we behind previous char in fact? -> go to that char
2221         if (cpos > 0 && boundary())
2222                 --cpos;
2223
2224         // find position to take the font from
2225         if (cpos != 0) {
2226                 // paragraph end? -> font of last char
2227                 if (cpos == lastpos())
2228                         --cpos;
2229                 // on space? -> look at the words in front of space
2230                 else if (cpos > 0 && par.isSeparator(cpos))     {
2231                         // abc| def -> font of c
2232                         // abc |[WERBEH], i.e. boundary==true -> font of c
2233                         // abc [WERBEH]| def, font of the space
2234                         if (!tm.isRTLBoundary(cpit, cpos))
2235                                 --cpos;
2236                 }
2237         }
2238
2239         // get font
2240         BufferParams const & bufparams = buffer()->params();
2241         current_font = par.getFontSettings(bufparams, cpos);
2242         real_current_font = tm.displayFont(cpit, cpos);
2243
2244         // special case for paragraph end
2245         if (cs.pos() == lastpos()
2246             && tm.isRTLBoundary(cpit, cs.pos())
2247             && !boundary()) {
2248                 Language const * lang = par.getParLanguage(bufparams);
2249                 current_font.setLanguage(lang);
2250                 current_font.fontInfo().setNumber(FONT_OFF);
2251                 real_current_font.setLanguage(lang);
2252                 real_current_font.fontInfo().setNumber(FONT_OFF);
2253         }
2254 }
2255
2256
2257 bool Cursor::textUndo()
2258 {
2259         DocIterator dit = *this;
2260         // Undo::textUndo() will modify dit.
2261         if (!buffer()->undo().textUndo(dit))
2262                 return false;
2263         // Set cursor
2264         setCursor(dit);
2265         clearSelection();
2266         fixIfBroken();
2267         return true;
2268 }
2269
2270
2271 bool Cursor::textRedo()
2272 {
2273         DocIterator dit = *this;
2274         // Undo::textRedo() will modify dit.
2275         if (!buffer()->undo().textRedo(dit))
2276                 return false;
2277         // Set cursor
2278         setCursor(dit);
2279         clearSelection();
2280         fixIfBroken();
2281         return true;
2282 }
2283
2284
2285 void Cursor::finishUndo() const
2286 {
2287         buffer()->undo().finishUndo();
2288 }
2289
2290
2291 void Cursor::beginUndoGroup() const
2292 {
2293         buffer()->undo().beginUndoGroup();
2294 }
2295
2296
2297 void Cursor::endUndoGroup() const
2298 {
2299         buffer()->undo().endUndoGroup();
2300 }
2301
2302
2303 void Cursor::recordUndo(UndoKind kind, pit_type from, pit_type to) const
2304 {
2305         buffer()->undo().recordUndo(*this, kind, from, to);
2306 }
2307
2308
2309 void Cursor::recordUndo(UndoKind kind, pit_type from) const
2310 {
2311         buffer()->undo().recordUndo(*this, kind, from);
2312 }
2313
2314
2315 void Cursor::recordUndo(UndoKind kind) const
2316 {
2317         buffer()->undo().recordUndo(*this, kind);
2318 }
2319
2320
2321 void Cursor::recordUndoInset(UndoKind kind) const
2322 {
2323         buffer()->undo().recordUndoInset(*this, kind);
2324 }
2325
2326
2327 void Cursor::recordUndoFullDocument() const
2328 {
2329         buffer()->undo().recordUndoFullDocument(*this);
2330 }
2331
2332
2333 void Cursor::recordUndoSelection() const
2334 {
2335         if (inMathed()) {
2336                 if (cap::multipleCellsSelected(*this))
2337                         recordUndoInset();
2338                 else
2339                         recordUndo();
2340         } else {
2341                 buffer()->undo().recordUndo(*this, ATOMIC_UNDO,
2342                         selBegin().pit(), selEnd().pit());
2343         }
2344 }
2345
2346
2347 void Cursor::checkBufferStructure()
2348 {
2349         Buffer const * master = buffer()->masterBuffer();
2350         master->tocBackend().updateItem(*this);
2351         if (master != buffer() && !master->hasGuiDelegate())
2352                 // In case the master has no gui associated with it, 
2353                 // the TocItem is not updated (part of bug 5699).
2354                 buffer()->tocBackend().updateItem(*this);
2355 }
2356
2357
2358 } // namespace lyx