]> git.lyx.org Git - lyx.git/blobdiff - src/Cursor.cpp
Provide proper fallback if a bibliography processor is not found
[lyx.git] / src / Cursor.cpp
index 05389d9845b755c32f215ff010f9f42dd9e2ea0c..bdfba6114bc776d61b28fc196f6d4736bf54924a 100644 (file)
@@ -21,7 +21,6 @@
 #include "Cursor.h"
 #include "CutAndPaste.h"
 #include "DispatchResult.h"
-#include "Encoding.h"
 #include "Font.h"
 #include "FuncCode.h"
 #include "FuncRequest.h"
@@ -53,7 +52,7 @@
 #include "mathed/MacroTable.h"
 #include "mathed/MathData.h"
 #include "mathed/MathFactory.h"
-#include "mathed/MathMacro.h"
+#include "mathed/InsetMathMacro.h"
 
 #include <sstream>
 #include <limits>
@@ -115,7 +114,7 @@ DocIterator bruteFind(Cursor const & c, int x, int y)
 }
 
 
-} // namespace anon
+} // namespace
 
 
 CursorData::CursorData()
@@ -454,19 +453,6 @@ int Cursor::currentMode()
 }
 
 
-bool Cursor::inCoordCache() const
-{
-       // the root inset is not in cache, but we do not need it.
-       if (depth() == 1)
-               return true;
-       CoordCache::Insets const & icache = bv_->coordCache().getInsets();
-       for (size_t i = 1 ; i < depth() ; ++i)
-               if (!icache.has(&(*this)[i].inset()))
-                       return false;
-       return true;
-}
-
-
 void Cursor::getPos(int & x, int & y) const
 {
        Point p = bv().getPos(*this);
@@ -758,7 +744,7 @@ bool findNonVirtual(Row const & row, Row::const_iterator & cit, bool onleft)
        return cit != row.end() && !cit->isVirtual();
 }
 
-}
+} // namespace
 
 void Cursor::getSurroundingPos(pos_type & left_pos, pos_type & right_pos) const
 {
@@ -1028,6 +1014,56 @@ void Cursor::clearSelection()
 }
 
 
+int Cursor::countInsetsInSelection(InsetCode const & inset_code)
+{
+       if (!selection_)
+               return 0;
+
+       DocIterator from, to;
+       from = selectionBegin();
+       to = selectionEnd();
+
+       int count = 0;
+
+       if (!from.nextInset())      //move to closest inset
+               from.forwardInset();
+
+       while (!from.empty() && from < to) {
+               Inset * inset = from.nextInset();
+               if (!inset)
+                       break;
+               if (inset->lyxCode() == inset_code)
+                       count ++;
+               from.forwardInset();
+       }
+       return count;
+}
+
+
+bool Cursor::insetInSelection(InsetCode const & inset_code)
+{
+       if (!selection_)
+               return false;
+
+       DocIterator from, to;
+       from = selectionBegin();
+       to = selectionEnd();
+
+       if (!from.nextInset())      //move to closest inset
+               from.forwardInset();
+
+       while (!from.empty() && from < to) {
+               Inset * inset = from.nextInset();
+               if (!inset)
+                       break;
+               if (inset->lyxCode() == inset_code)
+                       return true;
+               from.forwardInset();
+       }
+       return false;
+}
+
+
 void Cursor::setTargetX(int x)
 {
        x_target_ = x;
@@ -1057,7 +1093,7 @@ void Cursor::updateTextTargetOffset()
 }
 
 
-void Cursor::info(odocstream & os) const
+void Cursor::info(odocstream & os, bool devel_mode) const
 {
        for (int i = 1, n = depth(); i < n; ++i) {
                operator[](i).inset().infoize(os);
@@ -1069,6 +1105,14 @@ void Cursor::info(odocstream & os) const
                if (inset)
                        prevInset()->infoize2(os);
        }
+       if (devel_mode) {
+               InsetMath * math = inset().asInsetMath();
+               if (math)
+                       os << _(", Inset: ") << math->id();
+               os << _(", Cell: ") << idx();
+               os << _(", Position: ") << pos();
+       }
+
 }
 
 
@@ -1303,9 +1347,20 @@ bool Cursor::backspace(bool const force)
                        // [|], can not delete from inside
                        return false;
                } else {
-                       if (inMathed())
-                               pullArg();
-                       else
+                       if (inMathed()) {
+                               switch (inset().asInsetMath()->getType()) {
+                               case hullEqnArray:
+                               case hullAlign:
+                               case hullFlAlign: {
+                                       FuncRequest cmd(LFUN_CHAR_BACKWARD);
+                                       this->dispatch(cmd);
+                                       break;
+                               }
+                               default:
+                                       pullArg();
+                                       break;
+                               }
+                       } else
                                popBackward();
                        return true;
                }
