]> git.lyx.org Git - features.git/commitdiff
Generalise the deletion protection mechanism from math to text (#9540)
authorGuillaume Munch <gm@lyx.org>
Sat, 18 Feb 2017 18:12:55 +0000 (19:12 +0100)
committerGuillaume Munch <gm@lyx.org>
Sat, 18 Feb 2017 22:03:23 +0000 (23:03 +0100)
Now backspace and delete in text will select non-empty math and text insets
before deleting them. This is consistent with what happens in math already.

This is implemented for InsetText as well but can be disabled in case of
negative feedback.

This can be set for any sort of inset with the new virtual method
Inset::confirmDeletion.

New option "force" for the LFUN_*_DELETE_* commands, that bypasses the
confirmDeletion check.

13 files changed:
src/Cursor.cpp
src/Cursor.h
src/DocIterator.cpp
src/DocIterator.h
src/LyXAction.cpp
src/Text.cpp
src/Text.h
src/Text3.cpp
src/insets/Inset.h
src/insets/InsetText.h
src/mathed/InsetMathHull.h
src/mathed/InsetMathNest.cpp
src/mathed/InsetMathNest.h

index 378a138da6b20c0c3daa7e3883d1aaa7a7d35834..05389d9845b755c32f215ff010f9f42dd9e2ea0c 100644 (file)
@@ -551,24 +551,6 @@ void Cursor::checkNewWordPosition()
 }
 
 
-bool Cursor::posBackward()
-{
-       if (pos() == 0)
-               return false;
-       --pos();
-       return true;
-}
-
-
-bool Cursor::posForward()
-{
-       if (pos() == lastpos())
-               return false;
-       ++pos();
-       return true;
-}
-
-
 bool Cursor::posVisRight(bool skip_inset)
 {
        Cursor new_cur = *this; // where we will move to
@@ -1301,7 +1283,7 @@ void Cursor::insert(MathData const & ar)
 }
 
 
-bool Cursor::backspace()
+bool Cursor::backspace(bool const force)
 {
        if (selection()) {
                cap::eraseSelection(*this);
@@ -1337,7 +1319,7 @@ bool Cursor::backspace()
                }
        }
 
