changeset 18888:0a66861d8069 gui-release

implementation of search in selection in gui editor (bbug #41196) * configure.ac: do the check OCTAVE_CHECK_FUNC_QSCI_FINDSELECTION * acinclude.m4 (OCTAVE_CHECK_FUNC_QSCI_FINDSELECTION): new function testing whether QsciScintilla::findFirstInSelection is available (added in 2.7) * find-dialog.cc (constructor): box for searching in selection enabled when function is available, connect signals when search has changed and when search selection is activated to the new related slots, initialize new flag for indicating an ongoing replace; (handle_search_text_changed): new slot reseting search result; (handle_sel_search_changed): new slot reseting search result; (handle_selection_changed): new slot enabling check box for search selection, nothing is done when the change was due to a replace operation; (find): revise calculation of cursor position for starting the search at end, add searching in selection if related check box is checked, use backward search when replacing all (do_replace): set flag for an active replace operation indicating that the selection is not changed by the user; (replace): switch to robust backward search, using new function do_replace; (replace_all): recover cursor position only when nor searching in selection, reset search result after operation, using new function do_replace * find-dialog.h: new flag for active replace operation, new slots
author Torsten <ttl@justmail.de>
date Sun, 22 Jun 2014 15:42:00 +0200
parents b314efd58072
children fc0f3b6c37a9
files configure.ac libgui/src/m-editor/find-dialog.cc libgui/src/m-editor/find-dialog.h m4/acinclude.m4
diffstat 4 files changed, 161 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Thu Jun 19 15:51:05 2014 -0400
+++ b/configure.ac	Sun Jun 22 15:42:00 2014 +0200
@@ -2772,6 +2772,7 @@
     OCTAVE_CHECK_QFONT_MONOSPACE
     OCTAVE_CHECK_FUNC_SETPLACEHOLDERTEXT
     OCTAVE_CHECK_FUNC_QTABWIDGET_SETMOVABLE
+    OCTAVE_CHECK_FUNC_QSCI_FINDSELECTION
   fi
 
   if test $build_gui = yes; then
--- a/libgui/src/m-editor/find-dialog.cc	Thu Jun 19 15:51:05 2014 -0400
+++ b/libgui/src/m-editor/find-dialog.cc	Sun Jun 22 15:42:00 2014 +0200
@@ -107,8 +107,13 @@
   _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"));
-  _search_selection_check_box->setCheckable (false); // TODO: Not implemented.
+#ifdef HAVE_QSCI_FINDSELECTION
+  _search_selection_check_box->setCheckable (true);
+  _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 ()),
@@ -125,6 +130,15 @@
            this,                SLOT (handle_backward_search_changed (int)));
   connect (_button_box,         SIGNAL (rejected ()),
            this,                SLOT (close ()));
+  connect (_search_line_edit,   SIGNAL (textChanged (QString)),
+           this,                SLOT (handle_search_text_changed (QString)));
+
+#ifdef 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);
@@ -158,6 +172,7 @@
   _find_next_button->setDefault (true);
   _find_result_available = false;
   _rep_all = 0;
+  _rep_active = false;
 
   // move dialog to side of the parent if there is room on the desktop to do so.
   QWidget * desktop = QApplication::desktop ();
@@ -183,6 +198,35 @@
     _from_start_check_box->setText (tr ("Search from start"));
 }
 
+// search text has changed: reset the search
+void
+find_dialog::handle_search_text_changed (QString)
+{
+  if (_search_selection_check_box->isChecked ())
+    _find_result_available = false;
+}
+
+#ifdef HAVE_QSCI_FINDSELECTION
+void
+find_dialog::handle_sel_search_changed (int selected)
+{
+  _from_start_check_box->setEnabled (! selected);
+  _find_result_available = false;
+}
+
+void
+find_dialog::handle_selection_changed (bool has_selected)
+{
+  if (_rep_active)
+    return;
+
+  _search_selection_check_box->setEnabled (has_selected);
+  _find_result_available = false;
+  if (! has_selected)
+    _search_selection_check_box->setChecked (false);
+}
+#endif
+
 // initialize search text with selected text if this is in one single line
 void
 find_dialog::init_search_text ()
@@ -215,17 +259,6 @@
   bool do_wrap = _wrap_check_box->isChecked ();
   bool do_forward = forward;
 
-  if (!forward && _find_result_available)
-    { // we found a match last time, cursor is at the end of the match
-      // backward: go to start of selection or we will find the same again
-      int line_end, col_end;
-      _edit_area->getSelection (&line,&col,&line_end,&col_end);
-      if (line > -1)
-        _edit_area->setCursorPosition (line,col);
-    }
-
-  _find_result_available = false;
-
   if (_rep_all)
     {
       if (_rep_all == 1)
@@ -234,49 +267,102 @@
           col = 0;
         }
       do_wrap = false;