@@ -1406,7 +1461,7 @@ bool Cursor::down()
 }
 
 
-bool Cursor::macroModeClose()
+bool Cursor::macroModeClose(bool cancel)
 {
        if (!inMacroMode())
                return false;
@@ -1418,36 +1473,37 @@ bool Cursor::macroModeClose()
        --pos();
        cell().erase(pos());
 
-       // do nothing if the macro name is empty
-       if (s == "\\")
-               return false;
-
        // trigger updates of macros, at least, if no full
        // updates take place anyway
        screenUpdateFlags(Update::Force);
 
+       // do nothing if the macro name is empty
+       if (s == "\\" || cancel) {
+               return false;
+       }
+
        docstring const name = s.substr(1);
        InsetMathNest * const in = inset().asInsetMath()->asNestInset();
        if (in && in->interpretString(*this, s))
                return true;
        bool const user_macro = buffer()->getMacro(name, *this, false);
-       MathAtom atom = user_macro ? MathAtom(new MathMacro(buffer(), name))
+       MathAtom atom = user_macro ? MathAtom(new InsetMathMacro(buffer(), name))
                                   : createInsetMath(name, buffer());
 
        // try to put argument into macro, if we just inserted a macro
        bool macroArg = false;
-       MathMacro * atomAsMacro = atom.nucleus()->asMacro();
+       InsetMathMacro * atomAsMacro = atom.nucleus()->asMacro();
        if (atomAsMacro) {
                // macros here are still unfolded (in init mode in fact). So
                // we have to resolve the macro here manually and check its arity
                // to put the selection behind it if arity > 0.
                MacroData const * data = buffer()->getMacro(atomAsMacro->name());
-               if (!selection.empty() && data && data->numargs() - data->optionals() > 0) {
+               if (!selection.empty() && data && data->numargs()) {
                        macroArg = true;
-                       atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 1);
+                       atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 1);
                } else
                        // non-greedy case. Do not touch the arguments behind
-                       atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 0);
+                       atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 0);
        }
 
        // insert remembered selection into first argument of a non-macro
@@ -1456,9 +1512,10 @@ bool Cursor::macroModeClose()
 
        MathWordList const & words = mathedWordList();
        MathWordList::const_iterator it = words.find(name);
-       bool keep_mathmode = it != words.end() && (it->second.inset == "font"
-                                               || it->second.inset == "oldfont"
-                                               || it->second.inset == "mbox");
+       bool keep_mathmode = user_macro
+               || (it != words.end() && (it->second.inset == "font"
+                                         || it->second.inset == "oldfont"
+                                         || it->second.inset == "mbox"));
        bool ert_macro = !user_macro && it == words.end() && atomAsMacro;
 
        if (in && in->currentMode() == Inset::TEXT_MODE
@@ -1499,8 +1556,11 @@ docstring Cursor::macroName()
 void Cursor::handleNest(MathAtom const & a, int c)
 {
        //lyxerr << "Cursor::handleNest: " << c << endl;
+       InsetMath const * im = selectionBegin().inset().asInsetMath();
+       Parse::flags const f = im && im->currentMode() != InsetMath::MATH_MODE
+               ? Parse::TEXTMODE : Parse::NORMAL;
        MathAtom t = a;
-       asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c));
+       asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c), f);
        insert(t);
        posBackward();
        pushBackward(*nextInset());