-       if (pos() != 0 && prevAtom()->nargs() > 0) {
+       if (pos() != 0 && !force && prevAtom()->confirmDeletion()) {
                // let's require two backspaces for 'big stuff' and
                // highlight on the first
                resetAnchor();
@@ -1351,7 +1333,7 @@ bool Cursor::backspace()
 }
 
 
-bool Cursor::erase()
+bool Cursor::erase(bool const force)
 {
        if (inMacroMode())
                return true;
@@ -1386,7 +1368,7 @@ bool Cursor::erase()
        }
 
        // 'clever' UI hack: only erase large items if previously slected
-       if (pos() != lastpos() && nextAtom()->nargs() > 0) {
+       if (pos() != lastpos() && !force && nextAtom()->confirmDeletion()) {
                resetAnchor();
                selection(true);
                ++pos();
@@ -2436,4 +2418,21 @@ void Cursor::checkBufferStructure()
 }
 
 
+bool Cursor::confirmDeletion(bool const before) const
+{
+       if (!selection()) {
+               if (Inset const * inset = before ? prevInset() : nextInset())
+                       return inset->confirmDeletion();
+       } else {
+               DocIterator dit = selectionBegin();
+               DocIterator const sel_end = selectionEnd();
+               for (; dit < sel_end; dit.posForward())
+                       if (Inset const * inset = dit.nextInset())
+                               if (inset->confirmDeletion())
+                                       return true;
+       }
+       return false;
+}
+
+
 } // namespace lyx
index f5f1322ce87554e5ee1993f0bf8ae66dc2062fed..dbdd1569b8d577fbc9e5b44b5a8e92eddeca6268 100644 (file)
@@ -232,10 +232,6 @@ public:
        //
        // common part
        //
-       /// move one step backwards
-       bool posBackward();
-       /// move one step forward
-       bool posForward();
        /// move visually one step to the right
        /**
         * @note: This method may move into an inset unless skip_inset == true.
@@ -398,6 +394,11 @@ public:
        /// and after leaving the word the result is empty.
        DocIterator newWord() const { return new_word_; }
 
+       /// Return true if the next or previous inset has confirmDeletion depending
+       /// on the boolean before. If there is a selection, return true if at least
+       /// one inset in the selection has confirmDeletion.
+       bool confirmDeletion(bool before = false) const;
+
 public:
 //private:
        
@@ -454,9 +455,10 @@ public:
        ///
        void insert(MathData const &);
        /// return false for empty math insets
-       bool erase();
-       /// return false for empty math insets
-       bool backspace();
+       /// Use force to skip the confirmDeletion check.
+       bool erase(bool force = false);
+       bool backspace(bool force = false);
+
        /// move the cursor up by sending an internal LFUN_UP
        /// return true if fullscreen update is needed
        bool up();
index fdb61876d6ca3975e9b0b417f1dea9804fb86bd8..51b44d88ef00b153c0ec9155afcfd16203fbb9af 100644 (file)
@@ -318,6 +318,24 @@ Inset * DocIterator::innerInsetOfType(int code) const
 }
 
 
+bool DocIterator::posBackward()
+{
+       if (pos() == 0)
+               return false;
+       --pos();
+       return true;
+}
+
+
+bool DocIterator::posForward()
+{
+       if (pos() == lastpos())
+               return false;
+       ++pos();
+       return true;
+}
+
+
 // This duplicates code above, but is in the critical path.
 // So please think twice before adding stuff
 void DocIterator::forwardPos()
index 425bfa4f6867f968efc58252aa523bd705c58d07..cde876cd86f1382a4a6938bfd7f3a91d876eca31 100644 (file)
@@ -184,6 +184,10 @@ public:
        //
        // elementary moving
        //
+       /// move one step backwards
+       bool posBackward();
+       /// move one step forward
+       bool posForward();
        /**
         * move on one logical position, descend into nested insets
         * including collapsed insets
index 9171e1c8b831cc08345ac320f08e8d1616a74f11..77cf3ea4f1cad394deacdbe25d099861bd4a2cfb 100644 (file)
@@ -1080,7 +1080,8 @@ void LyXAction::init()
 /*!
  * \var lyx::FuncCode lyx::LFUN_CHAR_DELETE_BACKWARD
  * \li Action: Deletes one character in the backward direction (usually the "BackSpace" key).
- * \li Syntax: char-delete-backward
+ * \li Syntax: char-delete-backward [force]
+ * \li Params: force: Delete big insets, do no only select them.
  * \endvar
  */
                { LFUN_CHAR_DELETE_BACKWARD, "char-delete-backward", SingleParUpdate, Edit },
@@ -1088,7 +1089,8 @@ void LyXAction::init()
 /*!
  * \var lyx::FuncCode lyx::LFUN_CHAR_DELETE_FORWARD
  * \li Action: Deletes one character in the backward direction (usually the "Delete" key).
- * \li Syntax: char-delete-forward
+ * \li Syntax: char-delete-forward [force]
+ * \li Params: force: Delete big insets, do no only select them.
  * \endvar
  */
                { LFUN_CHAR_DELETE_FORWARD, "char-delete-forward", SingleParUpdate, Edit },
@@ -4007,7 +4009,8 @@ void LyXAction::init()
 /*!
  * \var lyx::FuncCode lyx::LFUN_WORD_DELETE_BACKWARD
  * \li Action: Deletes characters to the beginning of the word (usually the "C+BackSpace" key).
- * \li Syntax: word-delete-backward
+ * \li Syntax: word-delete-backward [force]
+ * \li Params: force: Delete big insets, do no only select them.
  * \endvar
  */
                { LFUN_WORD_DELETE_BACKWARD, "word-delete-backward", Noop, Edit },
@@ -4015,7 +4018,8 @@ void LyXAction::init()
 /*!
  * \var lyx::FuncCode lyx::LFUN_WORD_DELETE_FORWARD
  * \li Action: Deletes characters to the end of the word (usually the "C+Delete" key).
- * \li Syntax: word-delete-forward
+ * \li Syntax: word-delete-forward [force]
+ * \li Params: force: Delete big insets, do no only select them.
  * \endvar
  */
                { LFUN_WORD_DELETE_FORWARD, "word-delete-forward", Noop, Edit },
index 8d08baa473eabab93f7804b2de971c7a4e5c75af..c1af0948a96a684776843a2857eefefee0caf554 100644 (file)
@@ -1466,7 +1466,7 @@ void Text::rejectChanges()
 }
 
 
-void Text::deleteWordForward(Cursor & cur)
+void Text::deleteWordForward(Cursor & cur, bool const force)
 {
        LBUFERR(this == cur.text());
        if (cur.lastpos() == 0)
@@ -1476,13 +1476,15 @@ void Text::deleteWordForward(Cursor & cur)
                cur.selection(true);
                cursorForwardOneWord(cur);
                cur.setSelection();
-               cutSelection(cur, true, false);
-               cur.checkBufferStructure();
+               if (force || !cur.confirmDeletion()) {
+                       cutSelection(cur, true, false);
+                       cur.checkBufferStructure();
+               }
        }
 }
 
 
-void Text::deleteWordBackward(Cursor & cur)
+void Text::deleteWordBackward(Cursor & cur, bool const force)
 {
        LBUFERR(this == cur.text());
        if (cur.lastpos() == 0)
@@ -1492,8 +1494,10 @@ void Text::deleteWordBackward(Cursor & cur)
                cur.selection(true);
                cursorBackwardOneWord(cur);
                cur.setSelection();
-               cutSelection(cur, true, false);
-               cur.checkBufferStructure();
+               if (force || !cur.confirmDeletion()) {
+                       cutSelection(cur, true, false);
+                       cur.checkBufferStructure();
+               }
        }
 }
 
index f49c8e2d91c8c41a2a7093d4dcacc8a6d751df14..2174984b2352fef7f2405786c80dcd3712e6720a 100644 (file)
@@ -223,9 +223,10 @@ public:
        ///
        bool cursorVisRightOneWord(Cursor & cur);
        /// Delete from cursor up to the end of the current or next word.
