diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 648053014f..e240f71066 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -216,6 +216,7 @@ set(dolphinstatic_SRCS
panels/folders/folderspanel.cpp
panels/terminal/terminalpanel.cpp
search/dolphinfacetswidget.cpp
+ search/dolphinquery.cpp
search/dolphinsearchbox.cpp
settings/general/behaviorsettingspage.cpp
settings/general/configurepreviewplugindialog.cpp
diff --git a/src/org.kde.dolphin.appdata.xml b/src/org.kde.dolphin.appdata.xml
index 155be6c44a..9fcc1b5a5a 100644
--- a/src/org.kde.dolphin.appdata.xml
+++ b/src/org.kde.dolphin.appdata.xml
@@ -523,7 +523,7 @@
復原支援
- https://dolphin.kde.org/
+ https://kde.org/applications/system/dolphin
https://bugs.kde.org/enter_bug.cgi?format=guided&product=dolphin
https://docs.kde.org/?application=dolphin
https://www.kde.org/community/donations/?app=dolphin&source=appdata
diff --git a/src/search/dolphinfacetswidget.cpp b/src/search/dolphinfacetswidget.cpp
index 1827192259..ae05509e77 100644
--- a/src/search/dolphinfacetswidget.cpp
+++ b/src/search/dolphinfacetswidget.cpp
@@ -153,7 +153,7 @@ void DolphinFacetsWidget::setRatingTerm(const QString& term)
void DolphinFacetsWidget::setFacetType(const QString& type)
{
- for (int index = 1; index <= m_typeSelector->count(); index++) {
+ for (int index = 0; index <= m_typeSelector->count(); index++) {
if (type == m_typeSelector->itemData(index).toString()) {
m_typeSelector->setCurrentIndex(index);
break;
diff --git a/src/search/dolphinquery.cpp b/src/search/dolphinquery.cpp
new file mode 100644
index 0000000000..09a8418591
--- /dev/null
+++ b/src/search/dolphinquery.cpp
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Ismael Asensio *
+ * *
+ * 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. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "dolphinquery.h"
+
+#include
+#ifdef HAVE_BALOO
+#include
+#endif
+
+namespace {
+ /** Checks if a given term in the Baloo::Query::searchString() is a special search term.
+ * This is a copy of `DolphinFacetsWidget::isRatingTerm()` method.
+ */
+ bool isSearchTerm(const QString& term)
+ {
+ static const QLatin1String searchTokens[] {
+ QLatin1String("modified>="),
+ QLatin1String("rating>=")
+ };
+
+ for (const auto &searchToken : searchTokens) {
+ if (term.startsWith(searchToken)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+DolphinQuery DolphinQuery::fromBalooSearchUrl(const QUrl& searchUrl)
+{
+ DolphinQuery model;
+ model.m_searchUrl = searchUrl;
+
+#ifdef HAVE_BALOO
+ const Baloo::Query query = Baloo::Query::fromSearchUrl(searchUrl);
+
+ model.m_includeFolder = query.includeFolder();
+
+ model.m_searchText = query.searchString();
+
+ const QStringList types = query.types();
+ model.m_fileType = types.isEmpty() ? QString() : types.first();
+
+ const QStringList subTerms = query.searchString().split(' ', QString::SkipEmptyParts);
+ foreach (const QString& subTerm, subTerms) {
+ if (subTerm.startsWith(QLatin1String("filename:"))) {
+ const QString value = subTerm.mid(9);
+ model.m_searchText = value;
+ } else if (isSearchTerm(subTerm)) {
+ model.m_searchTerms << subTerm;
+ }
+ }
+#endif
+ return model;
+}
+
+QUrl DolphinQuery::searchUrl() const
+{
+ return m_searchUrl;
+}
+
+QString DolphinQuery::text() const
+{
+ return m_searchText;
+}
+
+QString DolphinQuery::type() const
+{
+ return m_fileType;
+}
+
+QStringList DolphinQuery::searchTerms() const
+{
+ return m_searchTerms;
+}
+
+QString DolphinQuery::includeFolder() const
+{
+ return m_includeFolder;
+}
diff --git a/src/search/dolphinquery.h b/src/search/dolphinquery.h
new file mode 100644
index 0000000000..e60008e3bf
--- /dev/null
+++ b/src/search/dolphinquery.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Ismael Asensio *
+ * *
+ * 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. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#ifndef DOLPHINQUERY_H
+#define DOLPHINQUERY_H
+
+#include "dolphin_export.h"
+
+#include
+#include
+
+/**
+ * @brief Simple query model that parses a Baloo search Url and extracts its
+ * separate components to be displayed on dolphin search box.
+ */
+class DolphinQuery
+{
+public:
+ /** Calls Baloo::Query::fromSearchUrl() with the given @p searchUrl
+ * and parses the result to extract its separate components */
+ static DolphinQuery fromBalooSearchUrl(const QUrl& searchUrl);
+
+ /** @return the \a searchUrl passed to Baloo::Query::fromSearchUrl() */
+ QUrl searchUrl() const;
+ /** @return the user text part of the query, to be shown in the searchbar */
+ QString text() const;
+ /** @return the first of Baloo::Query::types(), or an empty string */
+ QString type() const;
+ /** @return a list of the search terms of the Baloo::Query that act as a filter,
+ * such as \"rating>= value\" or \"modified>= date\"*/
+ QStringList searchTerms() const;
+ /** @return Baloo::Query::includeFolder(), that is, the initial directory
+ * for the query or an empty string if its a global search" */
+ QString includeFolder() const;
+
+private:
+ QUrl m_searchUrl;
+ QString m_searchText;
+ QString m_fileType;
+ QStringList m_searchTerms;
+ QString m_includeFolder;
+};
+
+#endif //DOLPHINQUERY_H
diff --git a/src/search/dolphinsearchbox.cpp b/src/search/dolphinsearchbox.cpp
index 751b23942f..ee7cbe6283 100644
--- a/src/search/dolphinsearchbox.cpp
+++ b/src/search/dolphinsearchbox.cpp
@@ -22,6 +22,7 @@
#include "dolphin_searchsettings.h"
#include "dolphinfacetswidget.h"
+#include "dolphinquery.h"
#include "panels/places/placesitemmodel.h"
#include
@@ -143,7 +144,8 @@ QUrl DolphinSearchBox::urlForSearching() const
void DolphinSearchBox::fromSearchUrl(const QUrl& url)
{
if (url.scheme() == QLatin1String("baloosearch")) {
- fromBalooSearchUrl(url);
+ const DolphinQuery query = DolphinQuery::fromBalooSearchUrl(url);
+ updateFromQuery(query);
} else if (url.scheme() == QLatin1String("filenamesearch")) {
const QUrlQuery query(url);
setText(query.queryItemValue(QStringLiteral("search")));
@@ -498,11 +500,8 @@ QUrl DolphinSearchBox::balooUrlForSearching() const
#endif
}
-void DolphinSearchBox::fromBalooSearchUrl(const QUrl& url)
+void DolphinSearchBox::updateFromQuery(const DolphinQuery& query)
{
-#ifdef HAVE_BALOO
- const Baloo::Query query = Baloo::Query::fromSearchUrl(url);
-
// Block all signals to avoid unnecessary "searchRequest" signals
// while we adjust the search text and the facet widget.
blockSignals(true);
@@ -514,30 +513,17 @@ void DolphinSearchBox::fromBalooSearchUrl(const QUrl& url)
setSearchPath(QUrl::fromLocalFile(QDir::homePath()));
}
+ setText(query.text());
+
m_facetsWidget->resetOptions();
-
- setText(query.searchString());
-
- QStringList types = query.types();
- if (!types.isEmpty()) {
- m_facetsWidget->setFacetType(types.first());
- }
-
- const QStringList subTerms = query.searchString().split(' ', QString::SkipEmptyParts);
- foreach (const QString& subTerm, subTerms) {
- if (subTerm.startsWith(QLatin1String("filename:"))) {
- const QString value = subTerm.mid(9);
- setText(value);
- } else if (m_facetsWidget->isRatingTerm(subTerm)) {
- m_facetsWidget->setRatingTerm(subTerm);
- }
+ m_facetsWidget->setFacetType(query.type());
+ const QStringList searchTerms = query.searchTerms();
+ for (const QString& searchTerm : searchTerms) {
+ m_facetsWidget->setRatingTerm(searchTerm);
}
m_startSearchTimer->stop();
blockSignals(false);
-#else
- Q_UNUSED(url)
-#endif
}
void DolphinSearchBox::updateFacetsVisible()
diff --git a/src/search/dolphinsearchbox.h b/src/search/dolphinsearchbox.h
index 241dc40c12..5fef4ec5a7 100644
--- a/src/search/dolphinsearchbox.h
+++ b/src/search/dolphinsearchbox.h
@@ -24,6 +24,7 @@
#include
class DolphinFacetsWidget;
+class DolphinQuery;
class QLineEdit;
class KSeparator;
class QToolButton;
@@ -152,10 +153,9 @@ private:
QUrl balooUrlForSearching() const;
/**
- * Extracts information from the given Baloo search \a url to
- * initialize the search box properly.
+ * Sets the searchbox UI with the parameters established by the \a query
*/
- void fromBalooSearchUrl(const QUrl& url);
+ void updateFromQuery(const DolphinQuery& query);
void updateFacetsVisible();
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 6ecac1f1e8..8d44986758 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -49,6 +49,13 @@ if (KF5Baloo_FOUND)
LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
endif()
+# DolphinQuery
+if (KF5Baloo_FOUND)
+ ecm_add_test(dolphinquerytest.cpp
+ TEST_NAME dolphinquerytest
+ LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
+endif()
+
# KStandardItemModelTest
ecm_add_test(kstandarditemmodeltest.cpp
TEST_NAME kstandarditemmodeltest
diff --git a/src/tests/dolphinquerytest.cpp b/src/tests/dolphinquerytest.cpp
new file mode 100644
index 0000000000..14eb03620c
--- /dev/null
+++ b/src/tests/dolphinquerytest.cpp
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Ismael Asensio *
+ * *
+ * 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. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "search/dolphinquery.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+class DolphinSearchBoxTest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testBalooSearchParsing_data();
+ void testBalooSearchParsing();
+};
+
+/**
+ * Defines the parameters for the test cases in testBalooSearchParsing()
+ */
+void DolphinSearchBoxTest::testBalooSearchParsing_data()
+{
+ const QString text = QStringLiteral("xyz");
+ const QString filename = QStringLiteral("filename:\"xyz\"");
+ const QString rating = QStringLiteral("rating>=2");
+ const QString modified = QString("modified>=2019-08-07");
+
+ QTest::addColumn("searchString");
+ QTest::addColumn("expectedText");
+ QTest::addColumn("expectedTerms");
+
+ // Test for "Content"
+ QTest::newRow("content") << text << text << QStringList();
+ QTest::newRow("content/empty") << "" << "" << QStringList();
+ QTest::newRow("content/singleQuote") << "\"" << "" << QStringList();
+ QTest::newRow("content/doubleQuote") << "\"\"" << "" << QStringList();
+ // Test for empty `filename`
+ QTest::newRow("filename") << filename << text << QStringList();
+ QTest::newRow("filename/empty") << "filename:" << "" << QStringList();
+ QTest::newRow("filename/singleQuote") << "filename:\"" << "" << QStringList();
+ QTest::newRow("filename/doubleQuote") << "filename:\"\"" << "" << QStringList();
+
+ // Test for rating
+ QTest::newRow("rating") << rating << "" << QStringList({rating});
+ QTest::newRow("rating+content") << rating + " " + text << text << QStringList({rating});
+ QTest::newRow("rating+filename") << rating + " " + filename << text << QStringList({rating});
+ // Test for modified date
+ QTest::newRow("modified") << modified << "" << QStringList({modified});
+ QTest::newRow("modified+content") << modified + " " + text << text << QStringList({modified});
+ QTest::newRow("modified+filename") << modified + " " + filename << text << QStringList({modified});
+ // Combined tests
+ QTest::newRow("rating+modified") << rating + " AND " + modified << "" << QStringList({modified, rating});
+ QTest::newRow("rating+modified+content") << rating + " AND " + modified + " " + text << text << QStringList({modified, rating});
+ QTest::newRow("rating+modified+filename") << rating + " AND " + modified + " " + filename << text << QStringList({modified, rating});
+}
+
+/**
+ * Helper function to compose the baloo query URL used for searching
+ */
+QUrl composeQueryUrl(const QString& searchString)
+{
+ const QJsonObject jsonObject {
+ {"searchString", searchString}
+ };
+
+ const QJsonDocument doc(jsonObject);
+ const QString queryString = QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
+
+ QUrlQuery urlQuery;
+ urlQuery.addQueryItem(QStringLiteral("json"), queryString);
+
+ QUrl searchUrl;
+ searchUrl.setScheme(QLatin1String("baloosearch"));
+ searchUrl.setQuery(urlQuery);
+
+ return searchUrl;
+}
+
+/**
+ * The test verifies whether the different terms of a Baloo search URL ("baloosearch:") are
+ * properly handled by the searchbox, and only "user" or filename terms are added to the
+ * text bar of the searchbox.
+ */
+void DolphinSearchBoxTest::testBalooSearchParsing()
+{
+ QFETCH(QString, searchString);
+ QFETCH(QString, expectedText);
+ QFETCH(QStringList, expectedTerms);
+
+ const QUrl testUrl = composeQueryUrl(searchString);
+ const DolphinQuery query = DolphinQuery::fromBalooSearchUrl(testUrl);
+
+ QStringList searchTerms = query.searchTerms();
+ searchTerms.sort();
+
+ // FIXME: Current parsing bugs
+ QEXPECT_FAIL("content/singleQuote", "Quotes around text are shown", Continue);
+ QEXPECT_FAIL("content/doubleQuote", "Quotes around text are shown", Continue);
+
+ QEXPECT_FAIL("filename", "Quotes around text are shown", Continue);
+ QEXPECT_FAIL("filename/singleQuote", "Quotes around text are shown", Continue);
+ QEXPECT_FAIL("filename/doubleQuote", "Quotes around text are shown", Continue);
+
+ QEXPECT_FAIL("rating" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("rating+content" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("rating+filename" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("modified" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("modified+content" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("modified+filename" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("rating+modified" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("rating+modified+content" , "Text includes also search terms", Continue);
+ QEXPECT_FAIL("rating+modified+filename", "Text includes also search terms", Continue);
+
+ // Check for parsed text (would be displayed on the input search bar)
+ QCOMPARE(query.text(), expectedText);
+
+ // Check for parsed search terms (would be displayed by the facetsWidget)
+ QCOMPARE(searchTerms.count(), expectedTerms.count());
+ for (int i = 0; i < expectedTerms.count(); i++) {
+ QCOMPARE(searchTerms.at(i), expectedTerms.at(i));
+ }
+}
+
+QTEST_MAIN(DolphinSearchBoxTest)
+
+#include "dolphinquerytest.moc"