@@ -1738,11 +1798,23 @@ bool Cursor::mathForward(bool word)
        LASSERT(inMathed(), return false);
        if (pos() < lastpos()) {
                if (word) {
-                       // word: skip a group of insets with same math class
+                       // word: skip a group of insets of the form X*(B*|R*|P*) (greedy
+                       // match) where X is any math class, B is mathbin, R is mathrel, and
+                       // P is mathpunct. Make sure that the following remains true:
+                       //   mathForward(true); mathBackward(true); mathForward(true)
+                       // is the same as mathForward(true) and
+                       //   mathBackward(true); mathForward(true); mathBackward(true)
+                       // is the same as mathBackward(true).
                        MathClass mc = nextMath().mathClass();
                        do
                                posForward();
                        while (pos() < lastpos() && mc == nextMath().mathClass());
+                       if (pos() < lastpos() &&
+                           ((mc = nextMath().mathClass()) == MC_BIN ||
+                            mc == MC_REL || mc == MC_PUNCT))
+                               do
+                                       posForward();
+                               while (pos() < lastpos() && mc == nextMath().mathClass());
                } else if (openable(nextAtom())) {
                        // single step: try to enter the next inset
                        pushBackward(nextMath());
@@ -1767,11 +1839,17 @@ bool Cursor::mathBackward(bool word)
        LASSERT(inMathed(), return false);
        if (pos() > 0) {
                if (word) {
-                       // word: skip a group of insets with same math class
+                       // word: skip a group of insets. See the comment in mathForward.
                        MathClass mc = prevMath().mathClass();
                        do
                                posBackward();
                        while (pos() > 0 && mc == prevMath().mathClass());
+                       if (pos() > 0 && (mc == MC_BIN || mc == MC_REL || mc == MC_PUNCT)) {
+                               mc = prevMath().mathClass();
+                               do
+                                       posBackward();
+                               while (pos() > 0 && mc == prevMath().mathClass());
+                       }
                } else if (openable(prevAtom())) {
                        // single step: try to enter the preceding inset
                        posBackward();
@@ -1906,10 +1984,13 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
                int yo = bv().getPos(*this).y_;
                Cursor old = *this;
                // To next/previous row
+               // FIXME: the y position is often guessed wrongly across styles and
+               // insets, which leads to weird behaviour.
                if (up)
                        tm.editXY(*this, xo, yo - textRow().ascent() - 1);
                else
                        tm.editXY(*this, xo, yo + textRow().descent() + 1);
+               x_target_ = old.x_target_;
                clearSelection();
 
                // This happens when you move out of an inset.
@@ -1958,6 +2039,8 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
                bool bound = false;
                top().pos() = tm.getPosNearX(real_next_row, xo, bound);
                boundary(bound);
+               // When selection==false, this is done by TextMetrics::editXY
+               setCurrentFont();
 
                updateNeeded |= bv().checkDepm(*this, old);
        }
@@ -2033,7 +2116,7 @@ docstring parbreak(Cursor const * cur)
        return os.str();
 }
 
-}
+} // namespace
 
 
 docstring Cursor::selectionAsString(bool with_label) const
@@ -2085,23 +2168,16 @@ docstring Cursor::selectionAsString(bool with_label) const
 }
 
 
-docstring Cursor::currentState() const
+docstring Cursor::currentState(bool devel_mode) const
 {
        if (inMathed()) {
                odocstringstream os;
-               info(os);
-#ifdef DEVEL_VERSION
-               InsetMath * math = inset().asInsetMath();
-               if (math)
-                       os << _(", Inset: ") << math->id();
-               os << _(", Cell: ") << idx();
-               os << _(", Position: ") << pos();
-#endif
+               info(os, devel_mode);
                return os.str();
        }
 
        if (inTexted())
-               return text()->currentState(*this);
+               return text()->currentState(*this, devel_mode);
 
        return docstring();
 }
@@ -2113,22 +2189,6 @@ docstring Cursor::getPossibleLabel() const
 }
 
 
-Encoding const * Cursor::getEncoding() const
-{
-       if (empty())
-               return 0;
-       BufferParams const & bp = bv().buffer().params();
-       if (bp.useNonTeXFonts)
-               return encodings.fromLyXName("utf8-plain");
-
-       CursorSlice const & sl = innerTextSlice();
-       Text const & text = *sl.text();
-       Font font = text.getPar(sl.pit()).getFont(bp, sl.pos(),
-                                                 text.outerFont(sl.pit()));
-       return font.language()->encoding();
-}
-
-
 void Cursor::undispatched() const
 {
        disp_.dispatched(false);
@@ -2425,8 +2485,8 @@ bool Cursor::confirmDeletion(bool const before) const
                        return inset->confirmDeletion();
        } else {
                DocIterator dit = selectionBegin();
-               DocIterator const sel_end = selectionEnd();
-               for (; dit < sel_end; dit.posForward())
+               CursorSlice const end = selectionEnd().top();
+               for (; dit.top() < end; dit.top().forwardPos())
                        if (Inset const * inset = dit.nextInset())
                                if (inset->confirmDeletion())
                                        return true;
@@ -2435,4 +2495,22 @@ bool Cursor::confirmDeletion(bool const before) const
 }
 
 
+void Cursor::moveToClosestEdge(int const x, bool const edit)
+{
+       if (Inset const * inset = nextInset()) {
+               // stay in front of insets for which we want to open the dialog
+               // (e.g. InsetMathSpace).
+               if (edit && (inset->hasSettings() || !inset->contextMenuName().empty()))
+                       return;
+               CoordCache::Insets const & insetCache = bv().coordCache().getInsets();
+               if (!insetCache.has(inset))
+                       return;
+               int const wid = insetCache.dim(inset).wid;
+               Point p = insetCache.xy(inset);
+               if (x > p.x_ + (wid + 1) / 2)
+                       posForward();
+       }
+}
+
+
 } // namespace lyx