File indexing completed on 2025-01-05 03:54:00
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2008-01-09 0007 * Description : Core database searches XML queries manager 0008 * 0009 * SPDX-FileCopyrightText: 2008-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #ifndef DIGIKAM_CORE_DB_SEARCH_XML_H 0017 #define DIGIKAM_CORE_DB_SEARCH_XML_H 0018 0019 // Qt includes 0020 0021 #include <QString> 0022 #include <QDateTime> 0023 #include <QXmlStreamReader> 0024 #include <QXmlStreamWriter> 0025 #include <QStringList> 0026 #include <QVariant> 0027 0028 // Local includes 0029 0030 #include "digikam_export.h" 0031 0032 namespace Digikam 0033 { 0034 0035 namespace SearchXml 0036 { 0037 0038 enum Operator 0039 { 0040 And, 0041 Or, 0042 AndNot, 0043 OrNot 0044 }; 0045 0046 enum Element 0047 { 0048 Search, 0049 Group, 0050 GroupEnd, 0051 Field, 0052 FieldEnd, 0053 End 0054 }; 0055 0056 enum Relation 0057 { 0058 Equal, 0059 Unequal, 0060 Like, 0061 NotLike, 0062 LessThan, 0063 GreaterThan, 0064 LessThanOrEqual, 0065 GreaterThanOrEqual, 0066 Interval, // [a,b] 0067 IntervalOpen, // (a,b) 0068 OneOf, 0069 AllOf, 0070 InTree, 0071 NotInTree, 0072 Near, 0073 Inside 0074 }; 0075 0076 template <typename T> 0077 bool testRelation(T v1, T v2, Relation rel) 0078 { 0079 if (rel == Equal) 0080 { 0081 return v1 == v2; 0082 } 0083 else if (rel == Unequal) 0084 { 0085 return v1 != v2; 0086 } 0087 else if (rel == LessThan) 0088 { 0089 return v1 < v2; 0090 } 0091 else if (rel == LessThanOrEqual) 0092 { 0093 return v1 <= v2; 0094 } 0095 else if (rel == GreaterThan) 0096 { 0097 return v1 > v2; 0098 } 0099 else if (rel == GreaterThanOrEqual) 0100 { 0101 return v1 >= v2; 0102 } 0103 0104 return false; 0105 } 0106 0107 /** 0108 * General default values for groupOperator() and defaultFieldOperator() 0109 */ 0110 inline SearchXml::Operator standardGroupOperator() 0111 { 0112 return SearchXml::Or; 0113 } 0114 0115 inline SearchXml::Operator standardFieldOperator() 0116 { 0117 return SearchXml::And; 0118 } 0119 0120 inline SearchXml::Relation standardFieldRelation() 0121 { 0122 return SearchXml::Equal; 0123 } 0124 0125 } // namespace SearchXml 0126 0127 // --------------------------------------------------------------------------------- 0128 0129 class DIGIKAM_DATABASE_EXPORT SearchXmlReader : public QXmlStreamReader 0130 { 0131 public: 0132 0133 explicit SearchXmlReader(const QString& xml); 0134 0135 /** Continue parsing the document. Returns the type of the current element. 0136 */ 0137 SearchXml::Element readNext(); 0138 0139 /** Returns if the current element is a group element (start or end element). 0140 */ 0141 bool isGroupElement() const; 0142 0143 /** Returns if the current element is a field element (start or end element). 0144 */ 0145 bool isFieldElement() const; 0146 0147 /** Returns the group operator. Only valid if the current element is a group. 0148 */ 0149 SearchXml::Operator groupOperator() const; 0150 0151 /** Returns the (optional) group caption. Only valid if the current element is a group. 0152 */ 0153 QString groupCaption() const; 0154 0155 /** Returns the default field operator. This operator can be overridden by a specific fieldOperator(). 0156 */ 0157 SearchXml::Operator defaultFieldOperator() const; 0158 0159 /** Returns the field attributes. Only valid if the current element is a field. 0160 * fieldOperator returns the default operator if the field has not specified any. 0161 */ 0162 SearchXml::Operator fieldOperator() const; 0163 QString fieldName() const; 0164 SearchXml::Relation fieldRelation() const; 0165 0166 /** Returns the field values. Only valid if the current element is a field. 0167 * This reads to the end element of the field, and converts the found 0168 * text/elements to the desired output. 0169 */ 0170 QString value(); 0171 int valueToInt(); 0172 qlonglong valueToLongLong(); 0173 double valueToDouble(); 0174 QDateTime valueToDateTime(); 0175 QList<int> valueToIntList(); 0176 QList<qlonglong> valueToLongLongList(); 0177 QList<double> valueToDoubleList(); 0178 QStringList valueToStringList(); 0179 QList<QDateTime> valueToDateTimeList(); 0180 0181 QList<int> valueToIntOrIntList(); 0182 QList<double> valueToDoubleOrDoubleList(); 0183 QList<QString> valueToStringOrStringList(); 0184 0185 /** General helper method: Reads XML a start element with the given 0186 * name is found. The method goes to the next start element, and from 0187 * there down the hierarchy, but not further up in the hierarchy. 0188 * Returns false if the element is not found. 0189 */ 0190 bool readToStartOfElement(const QString& name); 0191 0192 /** General helper method: Reads XML until the end element of the current 0193 start element in reached. 0194 */ 0195 void readToEndOfElement(); 0196 0197 /** General helper method: Reads XML until the first field 0198 * of the next or first found group is reached. 0199 */ 0200 void readToFirstField(); 0201 0202 protected: 0203 0204 SearchXml::Operator readOperator(const QString&, SearchXml::Operator) const; 0205 SearchXml::Relation readRelation(const QString&, SearchXml::Relation) const; 0206 0207 protected: 0208 0209 SearchXml::Operator m_defaultFieldOperator; 0210 }; 0211 0212 // --------------------------------------------------------------------------------- 0213 0214 class DIGIKAM_DATABASE_EXPORT SearchXmlWriter : public QXmlStreamWriter 0215 { 0216 public: 0217 0218 /** 0219 * Note that SearchXmlWriter and SearchXmlGroupWriter rely on you 0220 * calling the methods following the restrictions set by the documentation; 0221 * Otherwise you will not produce the desired output. 0222 */ 0223 explicit SearchXmlWriter(); 0224 0225 /** Adds a group. Use the returned group writer to add fields. 0226 */ 0227 void writeGroup(); 0228 0229 /** Sets the operator applied to the group as a whole "OR (field1 ... fieldn)". 0230 * Default value is OR. 0231 */ 0232 void setGroupOperator(SearchXml::Operator op); 0233 0234 /** Sets an optional caption. 0235 */ 0236 void setGroupCaption(const QString& caption); 0237 0238 /** Sets the default operator for fields in this group "(field1 AND field2 AND ... fieldn)". 0239 * The default operator can in each field be overridden. Default value is AND. 0240 */ 0241 void setDefaultFieldOperator(SearchXml::Operator op); 0242 0243 /** Adds a new field with the given name (entity) and relation, "Rating less than ...". 0244 * Ensure that you closed the previous field with finishField(). 0245 * For a reference of valid field names, look into ItemQueryBuilder. 0246 * The general rule is that names are like the database fields, but all lower-case. 0247 */ 0248 void writeField(const QString& name, SearchXml::Relation relation); 0249 0250 /** Adds an optional operator overriding the default field operator of the group. 0251 */ 0252 void setFieldOperator(SearchXml::Operator op); 0253 0254 /** Adds the value, "4" in the case of "Rating less than 4". 0255 */ 0256 void writeValue(const QString& value); 0257 void writeValue(int value); 0258 void writeValue(qlonglong value); 0259 void writeValue(float value, int precision = 6); 0260 void writeValue(double value, int precision = 8); 0261 void writeValue(const QDateTime& dateTime); 0262 void writeValue(const QList<int>& valueList); 0263 void writeValue(const QList<qlonglong>& valueList); 0264 void writeValue(const QList<float>& valueList, int precision = 6); 0265 void writeValue(const QList<double>& valueList, int precision = 8); 0266 void writeValue(const QStringList& valueList); 0267 void writeValue(const QList<QDateTime>& valueList); 0268 0269 /** Finish writing the current field. 0270 * You shall call this method before adding another field, or closing the group. 0271 */ 0272 void finishField(); 0273 0274 /** Finish the current group. 0275 * You cannot add anymore fields after calling this. 0276 * Note that you will want to call this before 0277 * writing another group if you want the group on the same level. 0278 * You can as well add nested groups and call this to close the group afterwards. 0279 */ 0280 void finishGroup(); 0281 0282 /** 0283 * Finish the XML. No further group can be added after calling this. 0284 * You need to call this before you can get the resulting XML from xml(). 0285 */ 0286 void finish(); 0287 0288 /** Get the created XML. The value is only valid if finish() has been called. 0289 */ 0290 QString xml() const; 0291 0292 /** Returns ready-made XML for a query of type "keyword" with the specified 0293 * text as keyword. 0294 */ 0295 static QString keywordSearch(const QString& keyword); 0296 0297 protected: 0298 0299 void writeOperator(const QString&, SearchXml::Operator); 0300 void writeRelation(const QString&, SearchXml::Relation); 0301 0302 protected: 0303 0304 QString m_xml; 0305 }; 0306 0307 // --------------------------------------------------------------------------------- 0308 0309 namespace KeywordSearch 0310 { 0311 0312 /** Splits a given string to a list of keywords. 0313 * Splits at whitespace, but recognizes quotation marks 0314 * to group words in a single keyword. 0315 */ 0316 DIGIKAM_DATABASE_EXPORT QStringList split(const QString& string); 0317 0318 /** Reverse of split(). 0319 * From a list of keywords, gives a single string for a text entry field. 0320 */ 0321 DIGIKAM_DATABASE_EXPORT QString merge(const QStringList& keywordList); 0322 0323 /** Assuming previousContent is a string 0324 * as accepted by split and returned by merge, 0325 * adds newEntry as another (single) keyword to the string, 0326 * returning the combined result. 0327 */ 0328 DIGIKAM_DATABASE_EXPORT QString merge(const QString& previousContent, const QString& newEntry); 0329 0330 } // namespace KeywordSearch 0331 0332 // --------------------------------------------------------------------------------- 0333 0334 class DIGIKAM_DATABASE_EXPORT KeywordSearchReader : public SearchXmlReader 0335 { 0336 public: 0337 0338 explicit KeywordSearchReader(const QString& xml); 0339 0340 /// Returns the keywords from this search, merged in a list. 0341 QStringList keywords(); 0342 0343 /// Checks if the XML is a simple keyword search, compatible with keywords(). 0344 bool isSimpleKeywordSearch(); 0345 0346 private: 0347 0348 void readGroup(QStringList& list); 0349 bool isSimpleKeywordSearchGroup(); 0350 QString readField(); 0351 }; 0352 0353 // --------------------------------------------------------------------------------- 0354 0355 class DIGIKAM_DATABASE_EXPORT KeywordSearchWriter : public SearchXmlWriter 0356 { 0357 public: 0358 0359 explicit KeywordSearchWriter(); 0360 0361 QString xml(const QStringList& keywordList); 0362 }; 0363 0364 // --------------------------------------------------------------------------------- 0365 0366 class DIGIKAM_DATABASE_EXPORT SearchXmlCachingReader : public SearchXmlReader 0367 { 0368 public: 0369 0370 /** This class has the same semantics as SearchXmlReader, 0371 * but performs some caching and is thus much more relaxed than SearchXmlReader 0372 * about the calling order of methods: 0373 * With this class, you can access properties of a group until the next group 0374 * is read, access properties and the value of a field until the next field is read, 0375 * with all calls possible multiple times. 0376 */ 0377 explicit SearchXmlCachingReader(const QString& xml); 0378 0379 SearchXml::Element readNext(); 0380 0381 SearchXml::Operator groupOperator() const; 0382 QString groupCaption() const; 0383 0384 SearchXml::Operator fieldOperator() const; 0385 QString fieldName() const; 0386 SearchXml::Relation fieldRelation() const; 0387 QString value(); 0388 int valueToInt(); 0389 qlonglong valueToLongLong(); 0390 double valueToDouble(); 0391 QDateTime valueToDateTime(); 0392 QList<int> valueToIntList(); 0393 QList<qlonglong> valueToLongLongList(); 0394 QList<double> valueToDoubleList(); 0395 QStringList valueToStringList(); 0396 QList<QDateTime> valueToDateTimeList(); 0397 QList<int> valueToIntOrIntList(); 0398 QList<double> valueToDoubleOrDoubleList(); 0399 QList<QString> valueToStringOrStringList(); 0400 0401 protected: 0402 0403 SearchXml::Operator m_groupOperator; 0404 QString m_groupCaption; 0405 SearchXml::Operator m_fieldOperator; 0406 QString m_fieldName; 0407 SearchXml::Relation m_fieldRelation; 0408 QVariant m_value; 0409 bool m_readValue; 0410 }; 0411 0412 } // namespace Digikam 0413 0414 #endif // DIGIKAM_CORE_DB_SEARCH_XML_H