]> git.lyx.org Git - lyx.git/blobdiff - src/cursor.C
rename a function
[lyx.git] / src / cursor.C
index 0722215073d2200be904fb7653098db50cdd3776..50d630ec8501b1bb42a8129781f2fe6380658ebf 100644 (file)
 #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 <boost/assert.hpp>
 
@@ -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<MathHullInset *>(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<MathHullInset *>(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);
+}