X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fcursor.C;h=50d630ec8501b1bb42a8129781f2fe6380658ebf;hb=5ede7e4889b088219326a1d4a94a0a2a732a1379;hp=0722215073d2200be904fb7653098db50cdd3776;hpb=22590a98b36977c2257c66dc2d2a72741432d261;p=lyx.git diff --git a/src/cursor.C b/src/cursor.C index 0722215073..50d630ec85 100644 --- a/src/cursor.C +++ b/src/cursor.C @@ -20,9 +20,10 @@ #include "funcrequest.h" #include "iterators.h" #include "lfuns.h" +#include "lyxfunc.h" // only for setMessage() #include "lyxrc.h" -#include "lyxtext.h" #include "lyxrow.h" +#include "lyxtext.h" #include "paragraph.h" #include "insets/updatableinset.h" @@ -34,6 +35,9 @@ #include "mathed/math_support.h" #include "support/limited_stack.h" +#include "support/std_sstream.h" + +#include "frontends/LyXView.h" #include @@ -75,45 +79,46 @@ void LCursor::reset() DispatchResult LCursor::dispatch(FuncRequest const & cmd0) { - //lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl; + lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl; FuncRequest cmd = cmd0; - - for (int i = cursor_.size() - 1; i >= 1; --i) { - current_ = i; - CursorSlice const & citem = cursor_[i]; - lyxerr << "trying to dispatch to inset " << citem.inset_ << endl; - DispatchResult res = inset()->dispatch(*this, cmd); - if (res.dispatched()) { - lyxerr << " successfully dispatched to inset " << citem.inset_ << endl; - return DispatchResult(true, true); - } - // remove one level of cursor - switch (res.val()) { + disp_.update(true); + disp_.val(NONE); + for (current_ = cursor_.size() - 1; current_ >= 1; --current_) { + // the inset's dispatch() is supposed to reset the update and + // val flags if necessary + inset()->dispatch(*this, cmd); + + // "Mutate" the request for semi-handled requests that need + // additional handling in outer levels. + switch (disp_.val()) { + case NONE: + // the inset handled the event fully + current_ = cursor_.size() - 1; + return DispatchResult(true, true); case FINISHED: - pop(i); + // the inset handled the event partially cmd = FuncRequest(LFUN_FINISHED_LEFT); break; case FINISHED_RIGHT: - pop(i); cmd = FuncRequest(LFUN_FINISHED_RIGHT); break; case FINISHED_UP: - pop(i); cmd = FuncRequest(LFUN_FINISHED_UP); break; case FINISHED_DOWN: - pop(i); cmd = FuncRequest(LFUN_FINISHED_DOWN); break; default: - lyxerr << "not handled on level " << i << " val: " << res.val() << endl; + //lyxerr << "not handled on level " << current_ + // << " val: " << disp_.val() << endl; break; } } - lyxerr << "trying to dispatch to main text " << bv_->text() << endl; - DispatchResult res = bv_->text()->dispatch(*this, cmd); - lyxerr << " result: " << res.val() << endl; - return res; + BOOST_ASSERT(current_ == 0); + bv_->text()->dispatch(*this, cmd); + //lyxerr << " result: " << res.val() << endl; + current_ = cursor_.size() - 1; + return disp_; } @@ -129,24 +134,18 @@ void LCursor::push(InsetBase * inset) void LCursor::pop(int depth) { - //lyxerr << "LCursor::pop() to depth " << depth << endl; - while (int(cursor_.size()) > depth) + while (int(cursor_.size()) > depth + 1) pop(); + lyxerr << "LCursor::pop() result: " << *this << endl; } void LCursor::pop() { - BOOST_ASSERT(!cursor_.empty()); - //lyxerr << "LCursor::pop() a level" << endl; - if (cursor_.size() <= 1) - lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl; - else { - cursor_.pop_back(); - anchor_.pop_back(); - current_ = cursor_.size() - 1; - } - //lyxerr << "LCursor::pop() current now: " << current_ << endl; + BOOST_ASSERT(cursor_.size() >= 1); + cursor_.pop_back(); + anchor_.pop_back(); + current_ = cursor_.size() - 1; } @@ -185,7 +184,7 @@ bool LCursor::popRight() } inset()->notifyCursorLeaves(idx()); pop(); - posRight(); + ++pos(); return true; } @@ -222,7 +221,6 @@ int LCursor::currentMode() LyXText * LCursor::innerText() const { BOOST_ASSERT(!cursor_.empty()); - //lyxerr << "LCursor::innerText() depth: " << cursor_.size() << endl; if (cursor_.size() > 1) { // go up until first non-0 text is hit // (innermost text is 0 in mathed) @@ -237,7 +235,6 @@ LyXText * LCursor::innerText() const CursorSlice const & LCursor::innerTextSlice() const { BOOST_ASSERT(!cursor_.empty()); - //lyxerr << "LCursor::innerTextSlice() depth: " << cursor_.size() << endl; if (cursor_.size() > 1) { // go up until first non-0 text is hit // (innermost text is 0 in mathed) @@ -261,21 +258,16 @@ void LCursor::updatePos() void LCursor::getDim(int & asc, int & des) const { BOOST_ASSERT(!cursor_.empty()); - LyXText * text = innerText(); -#warning crashes with text-in-math - if (0 && text) { - RowList::iterator const rit = text->cursorRow(); - if (rit != text->endRow()) { - asc = rit->baseline(); - des = rit->height() - asc; - } else { - asc = 10; - des = 10; - } - } else { + if (inMathed()) { + BOOST_ASSERT(inset()); + BOOST_ASSERT(inset()->asMathInset()); + //inset()->asMathInset()->getCursorDim(asc, des); asc = 10; des = 10; - //innerInset()->getCursorDim(asc, des); + } else { + Row const & row = textRow(); + asc = row.baseline(); + des = row.height() - asc; } } @@ -285,10 +277,14 @@ void LCursor::getPos(int & x, int & y) const BOOST_ASSERT(!cursor_.empty()); x = 0; y = 0; - if (cursor_.size() <= 1) { + if (cursor_.size() == 1) { x = bv_->text()->cursorX(cursor_.front()); y = bv_->text()->cursorY(cursor_.front()); } else { + if (!inset()) { + lyxerr << "#### LCursor::getPos: " << *this << endl; + BOOST_ASSERT(inset()); + } inset()->getCursorPos(cursor_.back(), x, y); // getCursorPos gives _screen_ coordinates. We need to add // top_y to get document coordinates. This is hidden in cached_y_. @@ -301,7 +297,8 @@ void LCursor::getPos(int & x, int & y) const // inset.yo_, so getCursor() returns an old value. // Ugly as you like. } - lyxerr << "#### LCursor::getPos: x: " << x << " y: " << y << endl; + //lyxerr << "#### LCursor::getPos: " << *this + // << " x: " << x << " y: " << y << endl; } @@ -400,7 +397,6 @@ CursorSlice const & LCursor::selBegin() const { if (!selection()) return cursor_.back(); - // can't use std::min as this creates a new object return anchor() < cursor_.back() ? anchor() : cursor_.back(); } @@ -409,6 +405,7 @@ CursorSlice & LCursor::selBegin() { if (!selection()) return cursor_.back(); + // can't use std::min as this returns a const ref return anchor() < cursor_.back() ? anchor() : cursor_.back(); } @@ -423,8 +420,9 @@ CursorSlice const & LCursor::selEnd() const CursorSlice & LCursor::selEnd() { - if (selection()) + if (!selection()) return cursor_.back(); + // can't use std::min as this returns a const ref return anchor() > cursor_.back() ? anchor() : cursor_.back(); } @@ -482,18 +480,30 @@ LyXText * LCursor::text() const Paragraph & LCursor::paragraph() { - BOOST_ASSERT(!inMathed()); + BOOST_ASSERT(inTexted()); return current_ ? current().paragraph() : *bv_->text()->getPar(par()); } Paragraph const & LCursor::paragraph() const { - BOOST_ASSERT(!inMathed()); + BOOST_ASSERT(inTexted()); return current_ ? current().paragraph() : *bv_->text()->getPar(par()); } +Row & LCursor::textRow() +{ + return *paragraph().getRow(pos()); +} + + +Row const & LCursor::textRow() const +{ + return *paragraph().getRow(pos()); +} + + LCursor::par_type LCursor::lastpar() const { return inMathed() ? 0 : text()->paragraphs().size() - 1; @@ -568,15 +578,14 @@ MathArray & LCursor::cell() } -void LCursor::info(std::ostream & os) +void LCursor::info(std::ostream & os) const { for (int i = 1, n = depth(); i < n; ++i) { cursor_[i].inset()->infoize(os); os << " "; } -#warning FIXME - //if (pos() != 0) - // prevAtom()->infoize2(os); + if (pos() != 0) + prevInset()->infoize2(os); // overwite old message os << " "; } @@ -643,8 +652,9 @@ string LCursor::grabSelection() void LCursor::eraseSelection() { - CursorSlice i1 = selBegin(); - CursorSlice i2 = selEnd(); + //lyxerr << "LCursor::eraseSelection" << endl; + CursorSlice const & i1 = selBegin(); + CursorSlice const & i2 = selEnd(); #warning FIXME if (i1.inset()->asMathInset()) { if (i1.idx_ == i2.idx_) { @@ -662,6 +672,7 @@ void LCursor::eraseSelection() } else { lyxerr << "can't erase this selection 1" << endl; } + //lyxerr << "LCursor::eraseSelection end" << endl; } @@ -702,6 +713,7 @@ void LCursor::selCut() void LCursor::selDel() { + //lyxerr << "LCursor::selDel" << endl; if (selection()) { eraseSelection(); selection() = false; @@ -721,6 +733,7 @@ void LCursor::selPaste(size_t n) void LCursor::selHandle(bool sel) { + //lyxerr << "LCursor::selHandle" << endl; if (sel == selection()) return; resetAnchor(); @@ -728,15 +741,9 @@ void LCursor::selHandle(bool sel) } -void LCursor::selStart() -{ - resetAnchor(); - selection() = true; -} - - void LCursor::selClearOrDel() { + //lyxerr << "LCursor::selClearOrDel" << endl; if (lyxrc.auto_region_delete) selDel(); else @@ -746,10 +753,11 @@ void LCursor::selClearOrDel() std::ostream & operator<<(std::ostream & os, LCursor const & cur) { - os << "\n"; for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i) - os << " (" << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n"; - return os << "current: " << cur.current_ << endl; + os << " " << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n"; + os << " current: " << cur.current_ << endl; + os << " selection: " << cur.selection_ << endl; + return os; } @@ -867,7 +875,7 @@ bool LCursor::openable(MathAtom const & t) // we can't move into anything new during selection if (depth() == anchor_.size()) return false; - if (t.nucleus() != anchor_[depth()].inset()) + if (!ptr_cmp(t.nucleus(), anchor_[depth()].inset())) return false; return true; @@ -996,26 +1004,24 @@ void LCursor::plainInsert(MathAtom const & t) } -void LCursor::insert2(string const & str) -{ - MathArray ar; - asArray(str, ar); - insert(ar); -} - - void LCursor::insert(string const & str) { - lyxerr << "inserting '" << str << "'" << endl; + lyxerr << "LCursor::insert str '" << str << "'" << endl; selClearOrDel(); +#if 0 for (string::const_iterator it = str.begin(); it != str.end(); ++it) plainInsert(MathAtom(new MathCharInset(*it))); +#else + MathArray ar; + asArray(str, ar); + insert(ar); +#endif } void LCursor::insert(char c) { - lyxerr << "inserting '" << c << "'" << endl; + //lyxerr << "LCursor::insert char '" << c << "'" << endl; selClearOrDel(); plainInsert(MathAtom(new MathCharInset(c))); } @@ -1023,15 +1029,24 @@ void LCursor::insert(char c) void LCursor::insert(MathAtom const & t) { + //lyxerr << "LCursor::insert MathAtom: " << endl; macroModeClose(); selClearOrDel(); plainInsert(t); } +void LCursor::insert(InsetBase * inset) +{ + if (inMathed()) + insert(MathAtom(inset)); + else + text()->insertInset(*this, inset); +} + + void LCursor::niceInsert(string const & t) { - lyxerr << "*** LCursor::niceInsert 1: " << t << endl; MathArray ar; asArray(t, ar); if (ar.size() == 1) @@ -1043,17 +1058,17 @@ void LCursor::niceInsert(string const & t) void LCursor::niceInsert(MathAtom const & t) { - lyxerr << "*** LCursor::niceInsert 2: " << t << endl; macroModeClose(); string safe = grabAndEraseSelection(); plainInsert(t); // enter the new inset and move the contents of the selection if possible if (t->isActive()) { posLeft(); + // be careful here: don't use 'pushLeft(t)' as this we need to + // push the clone, not the original pushLeft(nextAtom().nucleus()); paste(safe); } - lyxerr << "*** LCursor::niceInsert 3: " << t << endl; } @@ -1200,11 +1215,12 @@ string LCursor::macroName() void LCursor::handleNest(MathAtom const & a, int c) { + //lyxerr << "LCursor::handleNest: " << c << endl; MathAtom t = a; asArray(grabAndEraseSelection(), t.nucleus()->cell(c)); insert(t); posLeft(); - pushLeft(t.nucleus()); + pushLeft(nextAtom().nucleus()); } @@ -1221,9 +1237,11 @@ int LCursor::targetX() const MathHullInset * LCursor::formula() const { - for (int i = cursor_.size() - 1; i >= 1; --i) - if (cursor_[i].inset()->lyxCode() == InsetBase::MATH_CODE) - return static_cast(cursor_[i].inset()); + for (int i = cursor_.size() - 1; i >= 1; --i) { + MathInset * inset = cursor_[i].inset()->asMathInset(); + if (inset && inset->asHullInset()) + return static_cast(inset); + } return 0; } @@ -1279,17 +1297,15 @@ MathGridInset * LCursor::enclosingGrid(idx_type & idx) const void LCursor::pullArg() { -#warning look here -#if 0 +#warning Look here MathArray ar = cell(); - if (popLeft()) { + if (popLeft() && inMathed()) { plainErase(); cell().insert(pos(), ar); resetAnchor(); } else { - formula()->mutateToText(); + //formula()->mutateToText(); } -#endif } @@ -1312,7 +1328,7 @@ void LCursor::normalize() << idx() << ' ' << nargs() << " in: " << inset() << endl; } - idx() = min(idx(), nargs() - 1); + idx() = min(idx(), lastidx()); if (pos() > lastpos()) { lyxerr << "this should not really happen - 2: " @@ -1344,9 +1360,10 @@ char LCursor::halign() bool LCursor::goUpDown(bool up) { - // Be warned: The 'logic' implemented in this function is highly fragile. - // A distance of one pixel or a '<' vs '<=' _really_ matters. - // So fiddle around with it only if you know what you are doing! + // Be warned: The 'logic' implemented in this function is highly + // fragile. A distance of one pixel or a '<' vs '<=' _really + // matters. So fiddle around with it only if you think you know + // what you are doing! int xo = 0; int yo = 0; getPos(xo, yo); @@ -1472,10 +1489,9 @@ void LCursor::bruteFind2(int x, int y) double best_dist = 1e10; CursorBase it = cursor_; - it.back().pos(0); + it.back().pos() = 0; CursorBase et = cursor_; - int n = et.back().asMathInset()->cell(et.back().idx_).size(); - et.back().pos(n); + et.back().pos() = et.back().asMathInset()->cell(et.back().idx_).size(); for (int i = 0; ; ++i) { int xo, yo; CursorSlice & cur = it.back(); @@ -1536,22 +1552,22 @@ bool LCursor::script(bool up) idx() = up; pos() = 0; } else if (pos() != 0 && prevAtom()->asScriptInset()) { - prevAtom().nucleus()->asScriptInset()->ensure(up); - posLeft(); - push(inset()); + --pos(); + nextAtom().nucleus()->asScriptInset()->ensure(up); + push(nextInset()); idx() = up; pos() = lastpos(); } else if (pos() != 0) { --pos(); cell()[pos()] = MathAtom(new MathScriptInset(nextAtom(), up)); - push(inset()); + push(nextInset()); idx() = up; pos() = 0; } else { plainInsert(MathAtom(new MathScriptInset(up))); - posLeft(); + --pos(); nextAtom().nucleus()->asScriptInset()->ensure(up); - push(inset()); + push(nextInset()); idx() = up; pos() = 0; } @@ -1562,7 +1578,7 @@ bool LCursor::script(bool up) bool LCursor::interpret(char c) { - lyxerr << "interpret 2: '" << c << "'" << endl; + //lyxerr << "interpret 2: '" << c << "'" << endl; clearTargetX(); if (inMacroArgMode()) { posLeft(); @@ -1707,7 +1723,7 @@ void LCursor::lockToggle() } else if (popLeft() && pos() != lastpos()) { // ... or enclosing inset if we are in the last inset position nextAtom().nucleus()->lock(!nextAtom()->lock()); - posRight(); + ++pos(); } } @@ -1765,6 +1781,7 @@ DispatchResult dispatch(LCursor & cur, FuncRequest const & cmd) void LCursor::handleFont(string const & font) { + lyxerr << "LCursor::handleFont: " << font << endl; string safe; if (selection()) { macroModeClose(); @@ -1797,16 +1814,15 @@ void LCursor::handleFont(string const & font) } -void LCursor::releaseMathCursor() +bool LCursor::inMathed() const { - if (inMathed()) - formula()->insetUnlock(bv()); + return formula(); } -bool LCursor::inMathed() const +bool LCursor::inTexted() const { - return formula(); + return !formula(); } @@ -1816,8 +1832,7 @@ InsetBase * LCursor::nextInset() return 0; if (inMathed()) return nextAtom().nucleus(); - Paragraph & par = paragraph(); - return par.isInset(pos()) ? par.getInset(pos()) : 0; + return paragraph().isInset(pos()) ? paragraph().getInset(pos()) : 0; } @@ -1827,7 +1842,120 @@ InsetBase * LCursor::prevInset() return 0; if (inMathed()) return prevAtom().nucleus(); - Paragraph & par = paragraph(); - return par.isInset(pos() - 1) ? par.getInset(pos() - 1) : 0; + return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0; +} + + +InsetBase const * LCursor::prevInset() const +{ + if (pos() == 0) + return 0; + if (inMathed()) + return prevAtom().nucleus(); + return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0; +} + + +void LCursor::message(string const & msg) const +{ + bv().owner()->getLyXFunc().setMessage(msg); +} + + +void LCursor::errorMessage(string const & msg) const +{ + bv().owner()->getLyXFunc().setErrorMessage(msg); +} + + +string LCursor::selectionAsString(bool label) const +{ + if (!selection()) + return string(); + + if (inTexted()) { + Buffer const & buffer = *bv().buffer(); + + // should be const ... + ParagraphList::iterator startpit = text()->getPar(selBegin()); + ParagraphList::iterator endpit = text()->getPar(selEnd()); + size_t const startpos = selBegin().pos(); + size_t const endpos = selEnd().pos(); + + if (startpit == endpit) + return startpit->asString(buffer, startpos, endpos, label); + + // First paragraph in selection + string result = + startpit->asString(buffer, startpos, startpit->size(), label) + "\n\n"; + + // The paragraphs in between (if any) + ParagraphList::iterator pit = startpit; + for (++pit; pit != endpit; ++pit) + result += pit->asString(buffer, 0, pit->size(), label) + "\n\n"; + + // Last paragraph in selection + result += endpit->asString(buffer, 0, endpos, label); + + return result; + } + +#warning an mathed? + return string(); +} + + +string LCursor::currentState() +{ + if (inMathed()) { + std::ostringstream os; + info(os); + return os.str(); + } + return text() ? text()->currentState(*this) : string(); +} + + +// only used by the spellchecker +void LCursor::replaceWord(string const & replacestring) +{ + LyXText * t = text(); + BOOST_ASSERT(t); + + t->replaceSelectionWithString(*this, replacestring); + t->setSelectionRange(*this, replacestring.length()); + + // Go back so that replacement string is also spellchecked + for (string::size_type i = 0; i < replacestring.length() + 1; ++i) + t->cursorLeft(*this, true); +} + + +void LCursor::update() +{ + bv().update(); +} + + +string LCursor::getPossibleLabel() +{ + return inMathed() ? "eq:" : text()->getPossibleLabel(*this); +} + + +void LCursor::notdispatched() +{ + disp_.dispatched(false); +} + + +void LCursor::dispatched(dispatch_result_t res) +{ + disp_.val(res); } + +void LCursor::noupdate() +{ + disp_.update(false); +}