]> git.lyx.org Git - lyx.git/blobdiff - src/text3.C
fix crash when collapsing ert with cursor inside
[lyx.git] / src / text3.C
index e46b83972155339d13ccfa9cb4015d2e309f6f76..1f706305193f81c68058b2f9a2b366e563609f65 100644 (file)
@@ -20,6 +20,7 @@
 #include "FloatList.h"
 #include "FuncStatus.h"
 #include "buffer.h"
+#include "buffer_funcs.h"
 #include "bufferparams.h"
 #include "BufferView.h"
 #include "cursor.h"
@@ -32,6 +33,7 @@
 #include "gettext.h"
 #include "intl.h"
 #include "language.h"
+#include "LyXAction.h"
 #include "lyxfunc.h"
 #include "lyxlex.h"
 #include "lyxrc.h"
@@ -59,6 +61,8 @@
 #include "mathed/math_hullinset.h"
 #include "mathed/math_macrotemplate.h"
 
+#include <boost/current_function.hpp>
+
 #include <clocale>
 #include <sstream>
 
@@ -70,15 +74,11 @@ using lyx::cap::pasteSelection;
 using lyx::cap::replaceSelection;
 
 using lyx::support::isStrUnsignedInt;
-using lyx::support::strToUnsignedInt;
-using lyx::support::atoi;
 using lyx::support::token;
 
 using std::endl;
-using std::find;
 using std::string;
 using std::istringstream;
-using std::vector;
 
 
 extern string current_layout;
@@ -182,78 +182,7 @@ string const freefont2string()
 
 }
 
-bool LyXText::gotoNextInset(LCursor & cur,
-       vector<InsetBase_code> const & codes, string const & contents)
-{
-       BOOST_ASSERT(this == cur.text());
-       pit_type end = paragraphs().size();
-       pit_type pit = cur.pit();
-       pos_type pos = cur.pos();
-
-       InsetBase * inset;
-       do {
-               if (pos + 1 < pars_[pit].size()) {
-                       ++pos;
-               } else  {
-                       ++pit;
-                       pos = 0;
-               }
-
-       } while (pit != end &&
-                !(pars_[pit].isInset(pos) &&
-                  (inset = pars_[pit].getInset(pos)) != 0 &&
-                  find(codes.begin(), codes.end(), inset->lyxCode()) != codes.end() &&
-                  (contents.empty() ||
-                   static_cast<InsetCommand *>(pars_[pit].getInset(pos))->getContents()
-                   == contents)));
-
-       if (pit == end)
-               return false;
-
-       setCursor(cur, pit, pos, false);
-       return true;
-}
-
-
-void LyXText::gotoInset(LCursor & cur,
-       vector<InsetBase_code> const & codes, bool same_content)
-{
-       cur.clearSelection();
-
-       string contents;
-       if (same_content
-           && cur.pos() < cur.lastpos()
-           && cur.paragraph().isInset(cur.pos())) {
-               InsetBase const * inset = cur.paragraph().getInset(cur.pos());
-               if (find(codes.begin(), codes.end(), inset->lyxCode())
-                   != codes.end())
-                       contents = static_cast<InsetCommand const *>(inset)->getContents();
-       }
-
-       if (!gotoNextInset(cur, codes, contents)) {
-               if (cur.pos() || cur.pit() != 0) {
-                       CursorSlice tmp = cur.top();
-                       cur.pit() = 0;
-                       cur.pos() = 0;
-                       if (!gotoNextInset(cur, codes, contents)) {
-                               cur.top() = tmp;
-                               cur.message(_("No more insets"));
-                       }
-               } else {
-                       cur.message(_("No more insets"));
-               }
-       }
-       cur.resetAnchor();
-}
-
-
-void LyXText::gotoInset(LCursor & cur, InsetBase_code code, bool same_content)
-{
-       gotoInset(cur, vector<InsetBase_code>(1, code), same_content);
-}
-
-
-void LyXText::cursorPrevious(LCursor & cur)
+bool LyXText::cursorPrevious(LCursor & cur)
 {
        pos_type cpos = cur.pos();
        lyx::pit_type cpar = cur.pit();
@@ -261,36 +190,38 @@ void LyXText::cursorPrevious(LCursor & cur)
        int x = cur.x_target();
 
        setCursorFromCoordinates(cur, x, 0);
-       cursorUp(cur);
+       bool updated = cursorUp(cur);
 
        if (cpar == cur.pit() && cpos == cur.pos()) {
                // we have a row which is taller than the workarea. The
                // simplest solution is to move to the previous row instead.
-               cursorUp(cur);
+               updated |= cursorUp(cur);
        }
 
        cur.bv().updateScrollbar();
        finishUndo();
+       return updated;
 }
 
 
