GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
find-files-dialog.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2013-2018 John Donoghue
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <QPushButton>
28 #include <QDialogButtonBox>
29 #include <QGridLayout>
30 #include <QLabel>
31 #include <QLineEdit>
32 #include <QComboBox>
33 #include <QCheckBox>
34 #include <QHeaderView>
35 #include <QTableView>
36 #include <QFileDialog>
37 #include <QStatusBar>
38 #include <QIcon>
39 #include <QFileInfo>
40 #include <QTimer>
41 #include <QDirIterator>
42 #include <QTextStream>
43 #include <QGroupBox>
44 
45 #include "find-files-dialog.h"
46 #include "find-files-model.h"
47 #include "resource-manager.h"
48 
49 namespace octave
50 {
52  : QDialog (p)
53  {
54  setWindowTitle (tr ("Find Files"));
55  setWindowIcon (resource_manager::icon ("edit-find"));
56 
57  m_dir_iterator = nullptr;
58 
59  m_timer = new QTimer (this);
60  connect (m_timer, SIGNAL (timeout (void)),
61  this, SLOT (look_for_files (void)));
62 
63  QSettings *settings = resource_manager::get_settings ();
64 
65  QLabel *file_name_label = new QLabel (tr ("Named:"));
67  m_file_name_edit->setToolTip (tr ("Enter the filename search expression"));
68 
69  m_file_name_edit->setText (settings->value ("findfiles/file_name",
70  "*").toString ());
71  file_name_label->setBuddy (m_file_name_edit);
72 
73  QLabel *start_dir_label = new QLabel (tr ("Start in:"));
74 
76  m_start_dir_edit->setText (settings->value ("findfiles/start_dir",
77  QDir::currentPath ()).toString ());
78  m_start_dir_edit->setToolTip (tr ("Enter the start directory"));
79  start_dir_label->setBuddy (m_start_dir_edit);
80 
81  m_browse_button = new QPushButton (tr ("Browse..."));
82  m_browse_button->setToolTip (tr ("Browse for start directory"));
83  connect (m_browse_button, SIGNAL (clicked (void)),
84  this, SLOT (browse_folders (void)));
85 
86  m_recurse_dirs_check = new QCheckBox (tr ("Search subdirectories"));
87  m_recurse_dirs_check->setChecked (settings->value ("findfiles/recurse_dirs",
88  false).toBool ());
89  m_recurse_dirs_check->setToolTip (tr ("Search recursively through directories for matching files"));
90 
91  m_include_dirs_check = new QCheckBox (tr ("Include directory names"));
92  m_include_dirs_check->setChecked (settings->value ("findfiles/include_dirs",
93  false).toBool ());
94  m_include_dirs_check->setToolTip (tr ("Include matching directories in search results"));
95 
96  m_name_case_check = new QCheckBox (tr ("Name case insensitive"));
97  m_name_case_check->setChecked (settings->value ("findfiles/name_case",
98  false).toBool ());
99  m_name_case_check->setToolTip (tr ("Set matching name is case insensitive"));
100 
101  m_contains_text_check = new QCheckBox (tr ("Contains text:"));
102  m_contains_text_check->setToolTip (tr ("Enter the file content search expression"));
103  m_contains_text_check->setChecked (settings->value ("findfiles/check_text",
104  false).toBool ());
105 
107  m_contains_text_edit->setToolTip (tr ("Text to match"));
108  m_contains_text_edit->setText (settings->value ("findfiles/contains_text",
109  "").toString ());
110 
111  m_content_case_check = new QCheckBox (tr ("Text case insensitive"));
112  m_content_case_check->setChecked (settings->value ("findfiles/content_case",
113  false).toBool ());
114  m_content_case_check->setToolTip (tr ("Set text content is case insensitive"));
115 
116  find_files_model *model = new find_files_model (this);
117 
118  m_file_list = new QTableView;
119  m_file_list->setWordWrap (false);
120  m_file_list->setModel (model);
121  m_file_list->setShowGrid (false);
122  m_file_list->setSelectionBehavior (QAbstractItemView::SelectRows);
123  m_file_list->setSelectionMode (QAbstractItemView::SingleSelection);
124  m_file_list->setAlternatingRowColors (true);
125  m_file_list->setToolTip (tr ("Search results"));
126  m_file_list->setSortingEnabled (true);
127  m_file_list->horizontalHeader ()->restoreState (settings->value ("findfiles/column_state").toByteArray ());
128  m_file_list->horizontalHeader ()->setSortIndicatorShown (true);
129 #if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
130  m_file_list->horizontalHeader ()->setSectionsClickable (true);
131 #else
132  m_file_list->horizontalHeader ()->setClickable (true);
133 #endif
134  m_file_list->horizontalHeader ()->setStretchLastSection (true);
135  m_file_list->sortByColumn (settings->value ("findfiles/sort_files_by_column",0).toInt (),
136  static_cast<Qt::SortOrder>
137  (settings->value ("findfiles/sort_files_by_order",
138  Qt::AscendingOrder).toUInt ()));
139 
140  connect (m_file_list, SIGNAL (doubleClicked (const QModelIndex&)),
141  this, SLOT (item_double_clicked (const QModelIndex &)));
142 
143  m_status_bar = new QStatusBar;
144  m_status_bar->showMessage (tr ("Idle."));
145 
146  m_find_button = new QPushButton (tr ("Find"));
147  m_find_button->setToolTip (tr ("Start search for matching files"));
148  connect (m_find_button, SIGNAL (clicked (void)),
149  this, SLOT (start_find (void)));
150 
151  m_stop_button = new QPushButton (tr ("Stop"));
152  m_stop_button->setToolTip (tr ("Stop searching"));
153  m_stop_button->setEnabled (false);
154  connect (m_stop_button, SIGNAL (clicked (void)),
155  this, SLOT (stop_find (void)));
156 
157  // layout everything
158  QDialogButtonBox *button_box = new QDialogButtonBox (Qt::Vertical);
159  button_box->addButton (m_find_button, QDialogButtonBox::ActionRole);
160  button_box->addButton (m_stop_button, QDialogButtonBox::ActionRole);
161 
162  // add dialog close button
163  m_close_button = button_box->addButton (QDialogButtonBox::Close);
164  connect (button_box, SIGNAL (rejected (void)), this, SLOT (close (void)));
165 
166  // name options
167  QGroupBox *name_group = new QGroupBox (tr ("Filename/location"));
168  QGridLayout *name_layout = new QGridLayout;
169  name_group->setLayout (name_layout);
170 
171  name_layout->addWidget (file_name_label,1,1, 1,1);
172  name_layout->addWidget (m_file_name_edit,1,2, 1,-1);
173 
174  name_layout->addWidget (start_dir_label,2,1);
175  name_layout->addWidget (m_start_dir_edit,2,2,1,3);
176  name_layout->addWidget (m_browse_button,2,5);
177  name_layout->setColumnStretch (2,1);
178 
179  name_layout->addWidget (m_recurse_dirs_check,3,1);
180  name_layout->addWidget (m_include_dirs_check,3,2);
181  name_layout->addWidget (m_name_case_check,3,3);
182 
183  // content options
184  QGroupBox *content_group = new QGroupBox (tr ("File contents"));
185  QGridLayout *content_layout = new QGridLayout;
186  content_group->setLayout (content_layout);
187  content_layout->addWidget (m_contains_text_check,4,1);
188  content_layout->addWidget (m_contains_text_edit,4,2,1,3);
189  content_layout->setColumnStretch (2,1);
190  content_layout->addWidget (m_content_case_check,5,1);
191 
192  QGridLayout *main_layout = new QGridLayout;
193  main_layout->setSizeConstraint (QLayout::SetFixedSize);
194  main_layout->addWidget (name_group, 0, 0);
195  main_layout->addWidget (content_group, 1, 0);
196  main_layout->addWidget (button_box, 0, 1,3,1);
197  main_layout->addWidget (m_file_list,2,0);
198  main_layout->setRowStretch (2,1);
199  main_layout->addWidget (m_status_bar,3,0,1,-1);
200 
201  setLayout (main_layout);
202 
203  connect (this, SIGNAL (finished (int)), this, SLOT (handle_done (int)));
204  }
205 
207  {
208  delete m_dir_iterator;
209  }
210 
212  {
213  QSettings *settings = resource_manager::get_settings ();
214 
215  if (! settings)
216  return;
217 
218  int sort_column = m_file_list->horizontalHeader ()->sortIndicatorSection ();
219  Qt::SortOrder sort_order
220  = m_file_list->horizontalHeader ()->sortIndicatorOrder ();
221  settings->setValue ("findfiles/sort_files_by_column", sort_column);
222  settings->setValue ("findfiles/sort_files_by_order", sort_order);
223  settings->setValue ("findfiles/column_state",
224  m_file_list->horizontalHeader ()->saveState ());
225 
226  settings->setValue ("findfiles/file_name", m_file_name_edit->text ());
227 
228  settings->setValue ("findfiles/start_dir", m_start_dir_edit->text ());
229 
230  settings->setValue ("findfiles/recurse_dirs", m_recurse_dirs_check->text ());
231  settings->setValue ("findfiles/include_dirs", m_include_dirs_check->text ());
232  settings->setValue ("findfiles/name_case", m_name_case_check->text ());
233 
234  settings->setValue ("findfiles/contains_text", m_contains_text_edit->text ());
235  settings->setValue ("findfiles/check_text",
236  m_contains_text_check->isChecked ());
237  settings->setValue ("findfiles/content_case",
238  m_content_case_check->isChecked ());
239 
240  settings->sync ();
241  }
242 
243  void find_files_dialog::set_search_dir (const QString& dir)
244  {
245  stop_find ();
246  m_start_dir_edit->setText (dir);
247  }
248 
250  {
251  stop_find ();
252 
253  find_files_model *m = static_cast<find_files_model *> (m_file_list->model ());
254  m->clear ();
255 
256  QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags;
257  if (m_recurse_dirs_check->isChecked ())
258  flags |= QDirIterator::Subdirectories;
259 
260  QDir::Filters filters = QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files;
261  if (! m_name_case_check->isChecked ())
262  filters |= QDir::CaseSensitive;
263 
264  QStringList nameFilters;
265  nameFilters.append (m_file_name_edit->text ());
266 
267  if (m_dir_iterator)
268  delete m_dir_iterator;
269 
270  m_dir_iterator = new QDirIterator (m_start_dir_edit->text (), nameFilters,
271  filters, flags);
272 
273  // enable/disable widgets
274  m_find_button->setEnabled (false);
275  m_stop_button->setEnabled (true);
276  m_close_button->setEnabled (false);
277  m_browse_button->setEnabled (false);
278  m_start_dir_edit->setEnabled (false);
279  m_file_name_edit->setEnabled (false);
280  m_recurse_dirs_check->setEnabled (false);
281  m_include_dirs_check->setEnabled (false);
282  m_name_case_check->setEnabled (false);
283  m_contains_text_check->setEnabled (false);
284  m_content_case_check->setEnabled (false);
285  m_contains_text_edit->setEnabled (false);
286 
287  m_status_bar->showMessage (tr ("Searching..."));
288  m_timer->start (0);
289  }
290 
292  {
293  m_timer->stop ();
294 
295  m_find_button->setEnabled (true);
296  m_stop_button->setEnabled (false);
297  m_close_button->setEnabled (true);
298  m_browse_button->setEnabled (true);
299  m_start_dir_edit->setEnabled (true);
300  m_file_name_edit->setEnabled (true);
301  m_recurse_dirs_check->setEnabled (true);
302  m_include_dirs_check->setEnabled (true);
303  m_name_case_check->setEnabled (true);
304  m_contains_text_check->setEnabled (true);
305  m_content_case_check->setEnabled (true);
306  m_contains_text_edit->setEnabled (true);
307 
308  find_files_model *m = static_cast<find_files_model *> (m_file_list->model ());
309  QString res_str = QString (tr ("%1 match (es)")).arg (m->rowCount ());
310 
311  m_status_bar->showMessage (res_str);
312  }
313 
315  {
316  QString dir =
317  QFileDialog::getExistingDirectory (this, tr ("Set search directory"),
318  m_start_dir_edit->text ());
319 
320  if (! dir.isEmpty ())
321  m_start_dir_edit->setText (dir);
322  }
323 
324  void find_files_dialog::item_double_clicked (const QModelIndex& idx)
325  {
326  find_files_model *m = static_cast<find_files_model *> (m_file_list->model ());
327 
328  QFileInfo info = m->fileInfo (idx);
329 
330  if (idx.column () == 1)
331  {
332  // clicked in directory part
333  emit dir_selected (info.absolutePath ());
334  }
335  else
336  {
337  // clicked in filename part
338  if (info.isDir ())
339  emit dir_selected (info.absoluteFilePath ());
340  else
341  emit file_selected (info.absoluteFilePath ());
342  }
343  }
344 
346  {
347  if (m_dir_iterator && m_dir_iterator->hasNext ())
348  {
349  QFileInfo info (m_dir_iterator->next ());
350 
352  = static_cast<find_files_model *> (m_file_list->model ());
353 
354  if (is_match (info))
355  m->addFile (info);
356  }
357  else
358  {
359  stop_find ();
360  }
361  }
362 
364  {
365  // make sure we stopped processing
366  stop_find ();
367  }
368 
369  bool find_files_dialog::is_match (const QFileInfo& info)
370  {
371  bool match = true;
372  if (info.isDir ())
373  {
374  if (! m_include_dirs_check->isChecked ()) match = false;
375  if (m_contains_text_check->isChecked ()) match = false;
376  }
377  else
378  {
379  // a file
380  if (m_contains_text_check->isChecked ())
381  {
382  match = false;
383 
384  QFile file (info.absoluteFilePath ());
385  if (file.open (QIODevice::ReadOnly))
386  {
387  QTextStream stream (&file);
388 
389  QString line;
390  QString match_str = m_contains_text_edit->text ();
391 
392  Qt::CaseSensitivity cs = m_content_case_check->isChecked () ?
393  Qt::CaseInsensitive : Qt::CaseSensitive;
394 
395  do
396  {
397  line = stream.readLine ();
398  match = line.contains (match_str, cs);
399  }
400  while (! line.isNull () && match == false);
401  }
402 
403  }
404  }
405 
406  return match;
407  }
408 }
void set_search_dir(const QString &dir)
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
bool is_match(const QFileInfo &info)
void file_selected(const QString &fileName)
find_files_dialog(QWidget *parent=nullptr)
void addFile(const QFileInfo &info)
void dir_selected(const QString &fileName)
void item_double_clicked(const QModelIndex &)
QFileInfo fileInfo(const QModelIndex &p) const
octave::call_stack & cs
Definition: ov-class.cc:1752
double timeout
Definition: graphics.cc:12198
static QIcon icon(const QString &icon_name, bool fallback=true)
p
Definition: lu.cc:138
static QSettings * get_settings(void)
int rowCount(const QModelIndex &p=QModelIndex()) const