Akonadi

searchquery.cpp
1 /*
2  Copyright (c) 2014 Daniel Vrátil <[email protected]>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "searchquery.h"
21 #include "akonadicore_debug.h"
22 
23 #include <QVariant>
24 #include <QJsonDocument>
25 #include <QJsonObject>
26 
27 using namespace Akonadi;
28 
29 class SearchTerm::Private : public QSharedData
30 {
31 public:
32  Private()
33  : QSharedData()
34  , condition(SearchTerm::CondEqual)
35  , relation(SearchTerm::RelAnd)
36  {
37  }
38 
39  Private(const Private &other)
40  : QSharedData(other)
41  , key(other.key)
42  , value(other.value)
43  , condition(other.condition)
44  , relation(other.relation)
45  , terms(other.terms)
46  , isNegated(other.isNegated)
47  {
48  }
49 
50  bool operator==(const Private &other) const
51  {
52  return relation == other.relation
53  && isNegated == other.isNegated
54  && terms == other.terms
55  && key == other.key
56  && value == other.value
57  && condition == other.condition;
58  }
59 
60  QString key;
62  Condition condition;
64  QList<SearchTerm> terms;
65  bool isNegated = false;
66 };
67 
68 class SearchQuery::Private : public QSharedData
69 {
70 public:
71  Private()
72  : QSharedData()
73  , limit(-1)
74  {
75  }
76 
77  Private(const Private &other)
78  : QSharedData(other)
79  , rootTerm(other.rootTerm)
80  , limit(other.limit)
81  {
82  }
83 
84  bool operator==(const Private &other) const
85  {
86  return rootTerm == other.rootTerm && limit == other.limit;
87  }
88 
89  static QVariantMap termToJSON(const SearchTerm &term)
90  {
91  const QList<SearchTerm> &subTerms = term.subTerms();
92  QVariantMap termJSON;
93  termJSON.insert(QStringLiteral("negated"), term.isNegated());
94  if (subTerms.isEmpty()) {
95  if (!term.isNull()) {
96  termJSON.insert(QStringLiteral("key"), term.key());
97  termJSON.insert(QStringLiteral("value"), term.value());
98  termJSON.insert(QStringLiteral("cond"), static_cast<int>(term.condition()));
99  }
100  } else {
101  termJSON.insert(QStringLiteral("rel"), static_cast<int>(term.relation()));
102  QVariantList subTermsJSON;
103  subTermsJSON.reserve(subTerms.count());
104  for (const SearchTerm &term : qAsConst(subTerms)) {
105  subTermsJSON.append(termToJSON(term));
106  }
107  termJSON.insert(QStringLiteral("subTerms"), subTermsJSON);
108  }
109 
110  return termJSON;
111  }
112 
113  static SearchTerm JSONToTerm(const QVariantMap &map)
114  {
115  if (map.isEmpty()) {
116  return SearchTerm();
117  } else if (map.contains(QStringLiteral("key"))) {
118  SearchTerm term(map[QStringLiteral("key")].toString(),
119  map[QStringLiteral("value")],
120  static_cast<SearchTerm::Condition>(map[QStringLiteral("cond")].toInt()));
121  term.setIsNegated(map[QStringLiteral("negated")].toBool());
122  return term;
123  } else if (map.contains(QStringLiteral("rel"))) {
124  SearchTerm term(static_cast<SearchTerm::Relation>(map[QStringLiteral("rel")].toInt()));
125  term.setIsNegated(map[QStringLiteral("negated")].toBool());
126  const QList<QVariant> list = map[QStringLiteral("subTerms")].toList();
127  for (const QVariant &var : list) {
128  term.addSubTerm(JSONToTerm(var.toMap()));
129  }
130  return term;
131  } else {
132  qCWarning(AKONADICORE_LOG) << "Invalid JSON for term: " << map;
133  return SearchTerm();
134  }
135  }
136 
137  SearchTerm rootTerm;
138  int limit;
139 };
140 
141 SearchTerm::SearchTerm(SearchTerm::Relation relation)
142  : d(new Private)
143 {
144  d->relation = relation;
145 }
146 
147 SearchTerm::SearchTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition)
148  : d(new Private)
149 {
150  d->relation = RelAnd;
151  d->key = key;
152  d->value = value;
153  d->condition = condition;
154 }
155 
157  : d(other.d)
158 {
159 }
160 
161 SearchTerm::~SearchTerm()
162 {
163 }
164 
165 SearchTerm &SearchTerm::operator=(const SearchTerm &other)
166 {
167  d = other.d;
168  return *this;
169 }
170 
171 bool SearchTerm::operator==(const SearchTerm &other) const
172 {
173  return *d == *other.d;
174 }
175 
176 bool SearchTerm::isNull() const
177 {
178  return d->key.isEmpty() && d->value.isNull() && d->terms.isEmpty();
179 }
180 
182 {
183  return d->key;
184 }
185 
187 {
188  return d->value;
189 }
190 
191 SearchTerm::Condition SearchTerm::condition() const
192 {
193  return d->condition;
194 }
195 
196 void SearchTerm::setIsNegated(bool negated)
197 {
198  d->isNegated = negated;
199 }
200 
202 {
203  return d->isNegated;
204 }
205 
207 {
208  d->terms << term;
209 }
210 
212 {
213  return d->terms;
214 }
215 
216 SearchTerm::Relation SearchTerm::relation() const
217 {
218  return d->relation;
219 }
220 
221 SearchQuery::SearchQuery(SearchTerm::Relation rel)
222  : d(new Private)
223 {
224  d->rootTerm = SearchTerm(rel);
225 }
226 
228  : d(other.d)
229 {
230 }
231 
232 SearchQuery::~SearchQuery()
233 {
234 }
235 
236 SearchQuery &SearchQuery::operator=(const SearchQuery &other)
237 {
238  d = other.d;
239  return *this;
240 }
241 
242 bool SearchQuery::operator==(const SearchQuery &other) const
243 {
244  return *d == *other.d;
245 }
246 
247 bool SearchQuery::isNull() const
248 {
249  return d->rootTerm.isNull();
250 }
251 
253 {
254  return d->rootTerm;
255 }
256 
257 void SearchQuery::addTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition)
258 {
259  addTerm(SearchTerm(key, value, condition));
260 }
261 
263 {
264  d->rootTerm.addSubTerm(term);
265 }
266 
268 {
269  d->rootTerm = term;
270 }
271 
273 {
274  d->limit = limit;
275 }
276 
278 {
279  return d->limit;
280 }
281 
282 QByteArray SearchQuery::toJSON() const
283 {
284  QVariantMap root;
285  if (!d->rootTerm.isNull()) {
286  root = Private::termToJSON(d->rootTerm);
287  root.insert(QStringLiteral("limit"), d->limit);
288  }
289 
291  QJsonDocument jdoc;
292  jdoc.setObject(jo);
293  return jdoc.toJson();
294 }
295 
296 SearchQuery SearchQuery::fromJSON(const QByteArray &jsonData)
297 {
298  QJsonParseError error;
299  const QJsonDocument json = QJsonDocument::fromJson(jsonData, &error);
300  if (error.error != QJsonParseError::NoError || json.isNull()) {
301  return SearchQuery();
302  }
303 
304  SearchQuery query;
305  const QJsonObject obj = json.object();
306  query.d->rootTerm = Private::JSONToTerm(obj.toVariantMap());
307  if (obj.contains(QLatin1String("limit"))) {
308  query.d->limit = obj.value(QStringLiteral("limit")).toInt();
309  }
310  return query;
311 }
312 
313 static QMap<EmailSearchTerm::EmailSearchField, QString> emailSearchFieldMapping()
314 {
316  if (mapping.isEmpty()) {
317  mapping.insert(EmailSearchTerm::Body, QStringLiteral("body"));
318  mapping.insert(EmailSearchTerm::Headers, QStringLiteral("headers"));
319  mapping.insert(EmailSearchTerm::Subject, QStringLiteral("subject"));
320  mapping.insert(EmailSearchTerm::Message, QStringLiteral("message"));
321  mapping.insert(EmailSearchTerm::HeaderFrom, QStringLiteral("from"));
322  mapping.insert(EmailSearchTerm::HeaderTo, QStringLiteral("to"));
323  mapping.insert(EmailSearchTerm::HeaderCC, QStringLiteral("cc"));
324  mapping.insert(EmailSearchTerm::HeaderBCC, QStringLiteral("bcc"));
325  mapping.insert(EmailSearchTerm::HeaderReplyTo, QStringLiteral("replyto"));
326  mapping.insert(EmailSearchTerm::HeaderOrganization, QStringLiteral("organization"));
327  mapping.insert(EmailSearchTerm::HeaderListId, QStringLiteral("listid"));
328  mapping.insert(EmailSearchTerm::HeaderResentFrom, QStringLiteral("resentfrom"));
329  mapping.insert(EmailSearchTerm::HeaderXLoop, QStringLiteral("xloop"));
330  mapping.insert(EmailSearchTerm::HeaderXMailingList, QStringLiteral("xmailinglist"));
331  mapping.insert(EmailSearchTerm::HeaderXSpamFlag, QStringLiteral("xspamflag"));
332  mapping.insert(EmailSearchTerm::HeaderDate, QStringLiteral("date"));
333  mapping.insert(EmailSearchTerm::HeaderOnlyDate, QStringLiteral("onlydate"));
334  mapping.insert(EmailSearchTerm::MessageStatus, QStringLiteral("messagestatus"));
335  mapping.insert(EmailSearchTerm::MessageTag, QStringLiteral("messagetag"));
336  mapping.insert(EmailSearchTerm::ByteSize, QStringLiteral("size"));
337  mapping.insert(EmailSearchTerm::Attachment, QStringLiteral("attachment"));
338  }
339 
340  return mapping;
341 }
342 
343 EmailSearchTerm::EmailSearchTerm(EmailSearchTerm::EmailSearchField field, const QVariant &value, SearchTerm::Condition condition)
344  : SearchTerm(toKey(field), value, condition)
345 {
346 
347 }
348 
350 {
351  return emailSearchFieldMapping().value(field);
352 }
353 
355 {
356  return emailSearchFieldMapping().key(key);
357 }
358 
359 static QMap<ContactSearchTerm::ContactSearchField, QString> contactSearchFieldMapping()
360 {
362  if (mapping.isEmpty()) {
363  mapping.insert(ContactSearchTerm::Name, QStringLiteral("name"));
364  mapping.insert(ContactSearchTerm::Nickname, QStringLiteral("nickname"));
365  mapping.insert(ContactSearchTerm::Email, QStringLiteral("email"));
366  mapping.insert(ContactSearchTerm::Uid, QStringLiteral("uid"));
367  mapping.insert(ContactSearchTerm::All, QStringLiteral("all"));
368  }
369  return mapping;
370 }
371 
372 ContactSearchTerm::ContactSearchTerm(ContactSearchTerm::ContactSearchField field, const QVariant &value, SearchTerm::Condition condition)
373  : SearchTerm(toKey(field), value, condition)
374 {
375 
376 }
377 
378 QString ContactSearchTerm::toKey(ContactSearchTerm::ContactSearchField field)
379 {
380  return contactSearchFieldMapping().value(field);
381 }
382 
383 ContactSearchTerm::ContactSearchField ContactSearchTerm::fromKey(const QString &key)
384 {
385  return contactSearchFieldMapping().key(key);
386 }
387 
389 {
391  if (mapping.isEmpty()) {
392  mapping.insert(IncidenceSearchTerm::All, QStringLiteral("all"));
393  mapping.insert(IncidenceSearchTerm::PartStatus, QStringLiteral("partstatus"));
394  mapping.insert(IncidenceSearchTerm::Organizer, QStringLiteral("organizer"));
395  mapping.insert(IncidenceSearchTerm::Summary, QStringLiteral("summary"));
396  mapping.insert(IncidenceSearchTerm::Location, QStringLiteral("location"));
397  }
398  return mapping;
399 }
400 
401 IncidenceSearchTerm::IncidenceSearchTerm(IncidenceSearchTerm::IncidenceSearchField field, const QVariant &value, SearchTerm::Condition condition)
402  : SearchTerm(toKey(field), value, condition)
403 {
404 
405 }
406 
407 QString IncidenceSearchTerm::toKey(IncidenceSearchTerm::IncidenceSearchField field)
408 {
409  return incidenceSearchFieldMapping().value(field);
410 }
411 
412 IncidenceSearchTerm::IncidenceSearchField IncidenceSearchTerm::fromKey(const QString &key)
413 {
414  return incidenceSearchFieldMapping().key(key);
415 }
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
void setIsNegated(bool negated)
Sets whether the entire term is negated.
An Akonadi Relation.
Definition: relation.h:52
bool contains(const Key &key) const const
QByteArray toJson() const const
QJsonObject fromVariantMap(const QVariantMap &map)
QJsonObject object() const const
void setTerm(const SearchTerm &term)
Sets the root term.
QVariantMap toVariantMap() const const
T value() const const
bool isNegated() const
Returns whether the entire term is negated.
bool isNull() const const
void addSubTerm(const SearchTerm &term)
Adds a new subterm to this term.
EmailSearchTerm(EmailSearchField field, const QVariant &value, SearchTerm::Condition condition=SearchTerm::CondEqual)
Constructs an email end term.
static QString toKey(EmailSearchField)
Translates field to key.
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
static IncidenceSearchField fromKey(const QString &key)
Translates key to field.
int toInt(int defaultValue) const const
void addTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition=SearchTerm::CondEqual)
Adds a new term.
int count(const T &value) const const
SearchTerm::Condition condition() const
Returns relation between key and value.
QString key() const
Returns key of this end term.
bool isEmpty() const const
bool contains(const QString &key) const const
SearchTerm(SearchTerm::Relation relation=SearchTerm::RelAnd)
Constructs a term where all subterms will be in given relation.
static EmailSearchField fromKey(const QString &key)
Translates key to field.
static QString toKey(ContactSearchField)
Translates field to key.
A query that can be passed to ItemSearchJob or others.
Definition: searchquery.h:128
char * toString(const T &value)
SearchTerm term() const
Returns the root term.
Helper integration between Akonadi and Qt.
void setLimit(int limit)
Sets the maximum number of results.
QList< SearchTerm > subTerms() const
Returns all subterms, or an empty list if this is an end term.
void setObject(const QJsonObject &object)
QJsonValue value(const QString &key) const const
QMap::iterator insert(const Key &key, const T &value)
QVariant value() const
Returns value of this end term.
bool isEmpty() const const
SearchQuery(SearchTerm::Relation rel=SearchTerm::RelAnd)
Constructs query where all added terms will be in given relation.
Search term represents the actual condition within query.
Definition: searchquery.h:39
int limit() const
Returns the maximum number of results.
static ContactSearchField fromKey(const QString &key)
Translates key to field.
static QString toKey(IncidenceSearchField)
Translates field to key.
SearchTerm::Relation relation() const
Returns relation in which all subterms are.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
EmailSearchField
All fields expect a search string unless noted otherwise.
Definition: searchquery.h:201
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.