-void LyXText::cursorNext(LCursor & cur)
+bool LyXText::cursorNext(LCursor & cur)
 {
        pos_type cpos = cur.pos();
        lyx::pit_type cpar = cur.pit();
 
        int x = cur.x_target();
        setCursorFromCoordinates(cur, x, cur.bv().workHeight() - 1);
-       cursorDown(cur);
+       bool updated = cursorDown(cur);
 
        if (cpar == cur.pit() && cpos == cur.pos()) {
                // we have a row which is taller than the workarea. The
                // simplest solution is to move to the next row instead.
-               cursorDown(cur);
+               updated |= cursorDown(cur);
        }
 
        cur.bv().updateScrollbar();
        finishUndo();
+       return updated;
 }
 
 
@@ -355,13 +286,13 @@ bool LyXText::isRTL(Paragraph const & par) const
 void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
 {
        lyxerr[Debug::ACTION] << "LyXText::dispatch: cmd: " << cmd << endl;
-       //lyxerr << "*** LyXText::dispatch: cmd: " << cmd << endl;
+       lyxerr << "*** LyXText::dispatch: cmd: " << cmd << endl;
 
        BOOST_ASSERT(cur.text() == this);
        BufferView * bv = &cur.bv();
-       CursorSlice sl = cur.top();
+       CursorSlice oldTopSlice = cur.top();
        bool sel = cur.selection();
-       bool moving = false;
+       bool needsUpdate = !lyxaction.funcHasFlag(cmd.action, LyXAction::NoUpdate);
 
        switch (cmd.action) {
 
@@ -369,6 +300,10 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                Paragraph & par = cur.paragraph();
                bool start = !par.params().startOfAppendix();
 
+#ifdef WITH_WARNINGS
+#warning The code below only makes sense at top level.
+// Should LFUN_APPENDIX be restricted to top-level paragraphs?
+#endif
                // ensure that we have only one start_of_appendix in this document
                for (pit_type tmp = 0, end = pars_.size(); tmp != end; ++tmp) {
                        if (pars_[tmp].params().startOfAppendix()) {
@@ -382,7 +317,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                par.params().startOfAppendix(start);
 
                // we can set the refreshing parameters now
-               updateCounters();
+               updateCounters(cur.buffer());
                break;
        }
 
@@ -405,29 +340,27 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_WORDRIGHT:
-               moving = true;
                if (!cur.mark())
                        cur.clearSelection();
                if (isRTL(cur.paragraph()))
-                       cursorLeftOneWord(cur);
+                       needsUpdate = cursorLeftOneWord(cur);
                else
-                       cursorRightOneWord(cur);
+                       needsUpdate = cursorRightOneWord(cur);
                finishChange(cur, false);
                break;
 
        case LFUN_WORDLEFT:
-               moving = true;
                if (!cur.mark())
                        cur.clearSelection();
                if (isRTL(cur.paragraph()))
-                       cursorRightOneWord(cur);
+                       needsUpdate = cursorRightOneWord(cur);
                else
-                       cursorLeftOneWord(cur);
+                       needsUpdate = cursorLeftOneWord(cur);
                finishChange(cur, false);
                break;
 
        case LFUN_BEGINNINGBUF:
-               if (cur.size() == 1) {
+               if (cur.depth() == 1) {
                        if (!cur.mark())
                                cur.clearSelection();
                        cursorTop(cur);
@@ -438,7 +371,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_BEGINNINGBUFSEL:
-               if (cur.size() == 1) {
+               if (cur.depth() == 1) {
                        if (!cur.selection())
                                cur.resetAnchor();
                        cursorTop(cur);
@@ -449,7 +382,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_ENDBUF:
-               if (cur.size() == 1) {
+               if (cur.depth() == 1) {
                        if (!cur.mark())
                                cur.clearSelection();
                        cursorBottom(cur);
@@ -460,7 +393,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_ENDBUFSEL:
-               if (cur.size() == 1) {
+               if (cur.depth() == 1) {
                        if (!cur.selection())
                                cur.resetAnchor();
                        cursorBottom(cur);
@@ -471,61 +404,65 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_RIGHT:
-               moving = true;
        case LFUN_RIGHTSEL:
-               //lyxerr << "handle LFUN_RIGHT[SEL]:\n" << cur << endl;
+               lyxerr << BOOST_CURRENT_FUNCTION
+                      << " LFUN_RIGHT[SEL]:\n" << cur << endl;
                cur.selHandle(cmd.action == LFUN_RIGHTSEL);
                if (isRTL(cur.paragraph()))
-                       cursorLeft(cur);
+                       needsUpdate = cursorLeft(cur);
                else
-                       cursorRight(cur);
-               if (sl == cur.top()) {
+                       needsUpdate = cursorRight(cur);
+               if (!needsUpdate && oldTopSlice == cur.top()) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_RIGHT);
                }
                break;
 
        case LFUN_LEFT:
-               moving = true;
        case LFUN_LEFTSEL:
                //lyxerr << "handle LFUN_LEFT[SEL]:\n" << cur << endl;
                cur.selHandle(cmd.action == LFUN_LEFTSEL);
                if (isRTL(cur.paragraph()))
-                       cursorRight(cur);
+                       needsUpdate = cursorRight(cur);
                else
-                       cursorLeft(cur);
-               if (sl == cur.top()) {
+                       needsUpdate = cursorLeft(cur);
+               if (oldTopSlice == cur.top()) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_LEFT);
                }
                break;
 
        case LFUN_UP:
-               moving = true;
        case LFUN_UPSEL:
                update(cur);
                //lyxerr << "handle LFUN_UP[SEL]:\n" << cur << endl;
                cur.selHandle(cmd.action == LFUN_UPSEL);
-               cursorUp(cur);
-               if (sl == cur.top()) {
+               needsUpdate = cursorUp(cur);
+               if (oldTopSlice == cur.top()) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_UP);
                }
                break;
 
        case LFUN_DOWN:
-               moving = true;
        case LFUN_DOWNSEL:
                update(cur);
                //lyxerr << "handle LFUN_DOWN[SEL]:\n" << cur << endl;
                cur.selHandle(cmd.action == LFUN_DOWNSEL);
-               cursorDown(cur);
-               if (sl == cur.top()) {
+               needsUpdate = cursorDown(cur);
+               if (oldTopSlice == cur.top()) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_DOWN);
                }
                break;
 
+       case LFUN_UP_PARAGRAPH:
+               if (!cur.mark())
+                       cur.clearSelection();
+               needsUpdate = cursorUpParagraph(cur);
+               finishChange(cur, false);
+               break;
+
        case LFUN_UP_PARAGRAPHSEL:
                if (!cur.selection())
                        cur.resetAnchor();
@@ -533,6 +470,13 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                finishChange(cur, true);
                break;
 
+       case LFUN_DOWN_PARAGRAPH:
+               if (!cur.mark())
+                       cur.clearSelection();
+               needsUpdate = cursorDownParagraph(cur);
+               finishChange(cur, false);
+               break;
+
        case LFUN_DOWN_PARAGRAPHSEL:
                if (!cur.selection())
                        cur.resetAnchor();
@@ -598,25 +542,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_UP_PARAGRAPH:
-               moving = true;
-               if (!cur.mark())
-                       cur.clearSelection();
-               cursorUpParagraph(cur);
-               finishChange(cur, false);
-               break;
-
-       case LFUN_DOWN_PARAGRAPH:
-               moving = true;
-               if (!cur.mark())
-                       cur.clearSelection();
-               cursorDownParagraph(cur);
-               finishChange(cur, false);
-               break;
-
        case LFUN_PRIOR:
                update(cur);
-               moving = true;
                if (!cur.mark())
                        cur.clearSelection();
                finishChange(cur, false);
@@ -624,13 +551,12 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_UP);
                } else {
-                       cursorPrevious(cur);
+                       needsUpdate = cursorPrevious(cur);
                }
                break;
 
        case LFUN_NEXT:
                update(cur);
-               moving = true;
                if (!cur.mark())
                        cur.clearSelection();
                finishChange(cur, false);
@@ -639,7 +565,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_DOWN);
                } else {
-                       cursorNext(cur);
+                       needsUpdate = cursorNext(cur);
                }
                break;
 
@@ -789,19 +715,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_INSET_APPLY: {
-               string const name = cmd.getArg(0);
-               InsetBase * inset = bv->owner()->getDialogs().getOpenInset(name);
-               if (inset) {
-                       FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
-                       inset->dispatch(cur, fr);
-               } else {
-                       FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
-                       dispatch(cur, fr);
-               }
-               break;
-       }
-
        case LFUN_INSET_INSERT: {
                recordUndo(cur);
                InsetBase * inset = createInset(bv, cmd);
@@ -886,7 +799,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
 #warning FIXME Check if the arg is in the domain of available selections.
 #endif
                if (isStrUnsignedInt(cmd.argument))
-                       pasteSelection(cur, strToUnsignedInt(cmd.argument));
+                       pasteSelection(cur, convert<unsigned int>(cmd.argument));
                else
                        pasteSelection(cur, 0);
                cur.clearSelection(); // bug 393
@@ -1005,22 +918,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_GOTOERROR:
-               gotoInset(cur, InsetBase::ERROR_CODE, false);
-               break;
-
-       case LFUN_GOTONOTE:
-               gotoInset(cur, InsetBase::NOTE_CODE, false);
-               break;
-
-       case LFUN_REFERENCE_GOTO: {
-               vector<InsetBase_code> tmp;
-               tmp.push_back(InsetBase::LABEL_CODE);
-               tmp.push_back(InsetBase::REF_CODE);
-               gotoInset(cur, tmp, true);
-               break;
-       }
-
        case LFUN_QUOTE: {
                lyx::cap::replaceSelection(cur);
                Paragraph & par = cur.paragraph();
@@ -1084,6 +981,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cur.resetAnchor();
                        cursorEnd(cur);
                        cur.setSelection();
+                       bv->cursor() = cur;
                        bv->haveSelection(cur.selection());
                }
                break;
@@ -1091,6 +989,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_MOUSE_DOUBLE:
                if (cmd.button() == mouse_button::button1) {
                        selectWord(cur, lyx::WHOLE_WORD_STRICT);
+                       bv->cursor() = cur;
                        bv->haveSelection(cur.selection());
                }
                break;
@@ -1215,6 +1114,12 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                cur.clearSelection();
                LyXFont const old_font = real_current_font;
 
+               // Prevents language turds in new lyxtexts under non-english
+               BufferParams const & bufparams = cur.buffer().params();
+               Language const * lang = cur.paragraph().getParLanguage(bufparams);
+               current_font.setLanguage(lang);
+               real_current_font.setLanguage(lang);
+
                string::const_iterator cit = cmd.argument.begin();
                string::const_iterator end = cmd.argument.end();
                for (; cit != end; ++cit)
@@ -1274,12 +1179,9 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_INSERT_BRANCH:
        case LFUN_INSERT_BIBITEM:
        case LFUN_INSET_ERT:
-       case LFUN_INSET_FLOAT:
        case LFUN_INSET_FOOTNOTE:
        case LFUN_INSET_MARGINAL:
        case LFUN_INSET_OPTARG:
-       case LFUN_INSET_WIDE_FLOAT:
-       case LFUN_INSET_WRAP:
        case LFUN_TABULAR_INSERT:
        case LFUN_ENVIRONMENT_INSERT:
                // Open the inset, and move the current selection
@@ -1288,6 +1190,16 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                cur.posRight();
                break;
 
+       case LFUN_INSET_FLOAT:
+       case LFUN_INSET_WIDE_FLOAT:
+       case LFUN_INSET_WRAP:
+               doInsertInset(cur, this, cmd, true, true);
+               cur.posRight();
+               // FIXME: the "Caption" name should not be hardcoded,
+               // but given by the float definition.
+               cur.dispatch(FuncRequest(LFUN_LAYOUT, "Caption"));
+               break;
+
        case LFUN_INDEX_INSERT:
                // Just open the inset
                doInsertInset(cur, this, cmd, true, false);
@@ -1331,7 +1243,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                else {
                        string s = cmd.argument;
                        string const s1 = token(s, ' ', 1);
-                       int const nargs = s1.empty() ? 0 : atoi(s1);
+                       int const nargs = s1.empty() ? 0 : convert<int>(s1);
                        string const s2 = token(s, ' ', 2);
                        string const type = s2.empty() ? "newcommand" : s2;
                        cur.insert(new MathMacroTemplate(token(s, ' ', 0), nargs, s2));
@@ -1600,17 +1512,20 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                break;
 
        default:
+               lyxerr << BOOST_CURRENT_FUNCTION
+                      << " Not DISPATCHED by LyXText" << endl;
                cur.undispatched();
                break;
        }
 
-       // avoid to update when navigating
-       if (moving
-           && &sl.inset() == &cur.inset()
-           && sl.idx() == cur.idx()
-           && sel == false
-           && cur.selection() == false)
+       if (!needsUpdate
+           && &oldTopSlice.inset() == &cur.inset()
+           && oldTopSlice.idx() == cur.idx()
+           && !sel
+           && !cur.selection())
                cur.noUpdate();
+       else
+               cur.needsUpdate();
 }
 
 
@@ -1638,7 +1553,7 @@ bool LyXText::getStatus(LCursor & cur, FuncRequest const & cmd,
 
        case LFUN_APPENDIX:
                flag.setOnOff(cur.paragraph().params().startOfAppendix());
-               break;
+               return true;
 
 #if 0
        // the functions which insert insets
@@ -1815,29 +1730,37 @@ bool LyXText::getStatus(LCursor & cur, FuncRequest const & cmd,
        case LFUN_INSET_DIALOG_SHOW:
                break;
 
+       case LFUN_INSET_MODIFY:
+               // We need to disable this, because we may get called for a
+               // tabular cell via
+               // InsetTabular::getStatus() -> InsetText::getStatus()
+               // and we don't handle LFUN_INSET_MODIFY.
+               enable = false;
+               break;
+
        case LFUN_EMPH:
                flag.setOnOff(font.emph() == LyXFont::ON);
-               break;
+               return true;
 
        case LFUN_NOUN:
                flag.setOnOff(font.noun() == LyXFont::ON);
-               break;
+               return true;
 
        case LFUN_BOLD:
                flag.setOnOff(font.series() == LyXFont::BOLD_SERIES);
-               break;
+               return true;
 
        case LFUN_SANS:
                flag.setOnOff(font.family() == LyXFont::SANS_FAMILY);
-               break;
+               return true;
 
        case LFUN_ROMAN:
                flag.setOnOff(font.family() == LyXFont::ROMAN_FAMILY);
-               break;
+               return true;
 
        case LFUN_CODE:
                flag.setOnOff(font.family() == LyXFont::TYPEWRITER_FAMILY);
-               break;
+               return true;
 
        case LFUN_DELETE_WORD_FORWARD:
        case LFUN_DELETE_WORD_BACKWARD:
@@ -1876,7 +1799,6 @@ bool LyXText::getStatus(LCursor & cur, FuncRequest const & cmd,
        case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
        case LFUN_BREAKPARAGRAPH_SKIP:
        case LFUN_PARAGRAPH_SPACING:
-       case LFUN_INSET_APPLY:
        case LFUN_INSET_INSERT:
        case LFUN_NEXT_INSET_TOGGLE:
        case LFUN_UPCASE_WORD:
@@ -1892,9 +1814,6 @@ bool LyXText::getStatus(LCursor & cur, FuncRequest const & cmd,
        case LFUN_GETLAYOUT:
        case LFUN_LAYOUT:
        case LFUN_PASTESELECTION:
-       case LFUN_GOTOERROR:
-       case LFUN_GOTONOTE:
-       case LFUN_REFERENCE_GOTO:
        case LFUN_DATE_INSERT:
        case LFUN_SELFINSERT:
        case LFUN_INSERT_LABEL: