GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
find-dialog.cc
Go to the documentation of this file.
1 /*
2 
3 Find dialog derived from an example from Qt Toolkit (license below (**))
4 
5 Copyright (C) 2012-2018 Torsten <ttl@justmail.de>
6 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
7  All rights reserved.
8  Contact: Nokia Corporation (qt-info@nokia.com)
9 
10 This file is part of Octave.
11 
12 Octave is free software: you can redistribute it and/or modify it
13 under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16 
17 Octave is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with Octave; see the file COPYING. If not, see
24 <https://www.gnu.org/licenses/>.
25 
26 ** This file is part of the examples of the Qt Toolkit.
27 **
28 ** $QT_BEGIN_LICENSE:LGPL$
29 ** Commercial Usage
30 ** Licensees holding valid Qt Commercial licenses may use this file in
31 ** accordance with the Qt Commercial License Agreement provided with the
32 ** Software or, alternatively, in accordance with the terms contained in
33 ** a written agreement between you and Nokia.
34 **
35 ** GNU Lesser General Public License Usage
36 ** Alternatively, this file may be used under the terms of the GNU Lesser
37 ** General Public License version 2.1 as published by the Free Software
38 ** Foundation and appearing in the file LICENSE.LGPL included in the
39 ** packaging of this file. Please review the following information to
40 ** ensure the GNU Lesser General Public License version 2.1 requirements
41 ** will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
42 **
43 ** In addition, as a special exception, Nokia gives you certain additional
44 ** rights. These rights are described in the Nokia Qt LGPL Exception
45 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
46 **
47 ** GNU General Public License Usage
48 ** Alternatively, this file may be used under the terms of the GNU
49 ** General Public License version 3.0 as published by the Free Software
50 ** Foundation and appearing in the file LICENSE.GPL included in the
51 ** packaging of this file. Please review the following information to
52 ** ensure the GNU General Public License version 3.0 requirements will be
53 ** met: https://www.gnu.org/copyleft/gpl.html.
54 **
55 ** If you have questions regarding the use of this file, please contact
56 ** Nokia at qt-info@nokia.com.
57 ** $QT_END_LICENSE$
58 **
59 
60 */
61 
62 #if defined (HAVE_CONFIG_H)
63 # include "config.h"
64 #endif
65 
66 #if defined (HAVE_QSCINTILLA)
67 
68 #include <QCheckBox>
69 #include <QCheckBox>
70 #include <QDialogButtonBox>
71 #include <QGridLayout>
72 #include <QIcon>
73 #include <QLabel>
74 #include <QLineEdit>
75 #include <QMessageBox>
76 #include <QPushButton>
77 #include <QVBoxLayout>
78 
79 #include "find-dialog.h"
80 
81 namespace octave
82 {
84  QList<QAction *> find_actions, QWidget *p)
85  : QDialog (p)
86  {
87  setWindowTitle (tr ("Find and Replace"));
88  setWindowIcon (QIcon (":/actions/icons/find.png"));
89 
90  _search_label = new QLabel (tr ("Find &what:"));
92  _search_label->setBuddy (_search_line_edit);
93  _replace_label = new QLabel (tr ("Re&place with:"));
96 
97  _case_check_box = new QCheckBox (tr ("Match &case"));
98  _from_start_check_box = new QCheckBox (tr ("Search from &start"));
99  _wrap_check_box = new QCheckBox (tr ("&Wrap while searching"));
100  _wrap_check_box->setChecked (true);
101  _find_next_button = new QPushButton (tr ("&Find Next"));
102  _find_prev_button = new QPushButton (tr ("Find &Previous"));
103  _replace_button = new QPushButton (tr ("&Replace"));
104  _replace_all_button = new QPushButton (tr ("Replace &All"));
105 
106  _more_button = new QPushButton (tr ("&More..."));
107  _more_button->setCheckable (true);
108  _more_button->setAutoDefault (false);
109 
110  _button_box = new QDialogButtonBox (Qt::Vertical);
111  _button_box->addButton (_find_next_button, QDialogButtonBox::ActionRole);
112  _button_box->addButton (_find_prev_button, QDialogButtonBox::ActionRole);
113  _button_box->addButton (_replace_button, QDialogButtonBox::ActionRole);
114  _button_box->addButton (_replace_all_button, QDialogButtonBox::ActionRole);
115  _button_box->addButton (_more_button, QDialogButtonBox::ActionRole);
116  _button_box->addButton (QDialogButtonBox::Close);
117 
118  _extension = new QWidget (this);
119  _whole_words_check_box = new QCheckBox (tr ("&Whole words"));
120  _regex_check_box = new QCheckBox (tr ("Regular E&xpressions"));
121  _backward_check_box = new QCheckBox (tr ("Search &backward"));
122  _search_selection_check_box = new QCheckBox (tr ("Search se&lection"));
123 #if defined (HAVE_QSCI_FINDSELECTION)
124  _search_selection_check_box->setCheckable (true);
125  _search_selection_check_box->setEnabled (edit_area->hasSelectedText ());
126 #else
127  _search_selection_check_box->setCheckable (false);
128  _search_selection_check_box->setEnabled (false);
129 #endif
130 
131  _edit_area = edit_area;
132  connect (_find_next_button, SIGNAL (clicked ()),
133  this, SLOT (find_next ()));
134  connect (_find_prev_button, SIGNAL (clicked ()),
135  this, SLOT (find_prev ()));
136  connect (_more_button, SIGNAL (toggled (bool)),
137  _extension, SLOT (setVisible (bool)));
138  connect (_replace_button, SIGNAL (clicked ()),
139  this, SLOT (replace ()));
140  connect (_replace_all_button, SIGNAL (clicked ()),
141  this, SLOT (replace_all ()));
142  connect (_backward_check_box, SIGNAL (stateChanged (int)),
143  this, SLOT (handle_backward_search_changed (int)));
144  connect (_button_box, SIGNAL (rejected ()),
145  this, SLOT (close ()));
146  connect (_search_line_edit, SIGNAL (textChanged (QString)),
147  this, SLOT (handle_search_text_changed (QString)));
148 
149 #if defined (HAVE_QSCI_FINDSELECTION)
150  connect (_edit_area, SIGNAL (copyAvailable (bool)),
151  this, SLOT (handle_selection_changed (bool)));
152  connect (_search_selection_check_box, SIGNAL (stateChanged (int)),
153  this, SLOT (handle_sel_search_changed (int)));
154 #endif
155 
156  QVBoxLayout *extension_layout = new QVBoxLayout ();
157  extension_layout->setMargin (0);
158  extension_layout->addWidget (_whole_words_check_box);
159  extension_layout->addWidget (_backward_check_box);
160  extension_layout->addWidget (_search_selection_check_box);
161  _extension->setLayout (extension_layout);
162 
163  QGridLayout *top_left_layout = new QGridLayout;
164  top_left_layout->addWidget (_search_label, 1, 1);
165  top_left_layout->addWidget (_search_line_edit, 1, 2);
166  top_left_layout->addWidget (_replace_label, 2, 1);
167  top_left_layout->addWidget (_replace_line_edit, 2, 2);
168 
169  QVBoxLayout *left_layout = new QVBoxLayout;
170  left_layout->addLayout (top_left_layout);
171  left_layout->insertStretch (1, 5);
172  left_layout->addWidget (_case_check_box);
173  left_layout->addWidget (_from_start_check_box);
174  left_layout->addWidget (_wrap_check_box);
175  left_layout->addWidget (_regex_check_box);
176 
177  QGridLayout *main_layout = new QGridLayout;
178  main_layout->setSizeConstraint (QLayout::SetFixedSize);
179  main_layout->addLayout (left_layout, 0, 0);
180  main_layout->addWidget (_button_box, 0, 1);
181  main_layout->addWidget (_extension, 1, 0);
182  setLayout (main_layout);
183 
184  _extension->hide ();
185  _find_next_button->setDefault (true);
186  _find_result_available = false;
187  _rep_all = 0;
188  _rep_active = false;
189 
190  // set the actions
191  addActions (find_actions);
192 
193  // move dialog to side of the parent if there is room on the desktop to do so.
194  int xp = p->x () +20;
195  int yp = p->y () + p->frameGeometry ().height () - sizeHint ().height () -20;
196 
197  if (yp < 0)
198  yp = 0;
199 
200  move (xp, yp);
201 
202  }
203 
204  // set text of "search from start" depending on backward search
206  {
207  if (backward)
208  _from_start_check_box->setText (tr ("Search from end"));
209  else
210  _from_start_check_box->setText (tr ("Search from start"));
211  }
212 
213  // search text has changed: reset the search
215  {
216  if (_search_selection_check_box->isChecked ())
217  _find_result_available = false;
218  }
219 
220 #if defined (HAVE_QSCI_FINDSELECTION)
221  void find_dialog::handle_sel_search_changed (int selected)
222  {
223  _from_start_check_box->setEnabled (! selected);
224  _find_result_available = false;
225  }
226 #else
227  void find_dialog::handle_sel_search_changed (int /* selected */) { }
228 #endif
229 
230 #if defined (HAVE_QSCI_FINDSELECTION)
231  void find_dialog::handle_selection_changed (bool has_selected)
232  {
233  if (_rep_active)
234  return;
235 
236  _search_selection_check_box->setEnabled (has_selected);
237  _find_result_available = false;
238  if (! has_selected)
239  _search_selection_check_box->setChecked (false);
240  }
241 #else
242  void find_dialog::handle_selection_changed (bool /* has_selected */) { }
243 #endif
244 
245  // initialize search text with selected text if this is in one single line
247  {
248  if (_edit_area->hasSelectedText ())
249  {
250  int lbeg, lend, cbeg, cend;
251  _edit_area->getSelection (&lbeg,&cbeg,&lend,&cend);
252  if (lbeg == lend)
253  _search_line_edit->setText (_edit_area->selectedText ());
254  }
255 
256  // set focus to "Find what" and select all text
257  _search_line_edit->setFocus ();
258  _search_line_edit->selectAll ();
259 
260  // Default to "find" next time.
261  // Otherwise, it defaults to the last action, which may be "replace all".
262  _find_next_button->setDefault (true);
263  }
264 
266  {
267  find (! _backward_check_box->isChecked ());
268  }
269 
271  {
272  find (_backward_check_box->isChecked ());
273  }
274 
275  void find_dialog::find (bool forward)
276  {
277  int line, col;
278  line = col = -1;
279  bool do_wrap = _wrap_check_box->isChecked ();
280  bool do_forward = forward;
281 
282  if (_rep_all)
283  {
284  if (_rep_all == 1)
285  {
286  line = 0;
287  col = 0;
288  }
289  do_wrap = false;
290  // The following line is a workaround for the issue that when replacing
291  // a text with a new one with different size within the selection,
292  // the selection is not updated leading to missing or extra replacements.
293  // This does not happen, when the selection is search backwards
294  do_forward = ! _search_selection_check_box->isChecked ();
295  }
296  else
297  {
298  if (_from_start_check_box->isChecked ())
299  {
300  if (do_forward)
301  {
302  line = 0;
303  col = 0;
304  }
305  else
306  {
307  line = _edit_area->lines () - 1;
308  col = _edit_area->text (line).length () - 1;
309  if (col == -1)
310  col = 0;
311  }
312  }
313  else if (! do_forward)
314  {
315  // search from position before search characters text length
316  // if search backward on existing results,
317  _edit_area->getCursorPosition (&line,&col);
318  if (_find_result_available && _edit_area->hasSelectedText ())
319  {
320  int currpos = _edit_area->positionFromLineIndex (line,col);
321  currpos -= (_search_line_edit->text ().length ());
322  if (currpos < 0)
323  currpos = 0;
324  _edit_area->lineIndexFromPosition (currpos, &line,&col);
325  }
326  }
327  }
328 
329  if (_edit_area)
330  {
331  if (_edit_area->hasSelectedText ()
332  && _search_selection_check_box->isChecked ())
333  {
334 #if defined (HAVE_QSCI_FINDSELECTION)
336  _find_result_available = _edit_area->findNext ();
337  else
339  = _edit_area->findFirstInSelection (
340  _search_line_edit->text (),
341  _regex_check_box->isChecked (),
342  _case_check_box->isChecked (),
343  _whole_words_check_box->isChecked (),
344  do_forward,
345  true
346 #if defined (HAVE_QSCI_VERSION_2_6_0)
347  , true
348 #endif
349  );
350 #endif
351  }
352  else
353  {
355  = _edit_area->findFirst (_search_line_edit->text (),
356  _regex_check_box->isChecked (),
357  _case_check_box->isChecked (),
358  _whole_words_check_box->isChecked (),
359  do_wrap,
360  do_forward,
361  line,col,
362  true
363 #if defined (HAVE_QSCI_VERSION_2_6_0)
364  , true
365 #endif
366  );
367  }
368  }
369 
371  _from_start_check_box->setChecked (0);
372  else if (! _rep_all)
374  }
375 
377  {
378  _rep_active = true; // changes in selection not made by the user
379  _edit_area->replace (_replace_line_edit->text ());
380  _rep_active = false;
381  }
382 
384  {
385  if (_edit_area)
386  {
387  // The following line is a workaround for the issue that when replacing
388  // a text with a new one with different size within the selection,
389  // the selection is not updated leading to missing or extra replacements.
390  // This does not happen, when the selection is search backwards
391  if (_search_selection_check_box->isChecked ())
392  _backward_check_box->setChecked (true);
393 
394  // do the replace if we have selected text
395  if (_find_result_available && _edit_area->hasSelectedText ())
396  do_replace ();
397 
398  find_next ();
399  }
400  }
401 
403  {
404  int line, col;
405 
406  if (_edit_area)
407  {
408  _edit_area->getCursorPosition (&line,&col);
409 
410  _rep_all = 1;
411  find_next (); // find first occurence (forward)
412  while (_find_result_available) // while search string is found
413  {
414  do_replace ();
415  _rep_all++; // inc counter
416  find_next (); // find next
417  }
418 
419  QMessageBox msg_box (QMessageBox::Information, tr ("Replace Result"),
420  tr ("%1 items replaced").arg (_rep_all-1),
421  QMessageBox::Ok, this);
422  msg_box.exec ();
423 
424  _rep_all = 0;
425  _find_result_available = false;
426 
427  if (! _search_selection_check_box->isChecked ())
428  _edit_area->setCursorPosition (line,col);
429  }
430  }
431 
433  {
434  QMessageBox msg_box (QMessageBox::Information, tr ("Find Result"),
435  tr ("No more matches found"), QMessageBox::Ok, this);
436  msg_box.exec ();
437  }
438 }
439 
440 #endif
QCheckBox * _case_check_box
Definition: find-dialog.h:107
QWidget * _extension
Definition: find-dialog.h:120
void no_matches_message(void)
Definition: find-dialog.cc:432
QCheckBox * _backward_check_box
Definition: find-dialog.h:113
QPushButton * _find_prev_button
Definition: find-dialog.h:116
void do_replace(void)
Definition: find-dialog.cc:376
void init_search_text(void)
Definition: find-dialog.cc:246
void handle_search_text_changed(QString new_search_text)
Definition: find-dialog.cc:214
QLineEdit * _replace_line_edit
Definition: find-dialog.h:106
find_dialog(QsciScintilla *edit_area, QList< QAction *> find_actions, QWidget *parent=nullptr)
Definition: find-dialog.cc:83
QLabel * _replace_label
Definition: find-dialog.h:105
QLineEdit * _search_line_edit
Definition: find-dialog.h:104
QCheckBox * _regex_check_box
Definition: find-dialog.h:111
QPushButton * _replace_button
Definition: find-dialog.h:117
void find(bool forward=true)
Definition: find-dialog.cc:275
void handle_backward_search_changed(int)
Definition: find-dialog.cc:205
octave_value arg
Definition: pr-output.cc:3244
QsciScintilla * _edit_area
Definition: find-dialog.h:121
void handle_selection_changed(bool has_selected)
Definition: find-dialog.cc:242
QDialogButtonBox * _button_box
Definition: find-dialog.h:114
QLabel * _search_label
Definition: find-dialog.h:103
QCheckBox * _from_start_check_box
Definition: find-dialog.h:108
void handle_sel_search_changed(int)
Definition: find-dialog.cc:227
void find_prev(void)
Definition: find-dialog.cc:270
QPushButton * _find_next_button
Definition: find-dialog.h:115
QCheckBox * _search_selection_check_box
Definition: find-dialog.h:112
p
Definition: lu.cc:138
void find_next(void)
Definition: find-dialog.cc:265
QPushButton * _more_button
Definition: find-dialog.h:119
QCheckBox * _wrap_check_box
Definition: find-dialog.h:109
QPushButton * _replace_all_button
Definition: find-dialog.h:118
void replace_all(void)
Definition: find-dialog.cc:402
QCheckBox * _whole_words_check_box
Definition: find-dialog.h:110