# HG changeset patch # User John Donoghue # Date 1366005960 14400 # Node ID 3e8fd0c479b48a055540467faa9906a38222a788 # Parent 59dbdaeeea40fe47fdb82134276e4ae02d551802 Add find files implemtation to main window menu * libgui/src/find-files-dialog.cc, libgui/src/find-files-dialog.h, libgui/src/find-files-model.cc, libgui/src/find-files-model.h: New files. * libgui/src/main-window.cc, libgui/src/main-window.h (main-window::main-window): Initialize find_files_dlg. Connect Find files menu. (main_window::find_files): New function. (main_window::find_files_finished): New function. * libgui/src/module.mk: Update file lists. diff --git a/libgui/src/find-files-dialog.cc b/libgui/src/find-files-dialog.cc new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-dialog.cc @@ -0,0 +1,349 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#include "find-files-dialog.h" +#include "find-files-model.h" +#include "resource-manager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +find_files_dialog::find_files_dialog (QWidget * p) + : QDialog (p) +{ + setWindowTitle (tr("Find Files")); + setWindowIcon (QIcon (":/actions/icons/search.png")); + + _dir_iterator = 0; + + _timer = new QTimer (this); + connect(_timer, SIGNAL(timeout()), this, SLOT(look_for_files())); + + QSettings *settings = resource_manager::get_settings (); + + QLabel * file_name_label = new QLabel (tr ("Named:")); + _file_name_edit = new QLineEdit; + _file_name_edit->setToolTip (tr ("Enter the filename expression")); + + _file_name_edit->setText (settings->value ("findfiles/file_name","*").toString ()); + file_name_label->setBuddy (_file_name_edit); + + QLabel * start_dir_label = new QLabel (tr ("Start in:")); + + _start_dir_edit = new QLineEdit; + _start_dir_edit->setText (settings->value ("findfiles/start_dir",QDir::currentPath()).toString()); + _start_dir_edit->setToolTip (tr ("Enter the start directory")); + start_dir_label->setBuddy (_start_dir_edit); + + QPushButton * browse_button = new QPushButton (tr ("Browse...")); + browse_button->setToolTip (tr ("Browse for start directory")); + connect(browse_button, SIGNAL(clicked()), this, SLOT(browse_folders())); + + _recurse_dirs_check = new QCheckBox (tr ("Recurse directories")); + _recurse_dirs_check->setChecked (settings->value ("findfiles/recurse_dirs", false).toBool()); + _recurse_dirs_check->setToolTip (tr ("Search recursively through directories for matching files")); + + _include_dirs_check = new QCheckBox (tr ("Include directories")); + _include_dirs_check->setChecked (settings->value ("findfiles/include_dirs", false).toBool()); + _include_dirs_check->setToolTip (tr ("Include matching directories in search results")); + + _name_case_check = new QCheckBox (tr ("Name case insensitive")); + _name_case_check->setChecked (settings->value ("findfiles/name_case", false).toBool()); + _name_case_check->setToolTip (tr ("Set matching name is case insensitive")); + + _contains_text_check = new QCheckBox (tr("Contains text:")); + _contains_text_check->setToolTip (tr ("Search must match text")); + _contains_text_check->setChecked (settings->value ("findfiles/check_text", false).toBool()); + + _contains_text_edit = new QLineEdit (); + _contains_text_edit->setToolTip (tr ("Text to match")); + _contains_text_edit->setText (settings->value ("findfiles/contains_text", "").toString()); + + _content_case_check = new QCheckBox (tr("Text case insensitive")); + _content_case_check->setChecked (settings->value ("findfiles/content_case", false).toBool()); + _content_case_check->setToolTip (tr ("Set text content is case insensitive")); + + find_files_model * model = new find_files_model (); + _file_list = new QTableView; + _file_list->setWordWrap (false); + _file_list->setModel (model); + _file_list->setShowGrid (false); + _file_list->setToolTip (tr ("Search results")); + _file_list->horizontalHeader ()->restoreState (settings->value ("findfiles/column_state").toByteArray ()); + _file_list->sortByColumn ( + settings->value ("findfiles/sort_files_by_column",0).toInt (), + static_cast(settings->value ("findfiles/sort_files_by_order",Qt::AscendingOrder).toUInt ())); + + connect (_file_list, SIGNAL(doubleClicked(const QModelIndex&)), + this, SLOT(item_double_clicked(const QModelIndex &))); + + _status_bar = new QStatusBar; + _status_bar->showMessage (tr("Idle.")); + + _find_button = new QPushButton (tr("Find")); + _find_button->setToolTip (tr ("Start search for matching files")); + connect (_find_button, SIGNAL(clicked()), this, SLOT(start_find())); + + _stop_button = new QPushButton (tr("Stop")); + _stop_button->setToolTip (tr ("Stop searching")); + _stop_button->setEnabled (false); + connect (_stop_button, SIGNAL(clicked()), this, SLOT(stop_find())); + + _close_button = new QPushButton (tr("Close")); + _close_button->setToolTip (tr ("Close the search window")); + connect (_close_button, SIGNAL(clicked()), this, SLOT(accept())); + + // layout everything + QDialogButtonBox * button_box = new QDialogButtonBox (Qt::Vertical); + button_box->addButton (_find_button, QDialogButtonBox::ActionRole); + button_box->addButton (_stop_button, QDialogButtonBox::ActionRole); + button_box->addButton (_close_button, QDialogButtonBox::ActionRole); + + QGridLayout * left_layout = new QGridLayout; + left_layout->addWidget (file_name_label,1,1, 1,1); + left_layout->addWidget (_file_name_edit,1,2, 1,-1); + + left_layout->addWidget (start_dir_label,2,1); + left_layout->addWidget (_start_dir_edit,2,2,1,3); + left_layout->addWidget (browse_button,2,5); + left_layout->setColumnStretch (2,1); + + left_layout->addWidget (_recurse_dirs_check,3,1); + left_layout->addWidget (_include_dirs_check,3,2); + left_layout->addWidget (_name_case_check,3,3); + + left_layout->addWidget (_contains_text_check,4,1); + left_layout->addWidget (_contains_text_edit,4,2,1,3); + left_layout->addWidget (_content_case_check,5,1); + + QGridLayout *main_layout = new QGridLayout; + main_layout->setSizeConstraint (QLayout::SetFixedSize); + main_layout->addLayout (left_layout, 0, 0); + main_layout->addWidget (button_box, 0, 1); + main_layout->addWidget (_file_list,1,0); + main_layout->setRowStretch (1,1); + main_layout->addWidget (_status_bar,2,0,1,-1); + + setLayout (main_layout); + + connect (this, SIGNAL(finished(int)), this, SLOT(handle_done(int))); +} + +find_files_dialog::~find_files_dialog () +{ + QSettings *settings = resource_manager::get_settings (); + + int sort_column = _file_list->horizontalHeader ()->sortIndicatorSection (); + Qt::SortOrder sort_order = _file_list->horizontalHeader ()->sortIndicatorOrder (); + settings->setValue ("findfiles/sort_files_by_column", sort_column); + settings->setValue ("findfiles/sort_files_by_order", sort_order); + settings->setValue ("findfiles/column_state", _file_list->horizontalHeader ()->saveState ()); + + settings->setValue ("findfiles/file_name", _file_name_edit->text()); + + settings->setValue ("findfiles/start_dir", _start_dir_edit->text()); + + settings->setValue ("findfiles/recurse_dirs", _recurse_dirs_check->text()); + settings->setValue ("findfiles/include_dirs", _include_dirs_check->text()); + settings->setValue ("findfiles/name_case", _name_case_check->text()); + + settings->setValue ("findfiles/contains_text", _contains_text_edit->text()); + settings->setValue ("findfiles/check_text", _contains_text_check->isChecked ()); + settings->setValue ("findfiles/content_case", _content_case_check->isChecked ()); + + settings->sync (); + + if(_dir_iterator) + delete _dir_iterator; +} + +void find_files_dialog::handle_done (int button) +{ + // make sure we stopped processing + stop_find (); +} + +void find_files_dialog::set_search_dir(const QString &dir) +{ + stop_find(); + _start_dir_edit->setText(dir); +} + +void +find_files_dialog::start_find () +{ + stop_find(); + + find_files_model *m = static_cast (_file_list->model()); + m->clear(); + + QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags; + if (_recurse_dirs_check->isChecked ()) flags |= QDirIterator::Subdirectories; + + QDir::Filters filters = QDir::Dirs|QDir::NoDotAndDotDot|QDir::Files; + if (!_name_case_check->isChecked ()) + filters |= QDir::CaseSensitive; + + QStringList nameFilters; + nameFilters.append (_file_name_edit->text()); + + if (_dir_iterator) delete _dir_iterator; + + _dir_iterator = new QDirIterator (_start_dir_edit->text(), nameFilters, filters, flags); + + // enable/disable widgets + _find_button->setEnabled (false); + _stop_button->setEnabled (true); + _close_button->setEnabled (false); + _start_dir_edit->setEnabled (false); + _file_name_edit->setEnabled (false); + _recurse_dirs_check->setEnabled (false); + _include_dirs_check->setEnabled (false); + _name_case_check->setEnabled (false); + _contains_text_check->setEnabled (false); + _content_case_check->setEnabled (false); + _contains_text_edit->setEnabled (false); + + _status_bar->showMessage (tr("Searching...")); + _timer->start (0); +} + +void +find_files_dialog::stop_find () +{ + _timer->stop (); + + _find_button->setEnabled (true); + _stop_button->setEnabled (false); + _close_button->setEnabled (true); + _start_dir_edit->setEnabled (true); + _file_name_edit->setEnabled (true); + _recurse_dirs_check->setEnabled (true); + _include_dirs_check->setEnabled (true); + _name_case_check->setEnabled (true); + _contains_text_check->setEnabled (true); + _content_case_check->setEnabled (true); + _contains_text_edit->setEnabled (true); + + find_files_model *m = static_cast (_file_list->model()); + QString res_str = QString ("%1 matches").arg(m->rowCount()); + + _status_bar->showMessage (res_str); +} + +void +find_files_dialog::browse_folders () +{ + QString dir = + QFileDialog::getExistingDirectory (this, tr ("Set search directory"), + _start_dir_edit->text()); + + if (! dir.isEmpty ()) + { + _start_dir_edit->setText (dir); + } +} + +void +find_files_dialog::item_double_clicked (const QModelIndex &idx) +{ + find_files_model *m = static_cast (_file_list->model()); + + QFileInfo info = m->fileInfo (idx); + + if(info.isDir()) + emit dir_selected (info.absoluteFilePath()); + else + emit file_selected (info.absoluteFilePath()); +} + +void +find_files_dialog::look_for_files () +{ + if(_dir_iterator && _dir_iterator->hasNext ()) + { + QFileInfo info (_dir_iterator->next ()); + + find_files_model *m = static_cast (_file_list->model ()); + + if(is_match (info)) + m->addFile (info); + } + else + { + stop_find (); + } +} + +bool find_files_dialog::is_match (const QFileInfo &info) +{ + bool match = true; + if (info.isDir ()) + { + if(!_include_dirs_check->isChecked ()) match = false; + if(_contains_text_check->isChecked ()) match = false; + } + else + { + // a file + if (_contains_text_check->isChecked ()) + { + match = false; + + QFile file(info.absoluteFilePath ()); + if (file.open (QIODevice::ReadOnly)) + { + QTextStream stream (&file); + + QString line; + QString match_str = _contains_text_edit->text (); + + Qt::CaseSensitivity cs = _content_case_check->isChecked () ? + Qt::CaseInsensitive : Qt::CaseSensitive; + + do + { + line = stream.readLine (); + match = line.contains (match_str, cs); + } + while(!line.isNull () && match == false); + } + + } + } + + return match; +} + diff --git a/libgui/src/find-files-dialog.h b/libgui/src/find-files-dialog.h new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-dialog.h @@ -0,0 +1,78 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ +#if !defined (find_files_dialog_h) +#define find_files_dialog_h + +#include +#include +#include + +class QLineEdit; +class QPushButton; +class QTableView; +class QTimer; +class QDirIterator; +class QCheckBox; +class QStatusBar; + +class find_files_dialog : public QDialog +{ + Q_OBJECT +public: + find_files_dialog (QWidget * parent=0); + virtual ~find_files_dialog (); + +signals: + void file_selected (const QString &fileName); + void dir_selected (const QString &fileName); + +public slots: + void set_search_dir(const QString &dir); + +private slots: + void start_find (); + void stop_find (); + void browse_folders (); + void look_for_files (); + void item_double_clicked (const QModelIndex&); + void handle_done(int); +private: + bool is_match(const QFileInfo &info); + QLineEdit * _start_dir_edit; + QLineEdit * _file_name_edit; + QPushButton * _stop_button; + QPushButton * _find_button; + QPushButton * _close_button; + QTableView * _file_list; + QTimer * _timer; + QCheckBox * _recurse_dirs_check; + QCheckBox * _include_dirs_check; + QCheckBox * _name_case_check; + QCheckBox * _contains_text_check; + QCheckBox * _content_case_check; + QLineEdit * _contains_text_edit; + QDirIterator * _dir_iterator; + QStatusBar * _status_bar; +}; + +#endif // find_files_dialog_h + diff --git a/libgui/src/find-files-model.cc b/libgui/src/find-files-model.cc new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-model.cc @@ -0,0 +1,135 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#include "find-files-model.h" +#include + +find_files_model::find_files_model (QObject *p) + : QAbstractListModel(p) +{ + _columnNames.append (tr ("Filename")); + _columnNames.append (tr ("Directory")); +} + +find_files_model::~find_files_model () +{ +} + +void +find_files_model::clear () +{ + beginResetModel(); + + _files.clear(); + + endResetModel (); +} + +void +find_files_model::addFile (const QFileInfo &info) +{ + beginInsertRows(QModelIndex(), _files.size(), _files.size() ); + + _files.append(info); + + endInsertRows(); +} + +int +find_files_model::rowCount (const QModelIndex & p) const +{ + return _files.size(); +} + +int +find_files_model::columnCount (const QModelIndex & p) const +{ + return _columnNames.size (); +} + +QVariant +find_files_model::data (const QModelIndex& idx, int role) const +{ + QVariant retval; + + if (idx.isValid ()) + { + if(role == Qt::DisplayRole) + { + switch (idx.column ()) + { + case 0: + retval = QVariant (_files[idx.row()].fileName()); + break; + + case 1: + retval = QVariant (_files[idx.row()].absolutePath()); + break; + + default: + break; + } + } + else if(role == Qt:: DecorationRole) + { + switch (idx.column()) + { + case 0: + retval = fileIcon(idx); + default: + break; + } + } + } + + return retval; +} + +QVariant +find_files_model::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return _columnNames[section]; + else + return QVariant (); +} + +QFileInfo +find_files_model::fileInfo (const QModelIndex & p) const +{ + if(p.isValid ()) + { + return _files[p.row()]; + } + return QFileInfo (); +} + +QIcon +find_files_model::fileIcon (const QModelIndex &p) const +{ + QFileIconProvider icon_provider; + if(p.isValid ()) + { + return icon_provider.icon (_files[p.row()]); + } + return QIcon (); +} diff --git a/libgui/src/find-files-model.h b/libgui/src/find-files-model.h new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-model.h @@ -0,0 +1,59 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ +#if !defined (find_files_model_h) +#define find_files_model_h + +#include +#include +#include +#include +#include + + +class find_files_model : public QAbstractListModel +{ +public: + find_files_model(QObject *p=0); + ~find_files_model (); + + void clear(); + + void addFile(const QFileInfo &info); + + int rowCount(const QModelIndex & p=QModelIndex()) const; + + int columnCount(const QModelIndex & p=QModelIndex()) const; + + QVariant data (const QModelIndex& idx, int role) const; + + QVariant headerData (int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QFileInfo fileInfo (const QModelIndex & p) const; + QIcon fileIcon (const QModelIndex &p) const; +private: + QList _files; + QStringList _columnNames; +}; + +#endif // find_files_model_h + diff --git a/libgui/src/main-window.cc b/libgui/src/main-window.cc --- a/libgui/src/main-window.cc +++ b/libgui/src/main-window.cc @@ -74,6 +74,7 @@ doc_browser_window (new documentation_dock_widget (this)), editor_window (create_default_editor (this)), workspace_window (new workspace_view (this)), + find_files_dlg (0), _octave_main_thread (0), _octave_qt_link (0) { @@ -94,6 +95,11 @@ delete history_window; delete status_bar; delete _workspace_model; + if (find_files_dlg) + { + delete find_files_dlg; + find_files_dlg = 0; + } delete _octave_main_thread; delete _octave_qt_link; } @@ -960,7 +966,6 @@ QAction *find_files_action = edit_menu->addAction (tr ("Find Files...")); find_files_action->setShortcut (ctrl_shift + Qt::Key_F); - find_files_action->setEnabled (false); // TODO: Make this work. edit_menu->addSeparator (); @@ -979,6 +984,9 @@ connect (_paste_action, SIGNAL (triggered()), command_window, SLOT (pasteClipboard ())); + connect (find_files_action, SIGNAL (triggered()), + this, SLOT (find_files ())); + connect (clear_command_window_action, SIGNAL (triggered ()), this, SLOT (handle_clear_command_window_request ())); @@ -1403,3 +1411,41 @@ { Fquit (); } + +void +main_window::find_files(const QString &start_dir) +{ + + if (! find_files_dlg) + { + find_files_dlg = new find_files_dialog (this); + + connect (find_files_dlg, SIGNAL (finished (int)), + this, SLOT (find_files_finished (int))); + + connect (find_files_dlg, SIGNAL (dir_selected(const QString &)), + file_browser_window, SLOT(set_current_directory(const QString&))); + + connect (find_files_dlg, SIGNAL (file_selected(const QString &)), + this, SLOT(open_file(const QString &))); + + find_files_dlg->setWindowModality (Qt::NonModal); + } + + if (! find_files_dlg->isVisible ()) + { + find_files_dlg->show (); + } + + find_files_dlg->set_search_dir(start_dir); + + find_files_dlg->activateWindow (); + +} + +void +main_window::find_files_finished(int button) +{ + +} + diff --git a/libgui/src/main-window.h b/libgui/src/main-window.h --- a/libgui/src/main-window.h +++ b/libgui/src/main-window.h @@ -53,6 +53,7 @@ #include "terminal-dock-widget.h" #include "documentation-dock-widget.h" #include "octave-qt-link.h" +#include "find-files-dialog.h" /** * \class MainWindow @@ -140,6 +141,9 @@ const QIntList&, const QIntList&, const QStringList&); + // find files dialog + void find_files(const QString &startdir=QDir::currentPath()); + void find_files_finished(int); protected: void closeEvent (QCloseEvent * closeEvent); @@ -235,6 +239,9 @@ static const int current_directory_max_count = 16; QLineEdit *_current_directory_line_edit; + // Find files dialog + find_files_dialog * find_files_dlg; + octave_main_thread *_octave_main_thread; octave_qt_link *_octave_qt_link; diff --git a/libgui/src/module.mk b/libgui/src/module.mk --- a/libgui/src/module.mk +++ b/libgui/src/module.mk @@ -84,6 +84,7 @@ src/moc-welcome-wizard.cc \ src/moc-workspace-model.cc \ src/moc-workspace-view.cc \ + src/moc-find-files-dialog.cc \ src/qtinfo/moc-parser.cc \ src/qtinfo/moc-webinfo.cc \ src/moc-octave-dock-widget.cc @@ -120,6 +121,8 @@ src/terminal-dock-widget.h \ src/color-picker.h \ src/welcome-wizard.h \ + src/find-files-dialog.h \ + src/find-files-model.h \ src/workspace-model.h \ src/workspace-view.h @@ -143,6 +146,8 @@ src/terminal-dock-widget.cc \ src/color-picker.cc \ src/welcome-wizard.cc \ + src/find-files-dialog.cc \ + src/find-files-model.cc \ src/workspace-model.cc \ src/workspace-view.cc