changeset 27133:fbe46901ae62

fix editors search and replace in selection (bug #56405) * file-editor-tab.cc (handle_double_click): update call to changed method octave_qscintilla::show_selection_markers * find-dialog.cc (find_dialog): parent is class octave_qscintilla, initialize the new class variables for searching in the selection; (handle_selection_changed): only disable selection checkbox if no text is selected, but leave check state as it is, remove the conditial compilation based on HAVE_QSCI_FINDSELECTION; (find): remove consitional compilation, initialize line and column for the search start also for selected text, remember start and end of a possible selection, remove workaround for wrong selection length update, only use finFirst also for the case with selection, check if search hit lies within the selection if necessary and stop search if required, update slection marker for showing the current selected area, remove this marker and restore real selection if no more occurrance of search text was found; (do_replace): update the length of the selection when replacing text; (replace): remove workaround for buggy selection length update * find-dialog.h: include octave_qscintilla, parent and _edit_area are of type octave_qscintilla, new class variable for storing and handling search in selection as well as selection begin and end * octave-qscintilla.cc (show_selection_markers): paraemters are now start line and column as wells as end line and column * octave-qscintilla.h: new parameters for show_selection_markers
author Torsten Lilge <ttl-octave@mailbox.org>
date Sat, 01 Jun 2019 19:30:56 +0200
parents 8ea53aa9ac39
children 8229d4e15a28
files libgui/src/m-editor/file-editor-tab.cc libgui/src/m-editor/find-dialog.cc libgui/src/m-editor/find-dialog.h libgui/src/m-editor/octave-qscintilla.cc libgui/src/m-editor/octave-qscintilla.h
diffstat 5 files changed, 136 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/m-editor/file-editor-tab.cc	Sat Jun 01 08:56:51 2019 -0700
+++ b/libgui/src/m-editor/file-editor-tab.cc	Sat Jun 01 19:30:56 2019 +0200
@@ -3166,7 +3166,7 @@
                     // get cursor position after having found an occurrence
                     _edit_area->getCursorPosition (&oline, &ocol);
                     // mark the selection
-                    _edit_area->show_selection_markers (oline, ocol, wlen);
+                    _edit_area->show_selection_markers (oline, ocol-wlen, oline, ocol);
 
                     // find next occurrence
                     find_result_available = _edit_area->findNext ();
--- a/libgui/src/m-editor/find-dialog.cc	Sat Jun 01 08:56:51 2019 -0700
+++ b/libgui/src/m-editor/find-dialog.cc	Sat Jun 01 19:30:56 2019 +0200
@@ -80,9 +80,9 @@
 
 namespace octave
 {
-  find_dialog::find_dialog (QsciScintilla *edit_area,
+  find_dialog::find_dialog (octave_qscintilla *edit_area,
                             QList<QAction *> find_actions, QWidget *p)
-    : QDialog (p)
+    : QDialog (p), m_in_sel (false), m_sel_beg (-1), m_sel_end (-1)
   {
     setWindowTitle (tr ("Find and Replace"));
     setWindowIcon (QIcon (":/actions/icons/find.png"));
@@ -120,14 +120,9 @@
     _regex_check_box = new QCheckBox (tr ("Regular E&xpressions"));
     _backward_check_box = new QCheckBox (tr ("Search &backward"));
     _search_selection_check_box = new QCheckBox (tr ("Search se&lection"));
-#if defined (HAVE_QSCI_FINDSELECTION)
     _search_selection_check_box->setCheckable (true);
     if (edit_area)
       _search_selection_check_box->setEnabled (edit_area->hasSelectedText ());
-#else
-    _search_selection_check_box->setCheckable (false);
-    _search_selection_check_box->setEnabled (false);
-#endif
 
     _edit_area = edit_area;
     connect (_find_next_button,   SIGNAL (clicked ()),
@@ -147,12 +142,10 @@
     connect (_search_line_edit,   SIGNAL (textChanged (QString)),
              this,                SLOT (handle_search_text_changed (QString)));
 
-#if defined (HAVE_QSCI_FINDSELECTION)
     connect (_edit_area, SIGNAL (copyAvailable (bool)),
              this,       SLOT (handle_selection_changed (bool)));
     connect (_search_selection_check_box, SIGNAL (stateChanged (int)),
              this,                        SLOT (handle_sel_search_changed (int)));
-#endif
 
     QVBoxLayout *extension_layout = new QVBoxLayout ();
     extension_layout->setMargin (0);
@@ -251,17 +244,12 @@
       _find_result_available = false;
   }
 
-#if defined (HAVE_QSCI_FINDSELECTION)
   void find_dialog::handle_sel_search_changed (int selected)
   {
     _from_start_check_box->setEnabled (! selected);
     _find_result_available = false;
   }
-#else
-  void find_dialog::handle_sel_search_changed (int /* selected */) { }
-#endif
 
-#if defined (HAVE_QSCI_FINDSELECTION)
   void find_dialog::handle_selection_changed (bool has_selected)
   {
     if (_rep_active)
@@ -269,12 +257,7 @@
 
     _search_selection_check_box->setEnabled (has_selected);
     _find_result_available = false;
-    if (! has_selected)
-      _search_selection_check_box->setChecked (false);
   }
-#else
-  void find_dialog::handle_selection_changed (bool /* has_selected */) { }
-#endif
 
   // initialize search text with selected text if this is in one single line
   void find_dialog::init_search_text (void)
@@ -311,46 +294,84 @@
     if (! _edit_area)
       return;
 
-    int line, col;
-    line = col = -1;
+    // line adn col: -1 means search starts at current position
+    int line = -1, col = -1;
+
     bool do_wrap = _wrap_check_box->isChecked ();
     bool do_forward = forward;
 
+    // Initialize the selection begin and end if it is the first search
+    if (! _find_result_available)
+      {
+        if (_search_selection_check_box->isChecked ()
+            && _edit_area->hasSelectedText ())
+          {
+            int l1, c1, l2, c2;
+            _edit_area->getSelection (&l1, &c1, &l2, &c2);
+
+            // Store the position of the selection
+            m_sel_beg = _edit_area->positionFromLineIndex (l1, c1);
+            m_sel_end = _edit_area->positionFromLineIndex (l2, c2);
+            m_in_sel = true;
+          }
+        else
+          m_in_sel = false;
+      }
+
+    // Get the correct line/col for beginning the search
     if (_rep_all)
       {
+        // Replace All
         if (_rep_all == 1)
           {
-            line = 0;
-            col = 0;
-          }
-        do_wrap = false;
-        // The following line is a workaround for the issue that when replacing
-        // a text with a new one with different size within the selection,
-        // the selection is not updated leading to missing or extra replacements.
-        // This does not happen, when the selection is search backwards
-        do_forward = ! _search_selection_check_box->isChecked ();
-      }
-    else
-      {
-        if (_from_start_check_box->isChecked ())
-          {
-            if (do_forward)
+            // Start at the beginning of file/sel if it is the first try
+            if (m_in_sel)
+              _edit_area->lineIndexFromPosition (m_sel_beg, &line, &col);
+            else
               {
                 line = 0;
                 col = 0;
               }
+          }
+        do_wrap = false;  // Never wrap when replacing all
+      }
+    else
+      {
+        // Normal search (not replace all): calculate start position of
+        // search (in file or selection)
+        if (_from_start_check_box->isChecked ()
+            || (m_in_sel && (! _find_result_available)))
+          {
+            // From the beginning or the end of file/sel
+            if (do_forward)
+              {
+                // From the beginning
+                if (m_in_sel)
+                  _edit_area->lineIndexFromPosition (m_sel_beg, &line, &col);
+                else
+                  {
+                    line = 0;
+                    col = 0;
+                  }
+              }
             else
               {
-                line = _edit_area->lines () - 1;
-                col  = _edit_area->text (line).length () - 1;
-                if (col == -1)
-                  col = 0;
+                // From the end
+                if (m_in_sel)
+                  _edit_area->lineIndexFromPosition (m_sel_end, &line, &col);
+                else
+                  {
+                    line = _edit_area->lines () - 1;
+                    col  = _edit_area->text (line).length () - 1;
+                    if (col == -1)
+                      col = 0;
+                  }
               }
           }
         else if (! do_forward)
           {
-            // search from position before search characters text length
-            // if search backward on existing results,
+            // Start from where the cursor is. Fix QScintilla's cursor
+            // positioning
             _edit_area->getCursorPosition (&line,&col);
             if (_find_result_available && _edit_area->hasSelectedText ())
               {
@@ -358,54 +379,65 @@
                 currpos -= (_search_line_edit->text ().length ());
                 if (currpos < 0)
                   currpos = 0;
-                _edit_area->lineIndexFromPosition (currpos, &line,&col);
+                _edit_area->lineIndexFromPosition (currpos, &line, &col);
               }
           }
       }
 
-    if (_edit_area->hasSelectedText ()
-        && _search_selection_check_box->isChecked ())
-      {
-#if defined (HAVE_QSCI_FINDSELECTION)
-        if (_find_result_available)
-          _find_result_available = _edit_area->findNext ();
-        else
-          _find_result_available
-            = _edit_area->findFirstInSelection (
-                                                _search_line_edit->text (),
-                                                _regex_check_box->isChecked (),
-                                                _case_check_box->isChecked (),
-                                                _whole_words_check_box->isChecked (),
-                                                do_forward,
-                                                true
+    // Do the search
+    _find_result_available = _edit_area->findFirst (
+                                  _search_line_edit->text (),
+                                  _regex_check_box->isChecked (),
+                                  _case_check_box->isChecked (),
+                                  _whole_words_check_box->isChecked (),
+                                  do_wrap,
+                                  do_forward,
+                                  line,col,
+                                  true
 #if defined (HAVE_QSCI_VERSION_2_6_0)
-                                                , true
+                                , true
 #endif
-                                               );
-#endif
-      }
-    else
+                              );
+
+    if (_find_result_available)
       {
-        _find_result_available
-          = _edit_area->findFirst (_search_line_edit->text (),
-                                   _regex_check_box->isChecked (),
-                                   _case_check_box->isChecked (),
-                                   _whole_words_check_box->isChecked (),
-                                   do_wrap,
-                                   do_forward,
-                                   line,col,
-                                   true
-#if defined (HAVE_QSCI_VERSION_2_6_0)
-                                    , true
-#endif
-                                  );
+        // Search successful: reset search-from-start box and check for
+        // the current selection
+        _from_start_check_box->setChecked (0);
+
+        if (m_in_sel)
+          {
+            _edit_area->getCursorPosition (&line,&col);
+            int pos = _edit_area->positionFromLineIndex (line, col);
+
+            int l1, c1, l2, c2;
+            _edit_area->lineIndexFromPosition (m_sel_beg, &l1, &c1);
+            _edit_area->lineIndexFromPosition (m_sel_end, &l2, &c2);
+            _edit_area->show_selection_markers (l1, c1, l2, c2);
+
+            // Check if new start position is still wihtin the selection
+            _find_result_available =  pos >= m_sel_beg && pos <= m_sel_end;
+          }
       }
 
+    // No more search hits
+    if (! _find_result_available)
+      {
+        if (m_in_sel)
+          {
+            // Restore real selection and remove marker for selection
+            int l1, c1, l2, c2;
+            _edit_area->lineIndexFromPosition (m_sel_beg, &l1, &c1);
+            _edit_area->lineIndexFromPosition (m_sel_end, &l2, &c2);
+            _edit_area->setSelection (l1, c1, l2, c2);
+            _edit_area->clear_selection_markers ();
+          }
 
-    if (_find_result_available)
-      _from_start_check_box->setChecked (0);
-    else if (! _rep_all)
-      no_matches_message ();
+        // Display message if not replace all
+        if (! _rep_all)
+          no_matches_message ();
+      }
+
   }
 
   void find_dialog::do_replace (void)
@@ -413,7 +445,16 @@
     if (_edit_area)
       {
         _rep_active = true;  // changes in selection not made by the user
+
         _edit_area->replace (_replace_line_edit->text ());
+        if (m_in_sel)
+          {
+            // Update the length of the selection
+            m_sel_end = m_sel_end
+                        - _search_line_edit->text ().toUtf8 ().size ()
+                        + _replace_line_edit->text ().toUtf8 ().size ();
+          }
+
         _rep_active = false;
       }
   }
@@ -422,14 +463,7 @@
   {
     if (_edit_area)
       {
-        // The following line is a workaround for the issue that when replacing
-        // a text with a new one with different size within the selection,
-        // the selection is not updated leading to missing or extra replacements.
-        // This does not happen, when the selection is search backwards
-        if (_search_selection_check_box->isChecked ())
-          _backward_check_box->setChecked (true);
-
-        // do the replace if we have selected text
+        // Do the replace if we have selected text
         if (_find_result_available && _edit_area->hasSelectedText ())
           do_replace ();
 
--- a/libgui/src/m-editor/find-dialog.h	Sat Jun 01 08:56:51 2019 -0700
+++ b/libgui/src/m-editor/find-dialog.h	Sat Jun 01 19:30:56 2019 +0200
@@ -63,7 +63,8 @@
 #define octave_find_dialog_h 1
 
 #include <QDialog>
-#include <Qsci/qsciscintilla.h>
+
+#include "octave-qscintilla.h"
 
 class QCheckBox;
 class QDialogButtonBox;
@@ -102,7 +103,7 @@
         FIND_DLG_SEL   = 128
       };
 
-    find_dialog (QsciScintilla *edit_area, QList<QAction *> find_actions,
+    find_dialog (octave_qscintilla *edit_area, QList<QAction *> find_actions,
                  QWidget *parent = nullptr);
     void init_search_text (void);
     void save_data (find_dialog_data *fdlg_data);
@@ -144,10 +145,14 @@
     QPushButton       *_replace_all_button;
     QPushButton       *_more_button;
     QWidget           *_extension;
-    QsciScintilla     *_edit_area;
+    octave_qscintilla  *_edit_area;
     bool               _find_result_available;
     int                _rep_all;
     bool               _rep_active;
+
+    bool               m_in_sel;
+    int                m_sel_beg;
+    int                m_sel_end;
   };
 }
 
--- a/libgui/src/m-editor/octave-qscintilla.cc	Sat Jun 01 08:56:51 2019 -0700
+++ b/libgui/src/m-editor/octave-qscintilla.cc	Sat Jun 01 19:30:56 2019 +0200
@@ -726,11 +726,12 @@
       }
   }
 
-  void octave_qscintilla::show_selection_markers (int line, int col, int len)
+  void octave_qscintilla::show_selection_markers (int l1, int c1, int l2, int c2)
   {
-    fillIndicatorRange (line, col - len, line, col, m_indicator_id);
+    fillIndicatorRange (l1, c1, l2, c2, m_indicator_id);
 
-    markerAdd (line, marker::selection);
+    if (l1 == l2)
+      markerAdd (l1, marker::selection);
   }
 
   void octave_qscintilla::contextmenu_help (bool)
--- a/libgui/src/m-editor/octave-qscintilla.h	Sat Jun 01 08:56:51 2019 -0700
+++ b/libgui/src/m-editor/octave-qscintilla.h	Sat Jun 01 19:30:56 2019 +0200
@@ -69,7 +69,7 @@
 
     void set_word_selection (const QString& word = QString ());
 
-    void show_selection_markers (int line, int col, int len);
+    void show_selection_markers (int l1, int c1, int l2, int c2);
 
     void set_selection_marker_color (const QColor& c);