/* Copyright (c) 2014 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "searchquery.h" #include #include #include #include using namespace Akonadi; class SearchTerm::Private : public QSharedData { public: Private() : QSharedData() , condition(SearchTerm::CondEqual) , relation(SearchTerm::RelAnd) , isNegated(false) { } Private(const Private &other) : QSharedData(other) , key(other.key) , value(other.value) , condition(other.condition) , relation(other.relation) , terms(other.terms) , isNegated(other.isNegated) { } bool operator==(const Private &other) const { return relation == other.relation && isNegated == other.isNegated && terms == other.terms && key == other.key && value == other.value && condition == other.condition; } QString key; QVariant value; Condition condition; Relation relation; QList terms; bool isNegated; }; class SearchQuery::Private : public QSharedData { public: Private() : QSharedData() , limit(-1) { } Private(const Private &other) : QSharedData(other) , rootTerm(other.rootTerm) , limit(other.limit) { } bool operator==(const Private &other) const { return rootTerm == other.rootTerm && limit == other.limit; } static QVariantMap termToJSON(const SearchTerm &term) { const QList &subTerms = term.subTerms(); QVariantMap termJSON; termJSON.insert(QLatin1String("negated"), term.isNegated()); if (subTerms.isEmpty()) { termJSON.insert(QLatin1String("key"), term.key()); termJSON.insert(QLatin1String("value"), term.value()); termJSON.insert(QLatin1String("cond"), static_cast(term.condition())); } else { termJSON.insert(QLatin1String("rel"), static_cast(term.relation())); QVariantList subTermsJSON; Q_FOREACH (const SearchTerm &term, subTerms) { subTermsJSON.append(termToJSON(term)); } termJSON.insert(QLatin1String("subTerms"), subTermsJSON); } return termJSON; } static SearchTerm JSONToTerm(const QVariantMap &json) { if (json.contains(QLatin1String("key"))) { SearchTerm term(json[QLatin1String("key")].toString(), json[QLatin1String("value")], static_cast(json[QLatin1String("cond")].toInt())); term.setIsNegated(json[QLatin1String("negated")].toBool()); return term; } else if (json.contains(QLatin1String("rel"))) { SearchTerm term(static_cast(json[QLatin1String("rel")].toInt())); term.setIsNegated(json[QLatin1String("negated")].toBool()); const QVariantList subTermsJSON = json[QLatin1String("subTerms")].toList(); Q_FOREACH (const QVariant &subTermJSON, subTermsJSON) { term.addSubTerm(JSONToTerm(subTermJSON.toMap())); } return term; } else { kWarning() << "Invalid JSON for term: " << json; return SearchTerm(); } } SearchTerm rootTerm; int limit; }; SearchTerm::SearchTerm(SearchTerm::Relation relation) : d(new Private) { d->relation = relation; } SearchTerm::SearchTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition) : d(new Private) { d->relation = RelAnd; d->key = key; d->value = value; d->condition = condition; } SearchTerm::SearchTerm(const SearchTerm &other) : d(other.d) { } SearchTerm::~SearchTerm() { } SearchTerm &SearchTerm::operator=(const SearchTerm &other) { d = other.d; return *this; } bool SearchTerm::operator==(const SearchTerm &other) const { return *d == *other.d; } bool SearchTerm::isNull() const { return d->key.isEmpty() && d->value.isNull() && d->terms.isEmpty(); } QString SearchTerm::key() const { return d->key; } QVariant SearchTerm::value() const { return d->value; } SearchTerm::Condition SearchTerm::condition() const { return d->condition; } void SearchTerm::setIsNegated(bool negated) { d->isNegated = negated; } bool SearchTerm::isNegated() const { return d->isNegated; } void SearchTerm::addSubTerm(const SearchTerm &term) { d->terms << term; } QList< SearchTerm > SearchTerm::subTerms() const { return d->terms; } SearchTerm::Relation SearchTerm::relation() const { return d->relation; } SearchQuery::SearchQuery(SearchTerm::Relation rel) : d(new Private) { d->rootTerm = SearchTerm(rel); } SearchQuery::SearchQuery(const SearchQuery &other) : d(other.d) { } SearchQuery::~SearchQuery() { } SearchQuery &SearchQuery::operator=(const SearchQuery &other) { d = other.d; return *this; } bool SearchQuery::operator==(const SearchQuery &other) const { return *d == *other.d; } bool SearchQuery::isNull() const { return d->rootTerm.isNull(); } SearchTerm SearchQuery::term() const { return d->rootTerm; } void SearchQuery::addTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition) { addTerm(SearchTerm(key, value, condition)); } void SearchQuery::addTerm(const SearchTerm &term) { d->rootTerm.addSubTerm(term); } void SearchQuery::setTerm(const SearchTerm &term) { d->rootTerm = term; } void SearchQuery::setLimit(int limit) { d->limit = limit; } int SearchQuery::limit() const { return d->limit; } QByteArray SearchQuery::toJSON() const { QVariantMap root = Private::termToJSON(d->rootTerm); root.insert(QLatin1String("limit"), d->limit); QJson::Serializer serializer; return serializer.serialize(root); } SearchQuery SearchQuery::fromJSON(const QByteArray &jsonData) { QJson::Parser parser; bool ok = false; const QVariant json = parser.parse(jsonData, &ok); if (!ok || json.isNull()) { return SearchQuery(); } const QVariantMap map = json.toMap(); SearchQuery query; query.d->rootTerm = Private::JSONToTerm(map); if (map.contains(QLatin1String("limit"))) { query.d->limit = map.value(QLatin1String("limit")).toInt(); } return query; } QMap initializeMapping() { QMap mapping; mapping.insert(EmailSearchTerm::Body, QLatin1String("body")); mapping.insert(EmailSearchTerm::Headers, QLatin1String("headers")); mapping.insert(EmailSearchTerm::Subject, QLatin1String("subject")); mapping.insert(EmailSearchTerm::Message, QLatin1String("message")); mapping.insert(EmailSearchTerm::HeaderFrom, QLatin1String("from")); mapping.insert(EmailSearchTerm::HeaderTo, QLatin1String("to")); mapping.insert(EmailSearchTerm::HeaderCC, QLatin1String("cc")); mapping.insert(EmailSearchTerm::HeaderBCC, QLatin1String("bcc")); mapping.insert(EmailSearchTerm::HeaderReplyTo, QLatin1String("replyto")); mapping.insert(EmailSearchTerm::HeaderOrganization, QLatin1String("organization")); mapping.insert(EmailSearchTerm::HeaderListId, QLatin1String("listid")); mapping.insert(EmailSearchTerm::HeaderResentFrom, QLatin1String("resentfrom")); mapping.insert(EmailSearchTerm::HeaderXLoop, QLatin1String("xloop")); mapping.insert(EmailSearchTerm::HeaderXMailingList, QLatin1String("xmailinglist")); mapping.insert(EmailSearchTerm::HeaderXSpamFlag, QLatin1String("xspamflag")); mapping.insert(EmailSearchTerm::HeaderDate, QLatin1String("date")); mapping.insert(EmailSearchTerm::HeaderOnlyDate, QLatin1String("onlydate")); mapping.insert(EmailSearchTerm::MessageStatus, QLatin1String("messagestatus")); mapping.insert(EmailSearchTerm::MessageTag, QLatin1String("messagetag")); mapping.insert(EmailSearchTerm::ByteSize, QLatin1String("size")); mapping.insert(EmailSearchTerm::Attachment, QLatin1String("attachment")); return mapping; } static QMap emailSearchFieldMapping = initializeMapping(); EmailSearchTerm::EmailSearchTerm(EmailSearchTerm::EmailSearchField field, const QVariant &value, SearchTerm::Condition condition) : SearchTerm(toKey(field), value, condition) { } QString EmailSearchTerm::toKey(EmailSearchTerm::EmailSearchField field) { return emailSearchFieldMapping.value(field); } EmailSearchTerm::EmailSearchField EmailSearchTerm::fromKey(const QString &key) { return emailSearchFieldMapping.key(key); } QMap initializeContactMapping() { QMap mapping; mapping.insert(ContactSearchTerm::Name, QLatin1String("name")); mapping.insert(ContactSearchTerm::Nickname, QLatin1String("nickname")); mapping.insert(ContactSearchTerm::Email, QLatin1String("email")); mapping.insert(ContactSearchTerm::Uid, QLatin1String("uid")); mapping.insert(ContactSearchTerm::All, QLatin1String("all")); return mapping; } static QMap contactSearchFieldMapping = initializeContactMapping(); ContactSearchTerm::ContactSearchTerm(ContactSearchTerm::ContactSearchField field, const QVariant &value, SearchTerm::Condition condition) : SearchTerm(toKey(field), value, condition) { } QString ContactSearchTerm::toKey(ContactSearchTerm::ContactSearchField field) { return contactSearchFieldMapping.value(field); } ContactSearchTerm::ContactSearchField ContactSearchTerm::fromKey(const QString &key) { return contactSearchFieldMapping.key(key); }