3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
7 * \author Alfredo Braunstein
10 * Full author contact details are available in file CREDITS.
15 #include "BufferView.h"
18 #include "coordcache.h"
19 #include "CutAndPaste.h"
21 #include "dispatchresult.h"
23 #include "funcrequest.h"
27 #include "lyxfunc.h" // only for setMessage()
31 #include "paragraph.h"
32 #include "paragraph_funcs.h"
33 #include "pariterator.h"
35 #include "insets/insettabular.h"
36 #include "insets/insettext.h"
38 #include "mathed/math_biginset.h"
39 #include "mathed/math_data.h"
40 #include "mathed/math_inset.h"
41 #include "mathed/math_scriptinset.h"
42 #include "mathed/math_macrotable.h"
43 #include "mathed/math_parser.h"
45 #include "support/limited_stack.h"
47 #include "frontends/LyXView.h"
48 #include "frontends/font_metrics.h"
50 #include <boost/assert.hpp>
51 #include <boost/bind.hpp>
52 #include <boost/current_function.hpp>
63 #ifndef CXX_GLOBAL_CSTD
72 positionable(DocIterator const & cursor, DocIterator const & anchor)
74 // avoid deeper nested insets when selecting
75 if (cursor.depth() > anchor.depth())
78 // anchor might be deeper, should have same path then
79 for (size_t i = 0; i < cursor.depth(); ++i)
80 if (&cursor[i].inset() != &anchor[i].inset())
83 // position should be ok.
88 // Find position closest to (x, y) in cell given by iter.
89 // Used only in mathed
90 DocIterator bruteFind2(LCursor const & c, int x, int y)
92 double best_dist = std::numeric_limits<double>::max();
99 et.top().pos() = et.top().asMathInset()->cell(et.top().idx()).size();
100 for (size_t i = 0; ; ++i) {
103 InsetBase const * inset = &it.inset();
104 Point o = theCoords.getInsets().xy(inset);
105 inset->cursorPos(it.top(), c.boundary(), xo, yo);
106 // Convert to absolute
109 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
110 // '<=' in order to take the last possible position
111 // this is important for clicking behind \sum in e.g. '\sum_i a'
112 lyxerr[Debug::DEBUG] << "i: " << i << " d: " << d
113 << " best: " << best_dist << endl;
114 if (d <= best_dist) {
126 /// moves position closest to (x, y) in given box
127 bool bruteFind(LCursor & cursor,
128 int x, int y, int xlow, int xhigh, int ylow, int yhigh)
130 BOOST_ASSERT(!cursor.empty());
131 InsetBase & inset = cursor[0].inset();
133 CoordCache::InnerParPosCache const & cache = theCoords.getParPos().find(cursor.bottom().text())->second;
134 // Get an iterator on the first paragraph in the cache
135 DocIterator it(inset);
136 it.push_back(CursorSlice(inset));
137 it.pit() = cache.begin()->first;
138 // Get an iterator after the last paragraph in the cache
139 DocIterator et(inset);
140 et.push_back(CursorSlice(inset));
141 et.pit() = boost::prior(cache.end())->first;
142 if (et.pit() >= et.lastpit())
143 et = doc_iterator_end(inset);
147 double best_dist = std::numeric_limits<double>::max();;
148 DocIterator best_cursor = et;
150 for ( ; it != et; it.forwardPos(true)) {
151 // avoid invalid nesting when selecting
152 if (!cursor.selection() || positionable(it, cursor.anchor_)) {
153 Point p = bv_funcs::getPos(it, false);
156 if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
157 double const dx = xo - x;
158 double const dy = yo - y;
159 double const d = dx * dx + dy * dy;
160 // '<=' in order to take the last possible position
161 // this is important for clicking behind \sum in e.g. '\sum_i a'
162 if (d <= best_dist) {
163 // lyxerr << "*" << endl;
171 if (best_cursor != et) {
172 cursor.setCursor(best_cursor);
180 /// moves position closest to (x, y) in given box
181 bool bruteFind3(LCursor & cur, int x, int y, bool up)
183 BufferView & bv = cur.bv();
184 int ylow = up ? 0 : y + 1;
185 int yhigh = up ? y - 1 : bv.workHeight();
187 int xhigh = bv.workWidth();
189 // FIXME: bit more work needed to get 'from' and 'to' right.
190 pit_type from = cur.bottom().pit();
191 //pit_type to = cur.bottom().pit();
192 //lyxerr << "Pit start: " << from << endl;
194 //lyxerr << "bruteFind3: x: " << x << " y: " << y
195 // << " xlow: " << xlow << " xhigh: " << xhigh
196 // << " ylow: " << ylow << " yhigh: " << yhigh
198 InsetBase & inset = bv.buffer()->inset();
199 DocIterator it = doc_iterator_begin(inset);
201 DocIterator et = doc_iterator_end(inset);
203 double best_dist = std::numeric_limits<double>::max();
204 DocIterator best_cursor = et;
206 for ( ; it != et; it.forwardPos()) {
207 // avoid invalid nesting when selecting
208 if (bv_funcs::status(&bv, it) == bv_funcs::CUR_INSIDE
209 && (!cur.selection() || positionable(it, cur.anchor_))) {
210 Point p = bv_funcs::getPos(it, false);
213 if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
214 double const dx = xo - x;
215 double const dy = yo - y;
216 double const d = dx * dx + dy * dy;
217 //lyxerr << "itx: " << xo << " ity: " << yo << " d: " << d
218 // << " dx: " << dx << " dy: " << dy
219 // << " idx: " << it.idx() << " pos: " << it.pos()
222 // '<=' in order to take the last possible position
223 // this is important for clicking behind \sum in e.g. '\sum_i a'
224 if (d <= best_dist) {
225 //lyxerr << "*" << endl;
233 //lyxerr << "best_dist: " << best_dist << " cur:\n" << best_cursor << endl;
234 if (best_cursor == et)
236 cur.setCursor(best_cursor);
243 // be careful: this is called from the bv's constructor, too, so
244 // bv functions are not yet available!
245 LCursor::LCursor(BufferView & bv)
246 : DocIterator(), bv_(&bv), anchor_(), x_target_(-1),
247 selection_(false), mark_(false), logicalpos_(false)
251 void LCursor::reset(InsetBase & inset)
254 push_back(CursorSlice(inset));
255 anchor_ = DocIterator(inset);
262 // this (intentionally) does neither touch anchor nor selection status
263 void LCursor::setCursor(DocIterator const & cur)
265 DocIterator::operator=(cur);
269 void LCursor::dispatch(FuncRequest const & cmd0)
271 lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION
272 << " cmd: " << cmd0 << '\n'
278 FuncRequest cmd = cmd0;
279 LCursor safe = *this;
281 for (; depth(); pop()) {
282 lyxerr[Debug::DEBUG] << "LCursor::dispatch: cmd: "
283 << cmd0 << endl << *this << endl;
284 BOOST_ASSERT(pos() <= lastpos());
285 BOOST_ASSERT(idx() <= lastidx());
286 BOOST_ASSERT(pit() <= lastpit());
288 // The common case is 'LFUN handled, need update', so make the
289 // LFUN handler's life easier by assuming this as default value.
290 // The handler can reset the update and val flags if necessary.
292 disp_.dispatched(true);
293 inset().dispatch(*this, cmd);
294 if (disp_.dispatched())
297 // it completely to get a 'bomb early' behaviour in case this
298 // object will be used again.
299 if (!disp_.dispatched()) {
300 lyxerr[Debug::DEBUG] << "RESTORING OLD CURSOR!" << endl;
302 disp_.dispatched(false);
307 DispatchResult LCursor::result() const
313 BufferView & LCursor::bv() const
320 Buffer & LCursor::buffer() const
323 BOOST_ASSERT(bv_->buffer());
324 return *bv_->buffer();
330 BOOST_ASSERT(depth() >= 1);
335 void LCursor::push(InsetBase & p)
337 push_back(CursorSlice(p));
341 void LCursor::pushLeft(InsetBase & p)
343 BOOST_ASSERT(!empty());
344 //lyxerr << "Entering inset " << t << " left" << endl;
350 bool LCursor::popLeft()
352 BOOST_ASSERT(!empty());
353 //lyxerr << "Leaving inset to the left" << endl;
354 inset().notifyCursorLeaves(*this);
362 bool LCursor::popRight()
364 BOOST_ASSERT(!empty());
365 //lyxerr << "Leaving inset to the right" << endl;
366 inset().notifyCursorLeaves(*this);
375 int LCursor::currentMode()
377 BOOST_ASSERT(!empty());
378 for (int i = depth() - 1; i >= 0; --i) {
379 int res = operator[](i).inset().currentMode();
380 if (res != InsetBase::UNDECIDED_MODE)
383 return InsetBase::TEXT_MODE;
387 void LCursor::getPos(int & x, int & y) const
389 Point p = bv_funcs::getPos(*this, boundary());
395 void LCursor::resetAnchor()
402 bool LCursor::posLeft()
411 bool LCursor::posRight()
413 if (pos() == lastpos())
420 CursorSlice LCursor::anchor() const
422 BOOST_ASSERT(anchor_.depth() >= depth());
423 CursorSlice normal = anchor_[depth() - 1];
424 if (depth() < anchor_.depth() && top() <= normal) {
425 // anchor is behind cursor -> move anchor behind the inset
432 CursorSlice LCursor::selBegin() const
436 return anchor() < top() ? anchor() : top();
440 CursorSlice LCursor::selEnd() const
444 return anchor() > top() ? anchor() : top();
448 DocIterator LCursor::selectionBegin() const
452 DocIterator di = (anchor() < top() ? anchor_ : *this);
458 DocIterator LCursor::selectionEnd() const
462 DocIterator di = (anchor() > top() ? anchor_ : *this);
463 if (di.depth() > depth()) {
471 void LCursor::setSelection()
474 // A selection with no contents is not a selection
476 #warning doesnt look ok
478 if (pit() == anchor().pit() && pos() == anchor().pos())
483 void LCursor::setSelection(DocIterator const & where, size_t n)
492 void LCursor::clearSelection()
501 int & LCursor::x_target()
507 int LCursor::x_target() const
513 void LCursor::clearTargetX()
520 void LCursor::info(std::ostream & os) const
522 for (int i = 1, n = depth(); i < n; ++i) {
523 operator[](i).inset().infoize(os);
527 prevInset()->infoize2(os);
528 // overwite old message
533 void LCursor::selHandle(bool sel)
535 //lyxerr << "LCursor::selHandle" << endl;
536 if (sel == selection())
544 std::ostream & operator<<(std::ostream & os, LCursor const & cur)
546 os << "\n cursor: | anchor:\n";
547 for (size_t i = 0, n = cur.depth(); i != n; ++i) {
548 os << " " << cur[i] << " | ";
549 if (i < cur.anchor_.depth())
550 os << cur.anchor_[i];
552 os << "-------------------------------";
555 for (size_t i = cur.depth(), n = cur.anchor_.depth(); i < n; ++i) {
556 os << "------------------------------- | " << cur.anchor_[i] << "\n";
558 os << " selection: " << cur.selection_
559 << " x_target: " << cur.x_target_ << endl;
566 ///////////////////////////////////////////////////////////////////
568 // The part below is the non-integrated rest of the original math
569 // cursor. This should be either generalized for texted or moved
570 // back to mathed (in most cases to MathNestInset).
572 ///////////////////////////////////////////////////////////////////
574 #include "mathed/math_charinset.h"
575 #include "mathed/math_factory.h"
576 #include "mathed/math_gridinset.h"
577 #include "mathed/math_macroarg.h"
578 #include "mathed/math_mathmlstream.h"
579 #include "mathed/math_scriptinset.h"
580 #include "mathed/math_support.h"
581 #include "mathed/math_unknowninset.h"
583 //#define FILEDEBUG 1
586 bool LCursor::isInside(InsetBase const * p)
588 for (size_t i = 0; i != depth(); ++i)
589 if (&operator[](i).inset() == p)
595 void LCursor::leaveInset(InsetBase const & inset)
597 for (size_t i = 0; i != depth(); ++i) {
598 if (&operator[](i).inset() == &inset) {
606 bool LCursor::openable(MathAtom const & t) const
617 // we can't move into anything new during selection
618 if (depth() >= anchor_.depth())
620 if (!ptr_cmp(t.nucleus(), &anchor_[depth()].inset()))
627 void LCursor::setScreenPos(int x, int y)
630 bruteFind(*this, x, y, 0, bv().workWidth(), 0, bv().workHeight());
635 void LCursor::plainErase()
641 void LCursor::markInsert()
643 insert(char_type(0));
647 void LCursor::markErase()
653 void LCursor::plainInsert(MathAtom const & t)
655 // Create a MathBigInset from cell()[pos() - 1] and t if possible
656 if (!empty() && pos() > 0 && cell()[pos() - 1]->asUnknownInset()) {
657 string const name = asString(t);
658 if (MathBigInset::isBigInsetDelim(name)) {
659 string prev = asString(cell()[pos() - 1]);
660 if (prev[0] == '\\') {
661 prev = prev.substr(1);
662 latexkeys const * l = in_word_set(prev);
663 if (l && l->inset == "big") {
665 MathAtom(new MathBigInset(prev, name));
671 cell().insert(pos(), t);
676 void LCursor::insert(string const & str)
678 for_each(str.begin(), str.end(),
679 boost::bind(static_cast<void(LCursor::*)(char_type)>
680 (&LCursor::insert), this, _1));
684 void LCursor::insert(char_type c)
686 //lyxerr << "LCursor::insert char '" << c << "'" << endl;
687 BOOST_ASSERT(!empty());
689 lyx::cap::selClearOrDel(*this);
690 insert(new MathCharInset(c));
692 text()->insertChar(*this, c);
697 void LCursor::insert(MathAtom const & t)
699 //lyxerr << "LCursor::insert MathAtom '" << t << "'" << endl;
701 lyx::cap::selClearOrDel(*this);
706 void LCursor::insert(InsetBase * inset)
709 insert(MathAtom(inset));
711 text()->insertInset(*this, inset);
715 void LCursor::niceInsert(string const & t)
726 void LCursor::niceInsert(MathAtom const & t)
729 string const safe = lyx::cap::grabAndEraseSelection(*this);
731 // enter the new inset and move the contents of the selection if possible
734 // be careful here: don't use 'pushLeft(t)' as this we need to
735 // push the clone, not the original
736 pushLeft(*nextInset());
737 // We may not use niceInsert here (recursion)
745 void LCursor::insert(MathArray const & ar)
749 lyx::cap::eraseSelection(*this);
750 cell().insert(pos(), ar);
755 bool LCursor::backspace()
757 autocorrect() = false;
760 lyx::cap::selDel(*this);
765 if (inset().nargs() == 1 && depth() == 1 && lastpos() == 0)
772 MathUnknownInset * p = activeMacro();
773 if (p->name().size() > 1) {
774 p->setName(p->name().substr(0, p->name().size() - 1));
779 if (pos() != 0 && prevAtom()->nargs() > 0) {
780 // let's require two backspaces for 'big stuff' and
781 // highlight on the first
793 bool LCursor::erase()
795 autocorrect() = false;
800 lyx::cap::selDel(*this);
804 // delete empty cells if possible
805 if (pos() == lastpos() && inset().idxDelete(idx()))
808 // special behaviour when in last position of cell
809 if (pos() == lastpos()) {
810 bool one_cell = inset().nargs() == 1;
811 if (one_cell && depth() == 1 && lastpos() == 0)
817 inset().idxGlue(idx());
821 // 'clever' UI hack: only erase large items if previously slected
822 if (pos() != lastpos() && nextAtom()->nargs() > 0) {
837 DocIterator save = *this;
841 autocorrect() = false;
849 DocIterator save = *this;
853 autocorrect() = false;
858 bool LCursor::macroModeClose()
862 MathUnknownInset * p = activeMacro();
864 string const s = p->name();
868 // do nothing if the macro name is empty
872 // prevent entering of recursive macros
873 // FIXME: this is only a weak attempt... only prevents immediate
875 string const name = s.substr(1);
876 InsetBase const * macro = innerInsetOfType(InsetBase::MATHMACRO_CODE);
877 if (macro && macro->getInsetName() == name)
878 lyxerr << "can't enter recursive macro" << endl;
880 plainInsert(createMathInset(name));
885 string LCursor::macroName()
887 return inMacroMode() ? activeMacro()->name() : string();
891 void LCursor::handleNest(MathAtom const & a, int c)
893 //lyxerr << "LCursor::handleNest: " << c << endl;
895 asArray(lyx::cap::grabAndEraseSelection(*this), t.nucleus()->cell(c));
898 pushLeft(*nextInset());
902 int LCursor::targetX() const
904 if (x_target() != -1)
913 void LCursor::setTargetX()
915 // For now this is good enough. A better solution would be to
916 // avoid this rebreak by setting cursorX only after drawing
917 bottom().text()->redoParagraph(bottom().pit());
925 bool LCursor::inMacroMode() const
929 MathUnknownInset const * p = prevAtom()->asUnknownInset();
930 return p && !p->final();
934 MathUnknownInset * LCursor::activeMacro()
936 return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
940 void LCursor::pullArg()
945 MathArray ar = cell();
946 if (popLeft() && inMathed()) {
948 cell().insert(pos(), ar);
951 //formula()->mutateToText();
956 void LCursor::touch()
962 DocIterator::const_iterator it = begin();
963 DocIterator::const_iterator et = end();
964 for ( ; it != et; ++it)
970 void LCursor::normalize()
972 if (idx() > lastidx()) {
973 lyxerr << "this should not really happen - 1: "
974 << idx() << ' ' << nargs()
975 << " in: " << &inset() << endl;
979 if (pos() > lastpos()) {
980 lyxerr << "this should not really happen - 2: "
981 << pos() << ' ' << lastpos() << " in idx: " << idx()
983 WriteStream wi(lyxerr, false, true);
984 inset().asMathInset()->write(wi);
991 bool LCursor::goUpDown(bool up)
993 // Be warned: The 'logic' implemented in this function is highly
994 // fragile. A distance of one pixel or a '<' vs '<=' _really
995 // matters. So fiddle around with it only if you think you know
996 // what you are doing!
1002 // check if we had something else in mind, if not, this is the future goal
1003 if (x_target() == -1)
1008 // try neigbouring script insets
1012 MathScriptInset const * p = prevAtom()->asScriptInset();
1013 if (p && p->has(up)) {
1015 push(*const_cast<MathScriptInset*>(p));
1016 idx() = p->idxOfScript(up);
1023 if (pos() != lastpos()) {
1024 MathScriptInset const * p = nextAtom()->asScriptInset();
1025 if (p && p->has(up)) {
1026 push(*const_cast<MathScriptInset*>(p));
1027 idx() = p->idxOfScript(up);
1034 // FIXME: Switch this on for more robust movement
1037 return bruteFind3(*this, xo, yo, up);
1040 //xarray().boundingBox(xlow, xhigh, ylow, yhigh);
1045 //if (bruteFind(*this, xo, yo, xlow, xhigh, ylow, yhigh)) {
1046 // lyxerr << "updown: handled by brute find in the same cell" << endl;
1050 // try to find an inset that knows better then we
1052 //lyxerr << "updown: We are in " << &inset() << " idx: " << idx() << endl;
1054 if (inset().idxUpDown(*this, up)) {
1055 //lyxerr << "idxUpDown triggered" << endl;
1056 // try to find best position within this inset
1058 setCursor(bruteFind2(*this, xo, yo));
1062 // no such inset found, just take something "above"
1064 //lyxerr << "updown: popleft failed (strange case)" << endl;
1065 int ylow = up ? 0 : yo + 1;
1066 int yhigh = up ? yo - 1 : bv().workHeight();
1067 return bruteFind(*this, xo, yo, 0, bv().workWidth(), ylow, yhigh);
1070 // any improvement so far?
1071 //lyxerr << "updown: popLeft succeeded" << endl;
1075 if (up ? ynew < yo : ynew > yo)
1079 // we should not come here.
1080 BOOST_ASSERT(false);
1085 void LCursor::handleFont(string const & font)
1087 lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << ": " << font << endl;
1091 safe = lyx::cap::grabAndEraseSelection(*this);
1094 if (lastpos() != 0) {
1095 // something left in the cell
1097 // cursor in first position
1099 } else if (pos() == lastpos()) {
1100 // cursor in last position
1103 // cursor in between. split cell
1104 MathArray::iterator bt = cell().begin();
1105 MathAtom at = createMathInset(font);
1106 at.nucleus()->cell(0) = MathArray(bt, bt + pos());
1107 cell().erase(bt, bt + pos());
1112 // nothing left in the cell
1120 void LCursor::message(string const & msg) const
1122 bv().owner()->getLyXFunc().setMessage(msg);
1126 void LCursor::errorMessage(string const & msg) const
1128 bv().owner()->getLyXFunc().setErrorMessage(msg);
1132 string LCursor::selectionAsString(bool label) const
1138 Buffer const & buffer = *bv().buffer();
1139 ParagraphList const & pars = text()->paragraphs();
1141 // should be const ...
1142 pit_type startpit = selBegin().pit();
1143 pit_type endpit = selEnd().pit();
1144 size_t const startpos = selBegin().pos();
1145 size_t const endpos = selEnd().pos();
1147 if (startpit == endpit)
1148 return pars[startpit].asString(buffer, startpos, endpos, label);
1150 // First paragraph in selection
1151 string result = pars[startpit].
1152 asString(buffer, startpos, pars[startpit].size(), label) + "\n\n";
1154 // The paragraphs in between (if any)
1155 for (pit_type pit = startpit + 1; pit != endpit; ++pit) {
1156 Paragraph const & par = pars[pit];
1157 result += par.asString(buffer, 0, par.size(), label) + "\n\n";
1160 // Last paragraph in selection
1161 result += pars[endpit].asString(buffer, 0, endpos, label);
1167 return lyx::cap::grabSelection(*this);
1173 string LCursor::currentState()
1176 std::ostringstream os;
1182 return text()->currentState(*this);
1188 string LCursor::getPossibleLabel()
1190 return inMathed() ? "eq:" : text()->getPossibleLabel(*this);
1194 Encoding const * LCursor::getEncoding() const
1201 // go up until first non-0 text is hit
1202 // (innermost text is 0 in mathed)
1203 for (s = depth() - 1; s >= 0; --s)
1204 if (operator[](s).text())
1206 CursorSlice const & sl = operator[](s);
1207 LyXText const & text = *sl.text();
1208 LyXFont font = text.getPar(sl.pit()).getFont(
1209 bv().buffer()->params(), sl.pos(), outerFont(sl.pit(), text.paragraphs()));
1210 return font.language()->encoding();
1214 void LCursor::undispatched()
1216 disp_.dispatched(false);
1220 void LCursor::dispatched()
1222 disp_.dispatched(true);
1226 void LCursor::needsUpdate()
1232 void LCursor::noUpdate()
1234 disp_.update(false);
1238 LyXFont LCursor::getFont() const
1240 // HACK. far from being perfect...
1242 // go up until first non-0 text is hit
1243 // (innermost text is 0 in mathed)
1244 for (s = depth() - 1; s >= 0; --s)
1245 if (operator[](s).text())
1247 CursorSlice const & sl = operator[](s);
1248 LyXText const & text = *sl.text();
1249 LyXFont font = text.getPar(sl.pit()).getFont(
1250 bv().buffer()->params(),
1252 outerFont(sl.pit(), text.paragraphs()));
1258 void LCursor::fixIfBroken()
1260 // find out last good level
1261 LCursor copy = *this;
1262 size_t newdepth = depth();
1263 while (!copy.empty()) {
1264 if (copy.idx() > copy.lastidx()) {
1265 lyxerr << "wrong idx " << copy.idx()
1266 << ", max is " << copy.lastidx()
1267 << " at level " << copy.depth()
1268 << ". Trying to correct this." << endl;
1269 newdepth = copy.depth() - 1;
1271 else if (copy.pit() > copy.lastpit()) {
1272 lyxerr << "wrong pit " << copy.pit()
1273 << ", max is " << copy.lastpit()
1274 << " at level " << copy.depth()
1275 << ". Trying to correct this." << endl;
1276 newdepth = copy.depth() - 1;
1278 else if (copy.pos() > copy.lastpos()) {
1279 lyxerr << "wrong pos " << copy.pos()
1280 << ", max is " << copy.lastpos()
1281 << " at level " << copy.depth()
1282 << ". Trying to correct this." << endl;
1283 newdepth = copy.depth() - 1;
1287 // shrink cursor to a size where everything is valid, possibly
1289 while (depth() > newdepth) {
1291 lyxerr << "correcting cursor to level " << depth() << endl;