-      do_forward = true;
+      // 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 ())
         {
-          line = 0;
-          col  = 0;
-          if (_backward_check_box->isChecked ())
-            do_wrap = true;
+          if (do_forward)
+            {
+              line = 0;
+              col = 0;
+            }
+          else
+            {
+              line = _edit_area->lines () - 1;
+              col  = _edit_area->text (line).length () - 1;
+              if (col == -1)
+                col = 0;
+            }
         }
     }
 
   if (_edit_area)
     {
-      _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 (_edit_area->hasSelectedText ()
+          && _search_selection_check_box->isChecked ())
+        {
+#ifdef 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
 #ifdef HAVE_QSCI_VERSION_2_6_0
-                                , true
+                                      , true
+#endif
+                                      );
 #endif
-                                );
+        }
+      else
+        {
+          _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
+#ifdef HAVE_QSCI_VERSION_2_6_0
+                                    , true
+#endif
+                                    );
+        }
     }
+
   if (_find_result_available)
     _from_start_check_box->setChecked (0);
   else if (! _rep_all)
     no_matches_message ();
 }
 
+void
+find_dialog::do_replace ()
+{
+  _rep_active = true;  // changes in selection not made by the user
+  _edit_area->replace (_replace_line_edit->text ());
+  _rep_active = false;
+}
 
 void
 find_dialog::replace ()
 {
   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
       if (_find_result_available && _edit_area->hasSelectedText ())
-        _edit_area->replace (_replace_line_edit->text ());
+        do_replace ();
+
       find_next ();
     }
 }
@@ -294,7 +380,7 @@
       find_next ();  // find first occurence (forward)
       while (_find_result_available)   // while search string is found
         {
-          _edit_area->replace (_replace_line_edit->text ());   // replace
+          do_replace ();
           _rep_all++;                                          // inc counter
           find_next ();                                        // find next
         }
@@ -305,7 +391,10 @@
       msg_box.exec ();
 
       _rep_all = 0;
-      _edit_area->setCursorPosition (line,col);
+      _find_result_available = false;
+
+      if (! _search_selection_check_box->isChecked ())
+        _edit_area->setCursorPosition (line,col);
     }
 }
 
--- a/libgui/src/m-editor/find-dialog.h	Thu Jun 19 15:51:05 2014 -0400
+++ b/libgui/src/m-editor/find-dialog.h	Sun Jun 22 15:42:00 2014 +0200
@@ -79,7 +79,11 @@
   void init_search_text ();
 
 private slots:
+  void handle_sel_search_changed (int);
+  void handle_selection_changed (bool has_selected);
   void handle_backward_search_changed (int);
+  void handle_search_text_changed (QString new_search_text);
+
   void find (bool forward = true);
   void find_next ();
   void find_prev ();
@@ -87,7 +91,10 @@
   void replace_all ();
 
 private:
+
   void no_matches_message ();
+  void do_replace ();
+
   QLabel            *_search_label;
   QLineEdit         *_search_line_edit;
   QLabel            *_replace_label;
@@ -109,6 +116,7 @@
   QsciScintilla     *_edit_area;
   bool               _find_result_available;
   int                _rep_all;
+  bool               _rep_active;
 };
 
 #endif // FIND_DIALOG_H
--- a/m4/acinclude.m4	Thu Jun 19 15:51:05 2014 -0400
+++ b/m4/acinclude.m4	Sun Jun 22 15:42:00 2014 +0200
@@ -485,6 +485,38 @@
   fi
 ])
 dnl
+dnl Check whether the QsciScintilla::findFirstInSelection () function exists.
+dnl This function was added in QScintilla 2.7.
+dnl
+AC_DEFUN([OCTAVE_CHECK_FUNC_QSCI_FINDSELECTION], [
+  AC_CACHE_CHECK([whether QSci has the QsciScintilla::findFirstInSelection () function],
+    [octave_cv_func_qsci_findfirstinselection],
+    [AC_LANG_PUSH(C++)
+    ac_octave_save_CPPFLAGS="$CPPFLAGS"
+    CPPFLAGS="$QT_CPPFLAGS $CPPFLAGS"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+        #include <Qsci/qsciscintilla.h>
+        class qsci : public QsciScintilla
+        {
+        public:
+          qsci (QWidget *parent = 0) : QsciScintilla (parent)
+          { this->findFirstInSelection (QString ("x"),true,true,true,true,true); }
+          ~qsci () {}
+        };
+        ]], [[
+        qsci edit;
+        ]])],
+      octave_cv_func_qsci_findfirstinselection=yes,
+      octave_cv_func_qsci_findfirstinselection=no)
+    CPPFLAGS="$ac_octave_save_CPPFLAGS"
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_func_qsci_findfirstinselection = yes; then
+    AC_DEFINE(HAVE_QSCI_FINDSELECTION, 1,
+      [Define to 1 if Qsci has the QsciScintilla::findFirstInSelection () function.])
+  fi
+])
+dnl
 dnl Check whether HDF5 library has version 1.6 API functions.
 dnl
 AC_DEFUN([OCTAVE_CHECK_HDF5_HAS_VER_16_API], [