[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