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.
16 #include "BufferView.h"
19 #include "dispatchresult.h"
20 #include "funcrequest.h"
21 #include "iterators.h"
23 #include "lyxfunc.h" // only for setMessage()
27 #include "paragraph.h"
29 #include "insets/updatableinset.h"
30 #include "insets/insettabular.h"
31 #include "insets/insettext.h"
33 #include "mathed/math_data.h"
34 #include "mathed/math_hullinset.h"
35 #include "mathed/math_support.h"
37 #include "support/limited_stack.h"
38 #include "support/std_sstream.h"
40 #include "frontends/LyXView.h"
42 #include <boost/assert.hpp>
47 #ifndef CXX_GLOBAL_CSTD
56 limited_stack<string> theCutBuffer;
59 LCursor::LCursor(BufferView & bv)
60 : DocumentIterator(bv), anchor_(bv),
61 cached_y_(0), x_target_(-1), selection_(false), mark_(false)
68 push_back(CursorSlice());
70 anchor_.push_back(CursorSlice());
78 void LCursor::setCursor(DocumentIterator const & cur, bool sel)
80 // this (intentionally) does not touch the anchor
81 DocumentIterator::operator=(cur);
86 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
88 lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl;
89 BOOST_ASSERT(pos() <= lastpos());
90 BOOST_ASSERT(idx() <= lastidx());
91 BOOST_ASSERT(par() <= lastpar());
92 FuncRequest cmd = cmd0;
94 DocumentIterator orig = *this;
98 // the inset's dispatch() is supposed to reset the update and
99 // val flags if necessary
100 inset()->dispatch(*this, cmd);
102 // "Mutate" the request for semi-handled requests that need
103 // additional handling in outer levels.
104 switch (disp_.val()) {
106 // the inset handled the event fully
107 return DispatchResult(true, true);
109 // the inset handled the event partially
110 cmd = FuncRequest(LFUN_FINISHED_LEFT);
113 cmd = FuncRequest(LFUN_FINISHED_RIGHT);
116 cmd = FuncRequest(LFUN_FINISHED_UP);
119 cmd = FuncRequest(LFUN_FINISHED_DOWN);
122 //lyxerr << "not handled on level " << depth()
123 // << " val: " << disp_.val() << endl;
128 bv().text()->dispatch(*this, cmd);
130 setCursor(orig, false);
131 //lyxerr << " result: " << res.val() << endl;
136 bool LCursor::getStatus(FuncRequest const & cmd, FuncStatus & status)
138 lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
139 DocumentIterator orig = *this;
140 BOOST_ASSERT(pos() <= lastpos());
141 BOOST_ASSERT(idx() <= lastidx());
142 BOOST_ASSERT(par() <= lastpar());
143 for ( ; size() != 0; pop_back()) {
144 // the inset's getStatus() will return 'true' if it made
145 // a definitive decision on whether it want to handle the
146 // request or not. The result of this decision is put into
147 // the 'status' parameter.
148 bool const res = inset()->getStatus(*this, cmd, status);
150 setCursor(orig, false);
154 bool const res = bv().text()->getStatus(*this, cmd, status);
155 setCursor(orig, false);
160 BufferView & LCursor::bv() const
162 return DocumentIterator::bv();
167 void LCursor::pop(int depth)
169 while (int(size()) > depth + 1)
171 lyxerr << "LCursor::pop() result: " << *this << endl;
178 BOOST_ASSERT(size() >= 1);
184 void LCursor::push(InsetBase * p)
186 push_back(CursorSlice(p));
190 void LCursor::pushLeft(InsetBase * p)
192 BOOST_ASSERT(!empty());
193 //lyxerr << "Entering inset " << t << " left" << endl;
199 bool LCursor::popLeft()
201 BOOST_ASSERT(!empty());
202 //lyxerr << "Leaving inset to the left" << endl;
205 inset()->notifyCursorLeaves(idx());
208 inset()->notifyCursorLeaves(idx());
214 bool LCursor::popRight()
216 BOOST_ASSERT(!empty());
217 //lyxerr << "Leaving inset to the right" << endl;
220 inset()->notifyCursorLeaves(idx());
223 inset()->notifyCursorLeaves(idx());
230 int LCursor::currentMode()
232 BOOST_ASSERT(!empty());
233 for (int i = size() - 1; i >= 1; --i) {
234 int res = operator[](i).inset()->currentMode();
235 if (res != MathInset::UNDECIDED_MODE)
238 return MathInset::TEXT_MODE;
242 void LCursor::updatePos()
244 BOOST_ASSERT(!empty());
246 cached_y_ = bv().top_y() + back().inset()->yo();
247 //cached_y_ = back().inset()->yo();
251 void LCursor::getDim(int & asc, int & des) const
253 BOOST_ASSERT(!empty());
255 BOOST_ASSERT(inset());
256 BOOST_ASSERT(inset()->asMathInset());
257 //inset()->asMathInset()->getCursorDim(asc, des);
261 Row const & row = textRow();
262 asc = row.baseline();
263 des = row.height() - asc;
268 void LCursor::getPos(int & x, int & y) const
270 BOOST_ASSERT(!empty());
274 x = bv().text()->cursorX(front());
275 y = bv().text()->cursorY(front());
278 lyxerr << "#### LCursor::getPos: " << *this << endl;
279 BOOST_ASSERT(inset());
281 inset()->getCursorPos(back(), x, y);
282 // getCursorPos gives _screen_ coordinates. We need to add
283 // top_y to get document coordinates. This is hidden in cached_y_.
284 //y += cached_y_ - inset()->yo();
285 // The rest is non-obvious. The reason we have to have these
286 // extra computation is that the getCursorPos() calls rely
287 // on the inset's own knowledge of its screen position.
288 // If we scroll up or down in a big enough increment,
289 // inset->draw() is not called: this doesn't update
290 // inset.yo_, so getCursor() returns an old value.
293 //lyxerr << "#### LCursor::getPos: " << *this
294 // << " x: " << x << " y: " << y << endl;
298 void LCursor::paste(string const & data)
300 dispatch(FuncRequest(LFUN_PASTE, data));
304 void LCursor::resetAnchor()
311 bool LCursor::posLeft()
320 bool LCursor::posRight()
322 if (pos() == lastpos())
329 CursorSlice & LCursor::anchor()
331 return anchor_.back();
335 CursorSlice const & LCursor::anchor() const
337 return anchor_.back();
341 CursorSlice const & LCursor::selBegin() const
345 return anchor() < back() ? anchor() : back();
349 CursorSlice & LCursor::selBegin()
353 // can't use std::min as this returns a const ref
354 return anchor() < back() ? anchor() : back();
358 CursorSlice const & LCursor::selEnd() const
362 return anchor() > back() ? anchor() : back();
366 CursorSlice & LCursor::selEnd()
370 // can't use std::min as this returns a const ref
371 return anchor() > back() ? anchor() : back();
375 void LCursor::setSelection()
378 // a selection with no contents is not a selection
379 if (par() == anchor().par() && pos() == anchor().pos())
384 void LCursor::setSelection(DocumentIterator const & where, size_t n)
387 setCursor(where, false);
393 void LCursor::clearSelection()
402 int & LCursor::x_target()
408 int LCursor::x_target() const
414 void LCursor::clearTargetX()
421 void LCursor::info(std::ostream & os) const
423 for (int i = 1, n = depth(); i < n; ++i) {
424 operator[](i).inset()->infoize(os);
428 prevInset()->infoize2(os);
429 // overwite old message
436 void region(CursorSlice const & i1, CursorSlice const & i2,
437 LCursor::row_type & r1, LCursor::row_type & r2,
438 LCursor::col_type & c1, LCursor::col_type & c2)
440 InsetBase * p = i1.inset();
441 c1 = p->col(i1.idx_);
442 c2 = p->col(i2.idx_);
445 r1 = p->row(i1.idx_);
446 r2 = p->row(i2.idx_);
454 string LCursor::grabSelection()
459 CursorSlice i1 = selBegin();
460 CursorSlice i2 = selEnd();
462 if (i1.idx_ == i2.idx_) {
463 if (i1.inset()->asMathInset()) {
464 MathArray::const_iterator it = i1.cell().begin();
465 return asString(MathArray(it + i1.pos_, it + i2.pos_));
467 return "unknown selection 1";
473 region(i1, i2, r1, r2, c1, c2);
476 if (i1.inset()->asMathInset()) {
477 for (row_type row = r1; row <= r2; ++row) {
480 for (col_type col = c1; col <= c2; ++col) {
483 data += asString(i1.asMathInset()->cell(i1.asMathInset()->index(row, col)));
487 data = "unknown selection 2";
493 void LCursor::eraseSelection()
495 //lyxerr << "LCursor::eraseSelection" << endl;
496 CursorSlice const & i1 = selBegin();
497 CursorSlice const & i2 = selEnd();
499 if (i1.inset()->asMathInset()) {
500 if (i1.idx_ == i2.idx_) {
501 i1.cell().erase(i1.pos_, i2.pos_);
503 MathInset * p = i1.asMathInset();
506 region(i1, i2, r1, r2, c1, c2);
507 for (row_type row = r1; row <= r2; ++row)
508 for (col_type col = c1; col <= c2; ++col)
509 p->cell(p->index(row, col)).clear();
513 lyxerr << "can't erase this selection 1" << endl;
515 //lyxerr << "LCursor::eraseSelection end" << endl;
519 string LCursor::grabAndEraseSelection()
523 string res = grabSelection();
530 void LCursor::selClear()
537 void LCursor::selCopy()
540 theCutBuffer.push(grabSelection());
543 //theCutBuffer.erase();
548 void LCursor::selCut()
550 theCutBuffer.push(grabAndEraseSelection());
554 void LCursor::selDel()
556 //lyxerr << "LCursor::selDel" << endl;
564 void LCursor::selPaste(size_t n)
567 if (n < theCutBuffer.size())
568 paste(theCutBuffer[n]);
574 void LCursor::selHandle(bool sel)
576 //lyxerr << "LCursor::selHandle" << endl;
577 if (sel == selection())
584 void LCursor::selClearOrDel()
586 //lyxerr << "LCursor::selClearOrDel" << endl;
587 if (lyxrc.auto_region_delete)
594 std::ostream & operator<<(std::ostream & os, LCursor const & cur)
596 for (size_t i = 0, n = cur.size(); i != n; ++i)
597 os << " " << cur.operator[](i) << " | " << cur.anchor_[i] << "\n";
598 os << " selection: " << cur.selection_ << endl;
605 ///////////////////////////////////////////////////////////////////
607 // The part below is the non-integrated rest of the original math
608 // cursor. This should be either generalized for texted or moved
609 // back to mathed (in most cases to MathNestInset).
611 ///////////////////////////////////////////////////////////////////
613 #include "mathed/math_charinset.h"
614 #include "mathed/math_factory.h"
615 #include "mathed/math_gridinset.h"
616 #include "mathed/math_macroarg.h"
617 #include "mathed/math_macrotemplate.h"
618 #include "mathed/math_mathmlstream.h"
619 #include "mathed/math_scriptinset.h"
620 #include "mathed/math_support.h"
621 #include "mathed/math_unknowninset.h"
623 //#define FILEDEBUG 1
626 bool LCursor::isInside(InsetBase const * p)
628 for (unsigned i = 0; i < depth(); ++i)
629 if (operator[](i).inset() == p)
635 bool LCursor::openable(MathAtom const & t) const
646 // we can't move into anything new during selection
647 if (depth() == anchor_.size())
649 if (!ptr_cmp(t.nucleus(), anchor_[depth()].inset()))
656 bool positionable(DocumentIterator const & cursor,
657 DocumentIterator const & anchor)
659 // avoid deeper nested insets when selecting
660 if (cursor.size() > anchor.size())
663 // anchor might be deeper, should have same path then
664 for (size_t i = 0; i < cursor.size(); ++i)
665 if (cursor[i].inset() != anchor[i].inset())
668 // position should be ok.
673 void LCursor::setScreenPos(int x, int y)
675 bool res = bruteFind(x, y, formula()->xlow(), formula()->xhigh(),
676 formula()->ylow(), formula()->yhigh());
678 // this can happen on creation of "math-display"
687 void LCursor::plainErase()
693 void LCursor::markInsert()
695 cell().insert(pos(), MathAtom(new MathCharInset(0)));
699 void LCursor::markErase()
705 void LCursor::plainInsert(MathAtom const & t)
707 cell().insert(pos(), t);
712 void LCursor::insert(string const & str)
714 lyxerr << "LCursor::insert str '" << str << "'" << endl;
717 for (string::const_iterator it = str.begin(); it != str.end(); ++it)
718 plainInsert(MathAtom(new MathCharInset(*it)));
727 void LCursor::insert(char c)
729 //lyxerr << "LCursor::insert char '" << c << "'" << endl;
731 plainInsert(MathAtom(new MathCharInset(c)));
735 void LCursor::insert(MathAtom const & t)
737 //lyxerr << "LCursor::insert MathAtom: " << endl;
744 void LCursor::insert(InsetBase * inset)
747 insert(MathAtom(inset));
749 text()->insertInset(*this, inset);
753 void LCursor::niceInsert(string const & t)
764 void LCursor::niceInsert(MathAtom const & t)
767 string safe = grabAndEraseSelection();
769 // enter the new inset and move the contents of the selection if possible
772 // be careful here: don't use 'pushLeft(t)' as this we need to
773 // push the clone, not the original
774 pushLeft(nextAtom().nucleus());
780 void LCursor::insert(MathArray const & ar)
785 cell().insert(pos(), ar);
790 bool LCursor::backspace()
792 autocorrect() = false;
800 if (inset()->nargs() == 1 && depth() == 1 && lastpos() == 0)
807 MathUnknownInset * p = activeMacro();
808 if (p->name().size() > 1) {
809 p->setName(p->name().substr(0, p->name().size() - 1));
814 if (pos() != 0 && prevAtom()->nargs() > 0) {
815 // let's require two backspaces for 'big stuff' and
816 // highlight on the first
827 bool LCursor::erase()
829 autocorrect() = false;
838 // delete empty cells if possible
839 if (pos() == lastpos() && inset()->idxDelete(idx()))
842 // special behaviour when in last position of cell
843 if (pos() == lastpos()) {
844 bool one_cell = inset()->nargs() == 1;
845 if (one_cell && depth() == 1 && lastpos() == 0)
851 inset()->idxGlue(idx());
855 if (pos() != lastpos() && inset()->nargs() > 0) {
869 DocumentIterator save = *this;
872 setCursor(save, false);
873 autocorrect() = false;
881 DocumentIterator save = *this;
884 setCursor(save, false);
885 autocorrect() = false;
890 void LCursor::macroModeClose()
894 MathUnknownInset * p = activeMacro();
896 string s = p->name();
900 // do nothing if the macro name is empty
904 string const name = s.substr(1);
906 // prevent entering of recursive macros
907 InsetBase const * macro = innerInsetOfType(InsetBase::MATHMACRO_CODE);
908 if (macro && macro->getInsetName() == name)
909 lyxerr << "can't enter recursive macro" << endl;
911 niceInsert(createMathInset(name));
915 string LCursor::macroName()
917 return inMacroMode() ? activeMacro()->name() : string();
921 void LCursor::handleNest(MathAtom const & a, int c)
923 //lyxerr << "LCursor::handleNest: " << c << endl;
925 asArray(grabAndEraseSelection(), t.nucleus()->cell(c));
928 pushLeft(nextAtom().nucleus());
932 int LCursor::targetX() const
934 if (x_target() != -1)
943 MathHullInset * LCursor::formula() const
945 for (int i = size() - 1; i >= 1; --i) {
946 MathInset * inset = operator[](i).inset()->asMathInset();
947 if (inset && inset->asHullInset())
948 return static_cast<MathHullInset *>(inset);
954 void LCursor::adjust(pos_type from, int diff)
958 if (anchor().pos_ > from)
959 anchor().pos_ += diff;
960 // just to be on the safe side
961 // theoretically unecessary
966 bool LCursor::inMacroMode() const
970 MathUnknownInset const * p = prevAtom()->asUnknownInset();
971 return p && !p->final();
975 MathUnknownInset * LCursor::activeMacro()
977 return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
981 bool LCursor::inMacroArgMode() const
983 return pos() > 0 && prevAtom()->getChar() == '#';
987 MathGridInset * LCursor::enclosingGrid(idx_type & idx) const
989 for (MathInset::difference_type i = depth() - 1; i >= 0; --i) {
990 MathInset * m = operator[](i).inset()->asMathInset();
993 MathGridInset * p = m->asGridInset();
995 idx = operator[](i).idx_;
1003 void LCursor::pullArg()
1006 MathArray ar = cell();
1007 if (popLeft() && inMathed()) {
1009 cell().insert(pos(), ar);
1012 //formula()->mutateToText();
1017 void LCursor::touch()
1021 DocumentIterator::const_iterator it = begin();
1022 DocumentIterator::const_iterator et = end();
1023 for ( ; it != et; ++it)
1029 void LCursor::normalize()
1031 if (idx() >= nargs()) {
1032 lyxerr << "this should not really happen - 1: "
1033 << idx() << ' ' << nargs()
1034 << " in: " << inset() << endl;
1036 idx() = min(idx(), lastidx());
1038 if (pos() > lastpos()) {
1039 lyxerr << "this should not really happen - 2: "
1040 << pos() << ' ' << lastpos() << " in idx: " << idx()
1042 WriteStream wi(lyxerr, false, true);
1043 inset()->asMathInset()->write(wi);
1046 pos() = min(pos(), lastpos());
1050 char LCursor::valign()
1053 MathGridInset * p = enclosingGrid(idx);
1054 return p ? p->valign() : '\0';
1058 char LCursor::halign()
1061 MathGridInset * p = enclosingGrid(idx);
1062 return p ? p->halign(idx % p->ncols()) : '\0';
1066 bool LCursor::goUpDown(bool up)
1068 // Be warned: The 'logic' implemented in this function is highly
1069 // fragile. A distance of one pixel or a '<' vs '<=' _really
1070 // matters. So fiddle around with it only if you think you know
1071 // what you are doing!
1076 // check if we had something else in mind, if not, this is the future goal
1077 if (x_target() == -1)
1082 // try neigbouring script insets
1086 MathScriptInset const * p = prevAtom()->asScriptInset();
1087 if (p && p->has(up)) {
1090 idx() = up; // the superscript has index 1
1092 //lyxerr << "updown: handled by scriptinset to the left" << endl;
1098 if (pos() != lastpos()) {
1099 MathScriptInset const * p = nextAtom()->asScriptInset();
1100 if (p && p->has(up)) {
1104 //lyxerr << "updown: handled by scriptinset to the right" << endl;
1110 // try current cell for e.g. text insets
1111 if (inset()->idxUpDown2(*this, up))
1114 //xarray().boundingBox(xlow, xhigh, ylow, yhigh);
1119 //if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh)) {
1120 // lyxerr << "updown: handled by brute find in the same cell" << endl;
1124 // try to find an inset that knows better then we
1126 //lyxerr << "updown: We are in " << inset() << " idx: " << idx() << endl;
1128 if (inset()->idxUpDown(*this, up)) {
1129 // try to find best position within this inset
1135 // no such inset found, just take something "above"
1136 //lyxerr << "updown: handled by strange case" << endl;
1142 up ? formula()->ylow() : yo + 4,
1143 up ? yo - 4 : formula()->yhigh()
1147 // any improvement so far?
1150 if (up ? ynew < yo : ynew > yo)
1156 bool LCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhigh)
1158 DocumentIterator best_cursor(bv());
1159 double best_dist = 1e10;
1161 DocumentIterator it = bufferBegin(bv());
1162 DocumentIterator et = bufferEnd();
1164 // avoid invalid nesting when selecting
1165 if (!selection() || positionable(it, anchor_)) {
1167 CursorSlice & cur = it.back();
1168 cur.inset()->getCursorPos(cur, xo, yo);
1169 if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
1170 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
1171 //lyxerr << "x: " << x << " y: " << y << " d: " << endl;
1172 // '<=' in order to take the last possible position
1173 // this is important for clicking behind \sum in e.g. '\sum_i a'
1174 if (d <= best_dist) {
1186 if (best_dist < 1e10)
1187 setCursor(best_cursor, false);
1188 return best_dist < 1e10;
1192 void LCursor::bruteFind2(int x, int y)
1194 double best_dist = 1e10;
1196 DocumentIterator it = *this;
1197 it.back().pos() = 0;
1198 DocumentIterator et = *this;
1199 et.back().pos() = et.back().asMathInset()->cell(et.back().idx_).size();
1200 for (int i = 0; ; ++i) {
1202 CursorSlice & cur = it.back();
1203 cur.inset()->getCursorPos(cur, xo, yo);
1204 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
1205 // '<=' in order to take the last possible position
1206 // this is important for clicking behind \sum in e.g. '\sum_i a'
1207 lyxerr << "i: " << i << " d: " << d << " best: " << best_dist << endl;
1208 if (d <= best_dist) {
1210 setCursor(it, false);
1219 CursorSlice LCursor::normalAnchor()
1221 if (anchor_.size() < depth()) {
1223 lyxerr << "unusual Anchor size" << endl;
1225 //lyx::BOOST_ASSERT(Anchor_.size() >= cursor.depth());
1226 // use Anchor on the same level as Cursor
1227 CursorSlice normal = anchor_[size() - 1];
1229 if (depth() < anchor_.size() && !(normal < xx())) {
1230 // anchor is behind cursor -> move anchor behind the inset
1239 DispatchResult dispatch(LCursor & cur, FuncRequest const & cmd)
1241 // mouse clicks are somewhat special
1243 switch (cmd.action) {
1244 case LFUN_MOUSE_PRESS:
1245 case LFUN_MOUSE_MOTION:
1246 case LFUN_MOUSE_RELEASE:
1247 case LFUN_MOUSE_DOUBLE: {
1248 CursorSlice & pos = back();
1252 if (x < cmd.x && pos() != 0) {
1253 DispatchResult const res = prevAtom().nucleus()->dispatch(cmd);
1254 if (res.dispatched())
1257 if (x > cmd.x && pos() != lastpos()) {
1258 DispatchResult const res = inset()->dispatch(cmd);
1259 if (res.dispatched())
1270 void LCursor::handleFont(string const & font)
1272 lyxerr << "LCursor::handleFont: " << font << endl;
1276 safe = grabAndEraseSelection();
1279 if (lastpos() != 0) {
1280 // something left in the cell
1282 // cursor in first position
1284 } else if (pos() == lastpos()) {
1285 // cursor in last position
1288 // cursor in between. split cell
1289 MathArray::iterator bt = cell().begin();
1290 MathAtom at = createMathInset(font);
1291 at.nucleus()->cell(0) = MathArray(bt, bt + pos());
1292 cell().erase(bt, bt + pos());
1297 // nothing left in the cell
1305 void LCursor::message(string const & msg) const
1307 bv().owner()->getLyXFunc().setMessage(msg);
1311 void LCursor::errorMessage(string const & msg) const
1313 bv().owner()->getLyXFunc().setErrorMessage(msg);
1317 string LCursor::selectionAsString(bool label) const
1323 Buffer const & buffer = *bv().buffer();
1325 // should be const ...
1326 ParagraphList::iterator startpit = text()->getPar(selBegin());
1327 ParagraphList::iterator endpit = text()->getPar(selEnd());
1328 size_t const startpos = selBegin().pos();
1329 size_t const endpos = selEnd().pos();
1331 if (startpit == endpit)
1332 return startpit->asString(buffer, startpos, endpos, label);
1334 // First paragraph in selection
1336 startpit->asString(buffer, startpos, startpit->size(), label) + "\n\n";
1338 // The paragraphs in between (if any)
1339 ParagraphList::iterator pit = startpit;
1340 for (++pit; pit != endpit; ++pit)
1341 result += pit->asString(buffer, 0, pit->size(), label) + "\n\n";
1343 // Last paragraph in selection
1344 result += endpit->asString(buffer, 0, endpos, label);
1354 string LCursor::currentState()
1357 std::ostringstream os;
1361 return text() ? text()->currentState(*this) : string();
1365 // only used by the spellchecker
1366 void LCursor::replaceWord(string const & replacestring)
1368 LyXText * t = text();
1371 t->replaceSelectionWithString(*this, replacestring);
1372 t->setSelectionRange(*this, replacestring.length());
1374 // Go back so that replacement string is also spellchecked
1375 for (string::size_type i = 0; i < replacestring.length() + 1; ++i)
1376 t->cursorLeft(*this);
1380 void LCursor::update()
1386 string LCursor::getPossibleLabel()
1388 return inMathed() ? "eq:" : text()->getPossibleLabel(*this);
1392 void LCursor::undispatched()
1394 disp_.dispatched(false);
1398 void LCursor::dispatched(dispatch_result_t res)
1404 void LCursor::noUpdate()
1406 disp_.update(false);
1410 void LCursor::noPop()