[rkward] rkward: Allow regular expressions in object list view filtering.
Thomas Friedrichsmeier
thomas.friedrichsmeier at ruhr-uni-bochum.de
Mon Nov 16 10:19:13 UTC 2015
Git commit 75f6adff2a1986a67e6079c2c2203f3abdc325f7 by Thomas Friedrichsmeier.
Committed on 16/11/2015 at 10:19.
Pushed by tfry into branch 'master'.
Allow regular expressions in object list view filtering.
Use the same control in packages search.
M +7 -13 rkward/dialogs/rkloadlibsdialog.cpp
M +2 -1 rkward/dialogs/rkloadlibsdialog.h
M +1 -0 rkward/misc/CMakeLists.txt
A +67 -0 rkward/misc/rkdynamicsearchline.cpp [License: GPL (v2+)]
A +48 -0 rkward/misc/rkdynamicsearchline.h [License: GPL (v2+)]
M +9 -6 rkward/misc/rkobjectlistview.cpp
M +2 -0 rkward/misc/rkobjectlistview.h
http://commits.kde.org/rkward/75f6adff2a1986a67e6079c2c2203f3abdc325f7
diff --git a/rkward/dialogs/rkloadlibsdialog.cpp b/rkward/dialogs/rkloadlibsdialog.cpp
index a330306..7eb658f 100644
--- a/rkward/dialogs/rkloadlibsdialog.cpp
+++ b/rkward/dialogs/rkloadlibsdialog.cpp
@@ -45,6 +45,7 @@
#include "../misc/rkprogresscontrol.h"
#include "../misc/rkstandardicons.h"
#include "../misc/rkcommonfunctions.h"
+#include "../misc/rkdynamicsearchline.h"
#include "../debug.h"
@@ -678,7 +679,6 @@ InstallPackagesWidget::InstallPackagesWidget (RKLoadLibsDialog *dialog) : QWidge
packages_view->setSortingEnabled (true);
model = new RKRPackageInstallationStatusSortFilterModel (this);
model->setSourceModel (packages_status);
- model->setFilterCaseSensitivity (Qt::CaseInsensitive);
model->setSortCaseSensitivity (Qt::CaseInsensitive);
packages_view->setModel (model);
packages_view->setItemDelegateForColumn (0, new InstallPackagesDelegate (packages_view));
@@ -702,9 +702,9 @@ InstallPackagesWidget::InstallPackagesWidget (RKLoadLibsDialog *dialog) : QWidge
hbox->addLayout (buttonvbox);
buttonvbox->setContentsMargins (0, 0, 0, 0);
QLabel *label = new QLabel (i18n ("Show only packages matching:"), this);
- filter_edit = new QLineEdit (QString (), this);
- RKCommonFunctions::setTips (i18n ("<p>You can limit the packages displayed in the list to with names or titles matching a filter string.</p><p><b>Note:</b> To limit the search to matches at the start of the string, start the filter with '^', e.g. ('^rk.'). To limit searches to the end of the string, append '$' at the end of the filter.</p>"), label, filter_edit);
- connect (filter_edit, SIGNAL (textChanged(QString)), this, SLOT (filterChanged()));
+ filter_edit = new RKDynamicSearchLine (this);
+ RKCommonFunctions::setTips (i18n ("<p>You can limit the packages displayed in the list to with names or titles matching a filter string.</p>") + filter_edit->regexpTip (), label, filter_edit);
+ filter_edit->setModelToFilter (model);
rkward_packages_only = new QCheckBox (i18n ("Show only packages providing RKWard dialogs"), this);
RKCommonFunctions::setTips (i18n ("<p>Some but not all R packages come with plugins for RKWard. That means they provide a graphical user-interface in addition to R functions. Check this box to show only such packages.</p><p></p>"), rkward_packages_only);
connect (rkward_packages_only, SIGNAL(stateChanged(int)), this, SLOT (filterChanged()));
@@ -768,14 +768,8 @@ void InstallPackagesWidget::rowClicked (const QModelIndex& row) {
void InstallPackagesWidget::filterChanged () {
RK_TRACE (DIALOGS);
- QString f = filter_edit->text ();
- if (f.isEmpty ()) f = '*';
- else {
- if (!f.startsWith ('^')) f.prepend ('*');
- if (!f.endsWith ('$')) f.append ('*');
- }
- model->setFilterWildcard (f);
model->setRKWardOnly (rkward_packages_only->isChecked ());
+ // NOTE: filter string already set by RKDynamicSearchLine
}
void InstallPackagesWidget::trySelectPackage (const QString &package_name) {
@@ -1244,9 +1238,9 @@ bool RKRPackageInstallationStatusSortFilterModel::filterAcceptsRow (int source_r
}
// filter on Name and Title
QString name = source_parent.child (source_row, RKRPackageInstallationStatus::PackageName).data ().toString ();
- if (filterRegExp ().exactMatch (name)) return true;
+ if (name.contains (filterRegExp ())) return true;
QString title = source_parent.child (source_row, RKRPackageInstallationStatus::PackageTitle).data ().toString ();
- return (filterRegExp ().exactMatch (title));
+ return (title.contains (filterRegExp ()));
}
void RKRPackageInstallationStatusSortFilterModel::setRKWardOnly (bool only) {
diff --git a/rkward/dialogs/rkloadlibsdialog.h b/rkward/dialogs/rkloadlibsdialog.h
index fe37480..b6aade3 100644
--- a/rkward/dialogs/rkloadlibsdialog.h
+++ b/rkward/dialogs/rkloadlibsdialog.h
@@ -39,6 +39,7 @@ class RCommandChain;
class QCheckBox;
class PackageInstallParamsWidget;
class InstallPackagesWidget;
+class RKDynamicSearchLine;
/**
Dialog which excapsulates widgets to load/unload, update and install R packages
@@ -260,7 +261,7 @@ private:
RKRPackageInstallationStatusSortFilterModel *model;
QPushButton *mark_all_updates_button;
- QLineEdit *filter_edit;
+ RKDynamicSearchLine *filter_edit;
QCheckBox *rkward_packages_only;
PackageInstallParamsWidget *install_params;
diff --git a/rkward/misc/CMakeLists.txt b/rkward/misc/CMakeLists.txt
index 6f521e2..5417ff3 100644
--- a/rkward/misc/CMakeLists.txt
+++ b/rkward/misc/CMakeLists.txt
@@ -26,6 +26,7 @@ SET(misc_STAT_SRCS
rkmessagecatalog.cpp
rkdbusapi.cpp
rkfindbar.cpp
+ rkdynamicsearchline.cpp
rkaccordiontable.cpp
)
diff --git a/rkward/misc/rkdynamicsearchline.cpp b/rkward/misc/rkdynamicsearchline.cpp
new file mode 100644
index 0000000..0bcbe04
--- /dev/null
+++ b/rkward/misc/rkdynamicsearchline.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+ rkdynamicsearchline - description
+ -------------------
+ begin : Mon Nov 16 2015
+ copyright : (C) 2015 by Thomas Friedrichsmeier
+ email : thomas.friedrichsmeier at kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "rkdynamicsearchline.h"
+
+#include <klocale.h>
+#include <QSortFilterProxyModel>
+
+#include "../debug.h"
+
+RKDynamicSearchLine::RKDynamicSearchLine (QWidget *parent) : KLineEdit (parent) {
+ RK_TRACE (MISC);
+
+ model = 0;
+ setClearButtonShown (true);
+ setClickMessage (i18n ("Search"));
+ timer.setSingleShot (true);
+ connect (&timer, SIGNAL (timeout ()), this, SLOT (delayedSearch ()));
+ connect (this, SIGNAL (textChanged(QString)), this, SLOT (textChanged()));
+}
+
+RKDynamicSearchLine::~RKDynamicSearchLine () {
+ RK_TRACE (MISC);
+}
+
+void RKDynamicSearchLine::textChanged () {
+ RK_TRACE (MISC);
+ timer.start (300);
+}
+
+QString RKDynamicSearchLine::regexpTip () const {
+ return (i18n ("<p><b>Note:</b> This search line accepts so-called regular expressions. To limit the search to matches at the start of the string, start the filter with '^', e.g. ('^rk.'). To limit searches to the end of the string, append '$' at the end of the filter. To match arbitrary text in the middle of the search term, insert '.*'.</p>"));
+}
+
+void RKDynamicSearchLine::delayedSearch () {
+ RK_TRACE (MISC);
+
+ QString term = text ();
+ bool allnum = true;
+ for (int i = 0; i < term.size (); ++i) {
+ if (term.at (i).isLetterOrNumber ()) {
+ allnum = false;
+ break;
+ }
+ }
+
+ QRegExp filter (term, Qt::CaseInsensitive, allnum ? QRegExp::FixedString : QRegExp::RegExp2);
+ if (model) model->setFilterRegExp (filter);
+ emit (searchChanged (filter));
+}
+
+// KF5 TODO: remove
+#include "rkdynamicsearchline.moc"
diff --git a/rkward/misc/rkdynamicsearchline.h b/rkward/misc/rkdynamicsearchline.h
new file mode 100644
index 0000000..3f5918c
--- /dev/null
+++ b/rkward/misc/rkdynamicsearchline.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ rkdynamicsearchline - description
+ -------------------
+ begin : Mon Nov 16 2015
+ copyright : (C) 2015 by Thomas Friedrichsmeier
+ email : thomas.friedrichsmeier at kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RKDYNAMICSEARCHLINE_H
+#define RKDYNAMICSEARCHLINE_H
+
+#include <klineedit.h>
+
+#include <QTimer>
+
+class QSortFilterProxyModel;
+
+/** This class is mostly like KFilterProxySearchLine, except allowing us to filter using regexps.
+ * Also some internal differences, due to the fact that we don't have to hide implementation details as in a framework lib. */
+class RKDynamicSearchLine : public KLineEdit {
+ Q_OBJECT
+public:
+ RKDynamicSearchLine (QWidget *parent);
+ virtual ~RKDynamicSearchLine ();
+
+/** If a model is set, will call setFilterRegExp() when the search string is changed. */
+ void setModelToFilter (QSortFilterProxyModel* _model) { model = _model; };
+ QString regexpTip () const;
+signals:
+ void searchChanged (const QRegExp& search);
+private slots:
+ void textChanged ();
+ void delayedSearch ();
+private:
+ QTimer timer;
+ QSortFilterProxyModel *model;
+};
+
+#endif
diff --git a/rkward/misc/rkobjectlistview.cpp b/rkward/misc/rkobjectlistview.cpp
index a5aebbf..f2fc99e 100644
--- a/rkward/misc/rkobjectlistview.cpp
+++ b/rkward/misc/rkobjectlistview.cpp
@@ -17,7 +17,6 @@
#include "rkobjectlistview.h"
#include <klocale.h>
-#include <kfilterproxysearchline.h>
#include <QContextMenuEvent>
#include <QMenu>
@@ -36,6 +35,7 @@
#include "../core/rkmodificationtracker.h"
#include "rkstandardicons.h"
#include "rkcommonfunctions.h"
+#include "rkdynamicsearchline.h"
#include "../settings/rksettingsmoduleobjectbrowser.h"
#include "../debug.h"
@@ -265,8 +265,10 @@ QWidget* RKObjectListViewSettings::filterWidget (QWidget *parent) {
hlayout->setContentsMargins (0, 0, 0, 0);
layout->addLayout (hlayout);
- KFilterProxySearchLine* sline = new KFilterProxySearchLine (filter_widget);
- sline->setProxy (this);
+ sline = new RKDynamicSearchLine (filter_widget);
+ sline->setModelToFilter (this);
+ RKCommonFunctions::setTips (sline->regexpTip (), sline);
+ connect (sline, SIGNAL (searchChanged(QRegExp)), this, SLOT (filterSettingsChanged()));
hlayout->addWidget (sline);
QPushButton* expander = new QPushButton (filter_widget);
expander->setIcon (RKStandardIcons::getIcon (RKStandardIcons::ActionConfigureGeneric));
@@ -331,7 +333,7 @@ QWidget* RKObjectListViewSettings::filterWidget (QWidget *parent) {
connect (persistent_settings_actions[ShowObjectsHidden], SIGNAL (triggered(bool)), hidden_objects_box, SLOT (setChecked(bool)));
bottom_layout->addWidget (hidden_objects_box);
- reset_filters_button = new QPushButton (i18n ("Reset filters"), filter_widget);
+ reset_filters_button = new QPushButton (i18nc ("Width is limited, please opt for something that is not much longer than the English string. Simply 'Clear'/'Reset' should be good enough to understand the function.", "Reset filters"), filter_widget);
connect (reset_filters_button, SIGNAL (clicked(bool)), this, SLOT(resetFilters()));
RKCommonFunctions::setTips (i18n ("Discards the current object search filters"), reset_filters_button);
reset_filters_button->hide ();
@@ -350,11 +352,12 @@ void RKObjectListViewSettings::resetFilters () {
filter_on_label_box->setChecked (true);
filter_on_class_box->setChecked (true);
depth_box->setCurrentIndex (1);
-#warning TODO: reset search line
+ sline->setText (QString ());
} else {
hide_functions = hide_non_functions = false;
filter_on_class = filter_on_label = filter_on_name = true;
depth_limit = 1;
+ setFilterRegExp (QRegExp ());
}
in_reset_filters = false;
updateSelf ();
@@ -373,7 +376,7 @@ void RKObjectListViewSettings::filterSettingsChanged () {
hide_functions = type_box->currentIndex () == 2;
hide_non_functions = type_box->currentIndex () == 1;
- reset_filters_button->setVisible (!filter_on_name || !filter_on_class || !filter_on_label || (depth_limit != 1) || hide_functions || hide_non_functions);
+ reset_filters_button->setVisible (!filter_on_name || !filter_on_class || !filter_on_label || (depth_limit != 1) || hide_functions || hide_non_functions || !sline->text ().isEmpty ());
}
for (int i = 0; i < SettingsCount; ++i) {
diff --git a/rkward/misc/rkobjectlistview.h b/rkward/misc/rkobjectlistview.h
index 95e1c30..5bee726 100644
--- a/rkward/misc/rkobjectlistview.h
+++ b/rkward/misc/rkobjectlistview.h
@@ -30,6 +30,7 @@ class QTimer;
class QCheckBox;
class QComboBox;
class QPushButton;
+class RKDynamicSearchLine;
/**
This class provides the common functionality for the tree views in the RObjectBrowser and RKVarselector(s). The caps it (will) provide are: keeping the list up to date and emitting change-signals when appropriate, filtering for certain types of objects, sorting, mapping items to objects. Maybe some GUI-stuff like popup-menus should also be added to this class?
@@ -121,6 +122,7 @@ private:
void updateSelf ();
QWidget *filter_widget;
+ RKDynamicSearchLine *sline;
QWidget *filter_widget_expansion;
QCheckBox* filter_on_name_box;
QCheckBox* filter_on_label_box;
More information about the rkward-tracker
mailing list