-       void deleteWordForward(Cursor & cur);
+       /// Use force to skip the confirmDeletion check.
+       void deleteWordForward(Cursor & cur, bool force = false);
        /// Delete from cursor to start of current or prior word.
-       void deleteWordBackward(Cursor & cur);
+       void deleteWordBackward(Cursor & cur, bool force = false);
        ///
        bool cursorUpParagraph(Cursor & cur);
        ///
index 3e6fdf0e14e62634173830b242372aa160a48a51..cb5f0b5760e6bbbb906390b1a25e6036b1d970f8 100644 (file)
@@ -586,7 +586,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (cur.selection())
                        cutSelection(cur, true, false);
                else
-                       deleteWordForward(cur);
+                       deleteWordForward(cur, cmd.getArg(0) == "force");
                finishChange(cur, false);
                break;
 
@@ -594,7 +594,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (cur.selection())
                        cutSelection(cur, true, false);
                else
-                       deleteWordBackward(cur);
+                       deleteWordBackward(cur, cmd.getArg(0) == "force");
                finishChange(cur, false);
                break;
 
@@ -1054,6 +1054,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        if (cur.pos() == cur.paragraph().size())
                                // Par boundary, force full-screen update
                                singleParUpdate = false;
+                       else if (cmd.getArg(0) != "force" && cur.confirmDeletion()) {
+                               cur.resetAnchor();
+                               cur.selection(true);
+                               cur.posForward();
+                               cur.setSelection();
+                               break;
+                       }
                        needsUpdate |= erase(cur);
                        cur.resetAnchor();
                } else {
@@ -1071,6 +1078,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                // Par boundary, full-screen update
                                if (par_boundary)
                                        singleParUpdate = false;
+                               else if (cmd.getArg(0) != "force" && cur.confirmDeletion(true)) {
+                                       cur.resetAnchor();
+                                       cur.selection(true);
+                                       cur.posBackward();
+                                       cur.setSelection();
+                                       break;
+                               }
                                needsUpdate |= backspace(cur);
                                cur.resetAnchor();
                                if (par_boundary && !first_par && cur.pos() > 0
index 29c4395c38d228d25f4172d88a2c306439d905d7..3395e254a28a0ebc1eb5d616900922831b6f6476 100644 (file)
@@ -581,6 +581,10 @@ public:
        //
        enum { TEXT_TO_INSET_OFFSET = 4 };
 
+       /// Determine the action of backspace and delete: do we select instead of
+       /// deleting if not already selected?
+       virtual bool confirmDeletion() const { return false; }
+
 protected:
        /// Constructors
        Inset(Buffer * buf) : buffer_(buf) {}
index d8dbc43616dd69804333ddc7abc59d50fa84bb0a..eb52bc81b66020c1e68de411a831d3f6d869a18e 100644 (file)
@@ -219,6 +219,10 @@ public:
        std::string contextMenuName() const;
        ///
        void doDispatch(Cursor & cur, FuncRequest & cmd);
+
+       ///
+       bool confirmDeletion() const { return !text().empty(); }
+
 protected:
        ///
        void iterateForToc(DocIterator const & cdit, bool output_active,
index e04d68e91860caf370a6f709d955ce9a28b0f1ba..bc574b9650ee72a8387ac16113d1d3b27215c610 100644 (file)
@@ -189,6 +189,8 @@ public:
        InsetCode lyxCode() const { return MATH_HULL_CODE; }
        ///
        bool canPaintChange(BufferView const &) const;
+       ///
+       bool confirmDeletion() const { return nargs() != 1 || !cell(0).empty(); }
 
 protected:
        InsetMathHull(InsetMathHull const &);
index bdcd8a9a4c0cfeaf7eee8fdae6fd4ceba8e00504..ceec393ee6aa220b194f9c72a5b978e90225555e 100644 (file)
@@ -862,8 +862,8 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                else if (!cur.inMacroMode())
                        cur.recordUndoSelection();
                // if the inset can not be removed from within, delete it
-               if (!cur.backspace()) {
-                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
+               if (!cur.backspace(cmd.getArg(0) == "force")) {
+                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force");
                        cur.innerText()->dispatch(cur, cmd);
                }
                break;
@@ -876,8 +876,8 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                else
                        cur.recordUndoSelection();
                // if the inset can not be removed from within, delete it
-               if (!cur.erase()) {
-                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
+               if (!cur.erase(cmd.getArg(0) == "force")) {
+                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force");
                        cur.innerText()->dispatch(cur, cmd);
                }
                break;
index f1426350c3070145672610cd5913904612f1697a..f1cfdd8beb66fa4d2b6eee557928fd33bcbaa318 100644 (file)
@@ -131,6 +131,9 @@ public:
        ///
        InsetCode lyxCode() const { return MATH_NEST_CODE; }
 
+       ///
+       bool confirmDeletion() const { return nargs() > 0; }
+
 protected:
        ///
        InsetMathNest(InsetMathNest const & inset);