]> git.lyx.org Git - lyx.git/blobdiff - src/Text3.cpp
Fix text direction issue for InsetInfo in RTL context
[lyx.git] / src / Text3.cpp
index d811616eaa6c2ca9daf639fadaad3bdf56cd9b0c..c4cf664802d18e6a5c5f38a9b9cc0d426d627705 100644 (file)
@@ -89,6 +89,7 @@ using namespace lyx::support;
 namespace lyx {
 
 using cap::copySelection;
+using cap::copySelectionToTemp;
 using cap::cutSelection;
 using cap::cutSelectionToTemp;
 using cap::pasteFromStack;
@@ -106,9 +107,9 @@ static Font freefont(ignore_font, ignore_language);
 static bool toggleall = false;
 
 static void toggleAndShow(Cursor & cur, Text * text,
-       Font const & font, bool toggleall = true)
+       Font const & font, bool togall = true)
 {
-       text->toggleFree(cur, font, toggleall);
+       text->toggleFree(cur, font, togall);
 
        if (font.language() != ignore_language ||
            font.fontInfo().number() != FONT_IGNORE) {
@@ -249,20 +250,7 @@ static bool doInsertInset(Cursor & cur, Text * text,
                ci->setButtonLabel();
 
        cur.recordUndo();
-       if (cmd.action() == LFUN_INDEX_INSERT) {
-               docstring ds = subst(text->getStringToIndex(cur), '\n', ' ');
-               text->insertInset(cur, inset);
-               if (edit)
-                       inset->edit(cur, true);
-               // Now put this into inset
-               Font const f(inherit_font, cur.current_font.language());
-               if (!ds.empty()) {
-                       cur.text()->insertStringAsLines(cur, ds, f);
-                       cur.leaveInset(*inset);
-               }
-               return true;
-       }
-       else if (cmd.action() == LFUN_ARGUMENT_INSERT) {
+       if (cmd.action() == LFUN_ARGUMENT_INSERT) {
                bool cotextinsert = false;
                InsetArgument const * const ia = static_cast<InsetArgument const *>(inset);
                Layout const & lay = cur.paragraph().layout();
@@ -301,9 +289,16 @@ static bool doInsertInset(Cursor & cur, Text * text,
 
        bool gotsel = false;
        if (cur.selection()) {
-               cutSelectionToTemp(cur, false, pastesel);
+               if (cmd.action() == LFUN_INDEX_INSERT)
+                       copySelectionToTemp(cur);
+               else
+                       cutSelectionToTemp(cur, pastesel);
                cur.clearSelection();
                gotsel = true;
+       } else if (cmd.action() == LFUN_INDEX_INSERT) {
+               gotsel = text->selectWordWhenUnderCursor(cur, WHOLE_WORD);
+               copySelectionToTemp(cur);
+               cur.clearSelection();
        }
        text->insertInset(cur, inset);
 
@@ -351,12 +346,6 @@ static bool doInsertInset(Cursor & cur, Text * text,
 }
 
 
-string const freefont2string()
-{
-       return freefont.toString(toggleall);
-}
-
-
 /// the type of outline operation
 enum OutlineOp {
        OutlineUp, // Move this header with text down
@@ -577,9 +566,59 @@ bool Text::isRTL(Paragraph const & par) const
 
 namespace {
 
-       Language const * getLanguage(Cursor const & cur, string const & lang) {
-               return lang.empty() ? cur.getFont().language() : languages.getLanguage(lang);
+Language const * getLanguage(Cursor const & cur, string const & lang)
+{
+       return lang.empty() ? cur.getFont().language() : languages.getLanguage(lang);
+}
+
+
+docstring resolveLayout(docstring layout, DocIterator const & dit)
+{
+       Paragraph const & par = dit.paragraph();
+       docstring const old_layout = par.layout().name();
+       DocumentClass const & tclass = dit.buffer()->params().documentClass();
+
+       if (layout.empty())
+               layout = tclass.defaultLayoutName();
+
+       if (dit.inset().forcePlainLayout(dit.idx()))
+               // in this case only the empty layout is allowed
+               layout = tclass.plainLayoutName();
+       else if (par.usePlainLayout()) {
+               // in this case, default layout maps to empty layout
+               if (layout == tclass.defaultLayoutName())
+                       layout = tclass.plainLayoutName();
+       } else {
+               // otherwise, the empty layout maps to the default
+               if (layout == tclass.plainLayoutName())
+                       layout = tclass.defaultLayoutName();
+       }
+
+       // If the entry is obsolete, use the new one instead.
+       if (tclass.hasLayout(layout)) {
+               docstring const & obs = tclass[layout].obsoleted_by();
+               if (!obs.empty())
+                       layout = obs;
        }
+       if (!tclass.hasLayout(layout))
+               layout.clear();
+       return layout;
+}
+
+
+bool isAlreadyLayout(docstring const & layout, CursorData const & cur)
+{
+       ParagraphList const & pars = cur.text()->paragraphs();
+
+       pit_type pit = cur.selBegin().pit();
+       pit_type const epit = cur.selEnd().pit() + 1;
+       for ( ; pit != epit; ++pit)
+               if (pars[pit].layout().name() != layout)
+                       return false;
+
+       return true;
+}
+
 
 } // namespace
 
@@ -674,7 +713,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_WORD_DELETE_FORWARD:
                if (cur.selection())
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                else
                        deleteWordForward(cur, cmd.getArg(0) == "force");
                finishChange(cur, false);
@@ -682,7 +721,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_WORD_DELETE_BACKWARD:
                if (cur.selection())
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                else
                        deleteWordBackward(cur, cmd.getArg(0) == "force");
                finishChange(cur, false);
@@ -690,7 +729,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_LINE_DELETE_FORWARD:
                if (cur.selection())
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                else
                        tm->deleteLineForward(cur);
                finishChange(cur, false);
@@ -1092,8 +1131,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                } else {
                        // Maybe we shouldn't allow tabs within a line, because they
                        // are not (yet) aligned as one might do expect.
-                       FuncRequest cmd(LFUN_SELF_INSERT, from_ascii("\t"));
-                       dispatch(cur, cmd);
+                       FuncRequest ncmd(LFUN_SELF_INSERT, from_ascii("\t"));
+                       dispatch(cur, ncmd);
                }
                break;
        }
@@ -1168,7 +1207,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        needsUpdate |= erase(cur);
                        cur.resetAnchor();
                } else {
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                        singleParUpdate = false;
                }
                moveCursor(cur, false);
@@ -1198,7 +1237,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                }
                        }
                } else {
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                        singleParUpdate = false;
                }
                break;
@@ -1239,13 +1278,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                // If we have a list and autoinsert item insets,
                // insert them now.
                Layout::LaTeXArgMap args = par.layout().args();
-               Layout::LaTeXArgMap::const_iterator lait = args.begin();
-               Layout::LaTeXArgMap::const_iterator const laend = args.end();
-               for (; lait != laend; ++lait) {
-                       Layout::latexarg arg = (*lait).second;
-                       if (arg.autoinsert && prefixIs((*lait).first, "item:")) {
-                               FuncRequest cmd(LFUN_ARGUMENT_INSERT, (*lait).first);
-                               lyx::dispatch(cmd);
+               for (auto const & thearg : args) {
+                       Layout::latexarg arg = thearg.second;
+                       if (arg.autoinsert && prefixIs(thearg.first, "item:")) {
+                               FuncRequest cmd2(LFUN_ARGUMENT_INSERT, thearg.first);
+                               lyx::dispatch(cmd2);
                        }
                }
                break;
@@ -1285,7 +1322,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        }
                        */
                        if (cur.selection())
-                               cutSelection(cur, true, false);
+                               cutSelection(cur, false);
                        cur.insert(inset);
                        cur.forceBufferUpdate();
                        if (inset->editable() && inset->asInsetText())
@@ -1477,7 +1514,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_CUT:
-               cutSelection(cur, true, true);
+               cutSelection(cur, true);
                cur.message(_("Cut"));
                break;
 
@@ -1509,60 +1546,25 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                cur.message(cur.paragraph().layout().name());
                break;
 
-       case LFUN_LAYOUT: {
+       case LFUN_LAYOUT:
+       case LFUN_LAYOUT_TOGGLE: {
                bool const ignoreautonests = cmd.getArg(1) == "ignoreautonests";
-               docstring layout = ignoreautonests ? from_utf8(cmd.getArg(0)) : cmd.argument();
-               LYXERR(Debug::INFO, "LFUN_LAYOUT: (arg) " << to_utf8(layout));
-
-               Paragraph const & para = cur.paragraph();
-               docstring const old_layout = para.layout().name();
-               DocumentClass const & tclass = bv->buffer().params().documentClass();
-
-               if (layout.empty())
-                       layout = tclass.defaultLayoutName();
-
-               if (owner_->forcePlainLayout())
-                       // in this case only the empty layout is allowed
-                       layout = tclass.plainLayoutName();
-               else if (para.usePlainLayout()) {
-                       // in this case, default layout maps to empty layout
-                       if (layout == tclass.defaultLayoutName())
-                               layout = tclass.plainLayoutName();
-               } else {
-                       // otherwise, the empty layout maps to the default
-                       if (layout == tclass.plainLayoutName())
-                               layout = tclass.defaultLayoutName();
-               }
-
-               bool hasLayout = tclass.hasLayout(layout);
-
-               // If the entry is obsolete, use the new one instead.
-               if (hasLayout) {
-                       docstring const & obs = tclass[layout].obsoleted_by();
-                       if (!obs.empty())
-                               layout = obs;
-               }
+               docstring req_layout = ignoreautonests ? from_utf8(cmd.getArg(0)) : cmd.argument();
+               LYXERR(Debug::INFO, "LFUN_LAYOUT: (arg) " << to_utf8(req_layout));
 
-               if (!hasLayout) {
-                       cur.errorMessage(from_utf8(N_("Layout ")) + cmd.argument() +
+               docstring layout = resolveLayout(req_layout, cur);
+               if (layout.empty()) {
+                       cur.errorMessage(from_utf8(N_("Layout ")) + req_layout +
                                from_utf8(N_(" not known")));
                        break;
                }
 
-               bool change_layout = (old_layout != layout);
+               docstring const old_layout = cur.paragraph().layout().name();
+               bool change_layout = !isAlreadyLayout(layout, cur);
 
-               if (!change_layout && cur.selection() &&
-                       cur.selBegin().pit() != cur.selEnd().pit())
-               {
-                       pit_type spit = cur.selBegin().pit();
-                       pit_type epit = cur.selEnd().pit() + 1;
-                       while (spit != epit) {
-                               if (pars_[spit].layout().name() != old_layout) {
-                                       change_layout = true;
-                                       break;
-                               }
-                               ++spit;
-                       }
+               if (cmd.action() == LFUN_LAYOUT_TOGGLE && !change_layout) {
+                       change_layout = true;
+                       layout = resolveLayout(docstring(), cur);
                }
 
                if (change_layout) {
@@ -1578,14 +1580,12 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        }
                }
 
-               Layout::LaTeXArgMap args = tclass[layout].args();
-               Layout::LaTeXArgMap::const_iterator lait = args.begin();
-               Layout::LaTeXArgMap::const_iterator const laend = args.end();
-               for (; lait != laend; ++lait) {
-                       Layout::latexarg arg = (*lait).second;
+               DocumentClass const & tclass = bv->buffer().params().documentClass();
+               for (auto const & la_pair : tclass[layout].args()) {
+                       Layout::latexarg const & arg = la_pair.second;
                        if (arg.autoinsert) {
-                               FuncRequest cmd(LFUN_ARGUMENT_INSERT, (*lait).first);
-                               lyx::dispatch(cmd);
+                               FuncRequest const cmd2(LFUN_ARGUMENT_INSERT, la_pair.first);
+                               lyx::dispatch(cmd2);
                        }
                }
 
@@ -1698,21 +1698,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                bv->buffer().errors("Paste");
                break;
 
-       case LFUN_UNICODE_INSERT: {
-               if (cmd.argument().empty())
-                       break;
-               docstring hexstring = cmd.argument();
-               if (isHex(hexstring)) {
-                       char_type c = hexToInt(hexstring);
-                       if (c >= 32 && c < 0x10ffff) {
-                               lyxerr << "Inserting c: " << c << endl;
-                               docstring s = docstring(1, c);
-                               lyx::dispatch(FuncRequest(LFUN_SELF_INSERT, s));
-                       }
-               }
-               break;
-       }
-
        case LFUN_QUOTE_INSERT: {
                cap::replaceSelection(cur);
                cur.recordUndo();
@@ -1934,14 +1919,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                // true (on).
 
                if (lyxrc.auto_region_delete && cur.selection())
-                       cutSelection(cur, false, false);
-
+                       cutSelection(cur, false);
                cur.clearSelection();
 
-               docstring::const_iterator cit = cmd.argument().begin();
-               docstring::const_iterator const end = cmd.argument().end();
-               for (; cit != end; ++cit)
-                       bv->translateAndInsert(*cit, this, cur);
+               for (char_type c : cmd.argument())
+                       bv->translateAndInsert(c, this, cur);
 
                cur.resetAnchor();
                moveCursor(cur, false);
@@ -2018,7 +2000,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (cmd.argument().empty() && cur.selection()) {
                        // if command argument is empty use current selection as parameter.
                        docstring ds = cur.selectionAsString(false);
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                        FuncRequest cmd0(cmd, ds);
                        inset = createInset(cur.buffer(), cmd0);
                } else {
@@ -2070,8 +2052,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        if (arg.autoinsert) {
                                // The cursor might have been invalidated by the replaceSelection.
                                cur.buffer()->changed(true);
-                               FuncRequest cmd(LFUN_ARGUMENT_INSERT, (*lait).first);
-                               lyx::dispatch(cmd);
+                               FuncRequest cmd2(LFUN_ARGUMENT_INSERT, (*lait).first);
+                               lyx::dispatch(cmd2);
                                autoargs = true;
                        }
                }
@@ -2150,9 +2132,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_NOMENCL_INSERT: {
                InsetCommandParams p(NOMENCL_CODE);
-               if (cmd.argument().empty())
-                       p["symbol"] = bv->cursor().innerText()->getStringToIndex(bv->cursor());
-               else
+               if (cmd.argument().empty()) {
+                       p["symbol"] = 
+                               bv->cursor().innerText()->getStringForDialog(bv->cursor());
+                       cur.clearSelection();
+               } else
                        p["symbol"] = cmd.argument();
                string const data = InsetCommand::params2string(p);
                bv->showDialog("nomenclature", data);
@@ -2485,7 +2469,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (tclass.floats().typeExist(to_utf8(cmd.argument()))) {
                        cur.recordUndo();
                        if (cur.selection())
-                               cutSelection(cur, true, false);
+                               cutSelection(cur, false);
                        breakParagraph(cur);
 
                        if (cur.lastpos() != 0) {
@@ -2928,11 +2912,6 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        }
        case LFUN_NOTE_INSERT:
                code = NOTE_CODE;
-               // in commands (sections etc.) and description items,
-               // only Notes are allowed
-               enable = (cmd.argument().empty() || cmd.getArg(0) == "Note" ||
-                         (!cur.paragraph().layout().isCommand()
-                          && !inDescriptionItem(cur)));
                break;
        case LFUN_FLEX_INSERT: {
                code = FLEX_CODE;
@@ -3216,17 +3195,31 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
 
        case LFUN_CHANGE_ACCEPT:
        case LFUN_CHANGE_REJECT:
-               // In principle, these LFUNs should only be enabled if there
-               // is a change at the current position/in the current selection.
-               // However, without proper optimizations, this will inevitably
-               // result in unacceptable performance - just imagine a user who
-               // wants to select the complete content of a long document.
                if (!cur.selection())
                        enable = cur.paragraph().isChanged(cur.pos());
-               else
-                       // TODO: context-sensitive enabling of LFUN_CHANGE_ACCEPT/REJECT
-                       // for selections.
-                       enable = true;
+               else {
+                       // will enable if there is a change in the selection
+                       enable = false;
+
+                       // cheap improvement for efficiency: using cached
+                       // buffer variable, if there is no change in the
+                       // document, no need to check further.
+                       if (!cur.buffer()->areChangesPresent())
+                               break;
+
+                       for (DocIterator it = cur.selectionBegin(); it < cur.selectionEnd(); it.forwardPar()) {
+                               pos_type const beg = it.pos();
+                               pos_type end;
+                               if (it.paragraph().id() == cur.selectionEnd().paragraph().id())
+                                       end = cur.selectionEnd().pos();
+                               else
+                                       end = it.paragraph().size();
+                               if (beg != end && it.paragraph().isChanged(beg, end)) {
+                                       enable = true;
+                                       break;
+                               }
+                       }
+               }
                break;
 
        case LFUN_OUTLINE_UP:
@@ -3296,15 +3289,14 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                }
                break;
 
-       case LFUN_LAYOUT: {
-               DocumentClass const & tclass = cur.buffer()->params().documentClass();
+       case LFUN_LAYOUT:
+       case LFUN_LAYOUT_TOGGLE: {
                bool const ignoreautonests = cmd.getArg(1) == "ignoreautonests";
-               docstring layout = ignoreautonests ? from_utf8(cmd.getArg(0)) : cmd.argument();
-               if (layout.empty())
-                       layout = tclass.defaultLayoutName();
-               enable = !owner_->forcePlainLayout() && tclass.hasLayout(layout);
+               docstring const req_layout = ignoreautonests ? from_utf8(cmd.getArg(0)) : cmd.argument();
+               docstring const layout = resolveLayout(req_layout, cur);
 
-               flag.setOnOff(layout == cur.paragraph().layout().name());
+               enable = !owner_->forcePlainLayout() && !layout.empty();
+               flag.setOnOff(isAlreadyLayout(layout, cur));
                break;
        }