]> cloud.milkyroute.net Git - dolphin.git/blob - src/search/dolphinquery.cpp
Add support to tags: scheme in DolphinQuery
[dolphin.git] / src / search / dolphinquery.cpp
1 /***************************************************************************
2 * Copyright (C) 2019 by Ismael Asensio <isma.af@mgmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "dolphinquery.h"
21
22 #include <QRegularExpression>
23
24 #include <config-baloo.h>
25 #ifdef HAVE_BALOO
26 #include <Baloo/Query>
27 #endif
28
29 namespace {
30 #ifdef HAVE_BALOO
31 /** Checks if a given term in the Baloo::Query::searchString() is a special search term
32 * @return: the specific search token of the term, or an empty QString() if none is found
33 */
34 QString searchTermToken(const QString& term)
35 {
36 static const QLatin1String searchTokens[] {
37 QLatin1String("filename:"),
38 QLatin1String("modified>="),
39 QLatin1String("rating>="),
40 QLatin1String("tag:"), QLatin1String("tag=")
41 };
42
43 for (const auto &searchToken : searchTokens) {
44 if (term.startsWith(searchToken)) {
45 return searchToken;
46 }
47 }
48 return QString();
49 }
50
51 QString stripQuotes(const QString& text)
52 {
53 if (text.length() >= 2 && text.at(0) == QLatin1Char('"')
54 && text.back() == QLatin1Char('"')) {
55 return text.mid(1, text.size() - 2);
56 }
57 return text;
58 }
59
60 QStringList splitOutsideQuotes(const QString& text)
61 {
62 // Match groups on 3 possible conditions:
63 // - Groups with two leading quotes must close both on them (filename:""abc xyz" tuv")
64 // - Groups enclosed in quotes
65 // - Words separated by spaces
66 const QRegularExpression subTermsRegExp("(\\S*?\"\"[^\"]+\"[^\"]+\"+|\\S*?\"[^\"]+\"+|(?<=\\s|^)\\S+(?=\\s|$))");
67 auto subTermsMatchIterator = subTermsRegExp.globalMatch(text);
68
69 QStringList textParts;
70 while (subTermsMatchIterator.hasNext()) {
71 textParts << subTermsMatchIterator.next().captured(0);
72 }
73 return textParts;
74 }
75 #endif
76
77 QString trimChar(const QString& text, const QLatin1Char aChar)
78 {
79 const int start = text.startsWith(aChar) ? 1 : 0;
80 const int end = (text.length() > 1 && text.endsWith(aChar)) ? 1 : 0;
81
82 return text.mid(start, text.length() - start - end);
83 }
84 }
85
86
87 DolphinQuery DolphinQuery::fromSearchUrl(const QUrl& searchUrl)
88 {
89 DolphinQuery model;
90 model.m_searchUrl = searchUrl;
91
92 if (searchUrl.scheme() == QLatin1String("baloosearch")) {
93 model.parseBalooQuery();
94 } else if (searchUrl.scheme() == QLatin1String("tags")) {
95 // tags can contain # symbols or slashes within the Url
96 QString tag = trimChar(searchUrl.toString(QUrl::RemoveScheme), QLatin1Char('/'));
97 model.m_searchTerms << QStringLiteral("tag:%1").arg(tag);
98 }
99
100 return model;
101 }
102
103 bool DolphinQuery::supportsScheme(const QString& urlScheme)
104 {
105 static const QStringList supportedSchemes = {
106 QStringLiteral("baloosearch"),
107 QStringLiteral("tags"),
108 };
109
110 return supportedSchemes.contains(urlScheme);
111 }
112
113 void DolphinQuery::parseBalooQuery()
114 {
115 #ifdef HAVE_BALOO
116 const Baloo::Query query = Baloo::Query::fromSearchUrl(m_searchUrl);
117
118 m_includeFolder = query.includeFolder();
119
120 const QStringList types = query.types();
121 m_fileType = types.isEmpty() ? QString() : types.first();
122
123 QStringList textParts;
124 QString fileName;
125
126 const QStringList subTerms = splitOutsideQuotes(query.searchString());
127 foreach (const QString& subTerm, subTerms) {
128 const QString token = searchTermToken(subTerm);
129 const QString value = stripQuotes(subTerm.mid(token.length()));
130
131 if (token == QLatin1String("filename:")) {
132 if (!value.isEmpty()) {
133 fileName = value;
134 m_hasFileName = true;
135 }
136 continue;
137 } else if (!token.isEmpty()) {
138 m_searchTerms << token + value;
139 continue;
140 } else if (subTerm == QLatin1String("AND") && subTerm != subTerms.at(0) && subTerm != subTerms.back()) {
141 continue;
142 } else if (!value.isEmpty()) {
143 textParts << value;
144 m_hasContentSearch = true;
145 }
146 }
147
148 if (m_hasFileName) {
149 if (m_hasContentSearch) {
150 textParts << QStringLiteral("filename:\"%1\"").arg(fileName);
151 } else {
152 textParts << fileName;
153 }
154 }
155
156 m_searchText = textParts.join(QLatin1Char(' '));
157 #endif
158 }
159
160
161 QUrl DolphinQuery::searchUrl() const
162 {
163 return m_searchUrl;
164 }
165
166 QString DolphinQuery::text() const
167 {
168 return m_searchText;
169 }
170
171 QString DolphinQuery::type() const
172 {
173 return m_fileType;
174 }
175
176 QStringList DolphinQuery::searchTerms() const
177 {
178 return m_searchTerms;
179 }
180
181 QString DolphinQuery::includeFolder() const
182 {
183 return m_includeFolder;
184 }
185
186 bool DolphinQuery::hasContentSearch() const
187 {
188 return m_hasContentSearch;
189 }
190
191 bool DolphinQuery::hasFileName() const
192 {
193 return m_hasFileName;
194 }