File indexing completed on 2025-01-05 03:53:59
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 #include "coredbsearchxml.h" 0017 0018 #include <QRegularExpression> 0019 0020 // Local includes 0021 0022 #include "digikam_globals.h" 0023 0024 namespace Digikam 0025 { 0026 0027 SearchXmlReader::SearchXmlReader(const QString& xml) 0028 : QXmlStreamReader(xml) 0029 { 0030 m_defaultFieldOperator = SearchXml::And; 0031 0032 // read in root element "search" 0033 readNext(); 0034 } 0035 0036 SearchXml::Element SearchXmlReader::readNext() 0037 { 0038 while (!atEnd()) 0039 { 0040 QXmlStreamReader::readNext(); 0041 0042 if (isEndElement()) 0043 { 0044 if (isGroupElement()) 0045 { 0046 return SearchXml::GroupEnd; 0047 } 0048 else if (isFieldElement()) 0049 { 0050 return SearchXml::FieldEnd; 0051 } 0052 } 0053 0054 if (isStartElement()) 0055 { 0056 if (isGroupElement()) 0057 { 0058 // get possible default operator 0059 m_defaultFieldOperator = readOperator(QLatin1String("fieldoperator"), SearchXml::standardFieldOperator()); 0060 return SearchXml::Group; 0061 } 0062 else if (isFieldElement()) 0063 { 0064 return SearchXml::Field; 0065 } 0066 else if (name() == QLatin1String("search")) 0067 { 0068 // root element 0069 return SearchXml::Search; 0070 } 0071 } 0072 } 0073 0074 return SearchXml::End; 0075 } 0076 0077 // --------------------------------------------------------------------------------- 0078 0079 bool SearchXmlReader::isGroupElement() const 0080 { 0081 return (name() == QLatin1String("group")); 0082 } 0083 0084 bool SearchXmlReader::isFieldElement() const 0085 { 0086 return (name() == QLatin1String("field")); 0087 } 0088 0089 SearchXml::Operator SearchXmlReader::groupOperator() const 0090 { 0091 return readOperator(QLatin1String("operator"), SearchXml::standardGroupOperator()); 0092 } 0093 0094 QString SearchXmlReader::groupCaption() const 0095 { 0096 return attributes().value(QLatin1String("caption")).toString(); 0097 } 0098 0099 SearchXml::Operator SearchXmlReader::defaultFieldOperator() const 0100 { 0101 return m_defaultFieldOperator; 0102 } 0103 0104 SearchXml::Operator SearchXmlReader::fieldOperator() const 0105 { 0106 return readOperator(QLatin1String("operator"), m_defaultFieldOperator); 0107 } 0108 0109 QString SearchXmlReader::fieldName() const 0110 { 0111 return attributes().value(QLatin1String("name")).toString(); 0112 } 0113 0114 SearchXml::Relation SearchXmlReader::fieldRelation() const 0115 { 0116 return readRelation(QLatin1String("relation"), SearchXml::standardFieldRelation()); 0117 } 0118 0119 QString SearchXmlReader::value() 0120 { 0121 return readElementText(); 0122 } 0123 0124 int SearchXmlReader::valueToInt() 0125 { 0126 return readElementText().toInt(); 0127 } 0128 0129 qlonglong SearchXmlReader::valueToLongLong() 0130 { 0131 return readElementText().toLongLong(); 0132 } 0133 0134 double SearchXmlReader::valueToDouble() 0135 { 0136 return readElementText().toDouble(); 0137 } 0138 0139 QDateTime SearchXmlReader::valueToDateTime() 0140 { 0141 return QDateTime::fromString(readElementText(), Qt::ISODate); 0142 } 0143 0144 QList<int> SearchXmlReader::valueToIntList() 0145 { 0146 QList<int> list; 0147 0148 while (!atEnd()) 0149 { 0150 QXmlStreamReader::readNext(); 0151 0152 if (name() != QLatin1String("listitem")) 0153 { 0154 break; 0155 } 0156 0157 if (isStartElement()) 0158 { 0159 list << readElementText().toInt(); 0160 } 0161 } 0162 0163 return list; 0164 } 0165 0166 QList<qlonglong> SearchXmlReader::valueToLongLongList() 0167 { 0168 QList<qlonglong> list; 0169 0170 while (!atEnd()) 0171 { 0172 QXmlStreamReader::readNext(); 0173 0174 if (name() != QLatin1String("listitem")) 0175 { 0176 break; 0177 } 0178 0179 if (isStartElement()) 0180 { 0181 list << readElementText().toLongLong(); 0182 } 0183 } 0184 0185 return list; 0186 } 0187 0188 QList<double> SearchXmlReader::valueToDoubleList() 0189 { 0190 QList<double> list; 0191 0192 while (!atEnd()) 0193 { 0194 QXmlStreamReader::readNext(); 0195 0196 if (name() != QLatin1String("listitem")) 0197 { 0198 break; 0199 } 0200 0201 if (isStartElement()) 0202 { 0203 list << readElementText().toDouble(); 0204 } 0205 } 0206 0207 return list; 0208 } 0209 0210 QStringList SearchXmlReader::valueToStringList() 0211 { 0212 QStringList list; 0213 0214 while (!atEnd()) 0215 { 0216 QXmlStreamReader::readNext(); 0217 0218 if (name() != QLatin1String("listitem")) 0219 { 0220 break; 0221 } 0222 0223 if (isStartElement()) 0224 { 0225 list << readElementText(); 0226 } 0227 } 0228 0229 return list; 0230 } 0231 0232 QList<QDateTime> SearchXmlReader::valueToDateTimeList() 0233 { 0234 QList<QDateTime> list; 0235 0236 while (!atEnd()) 0237 { 0238 QXmlStreamReader::readNext(); 0239 0240 if (name() != QLatin1String("listitem")) 0241 { 0242 break; 0243 } 0244 0245 if (isStartElement()) 0246 { 0247 list << QDateTime::fromString(readElementText(), Qt::ISODate); 0248 } 0249 } 0250 0251 return list; 0252 } 0253 0254 QList<int> SearchXmlReader::valueToIntOrIntList() 0255 { 0256 QList<int> list; 0257 0258 // poke at next token 0259 QXmlStreamReader::TokenType token = QXmlStreamReader::readNext(); 0260 0261 // Found text? Treat text as with valueToInt(), return single element list 0262 if (token == QXmlStreamReader::Characters) 0263 { 0264 list << text().toString().toInt(); 0265 readNext(); 0266 0267 return list; 0268 } 0269 0270 // treat as with valueToIntList() 0271 while (!atEnd()) 0272 { 0273 if (token != QXmlStreamReader::StartElement || name() != QLatin1String("listitem")) 0274 { 0275 break; 0276 } 0277 0278 list << readElementText().toInt(); 0279 0280 token = QXmlStreamReader::readNext(); 0281 } 0282 0283 return list; 0284 } 0285 0286 QList<double> SearchXmlReader::valueToDoubleOrDoubleList() 0287 { 0288 QList<double> list; 0289 0290 // poke at next token 0291 QXmlStreamReader::TokenType token = QXmlStreamReader::readNext(); 0292 0293 // Found text? Treat text as with valueToInt(), return single element list 0294 if (token == QXmlStreamReader::Characters) 0295 { 0296 list << text().toString().toDouble(); 0297 readNext(); 0298 0299 return list; 0300 } 0301 0302 // treat as with valueToIntList() 0303 while (!atEnd()) 0304 { 0305 if (token != QXmlStreamReader::StartElement || name() != QLatin1String("listitem")) 0306 { 0307 break; 0308 } 0309 0310 list << readElementText().toDouble(); 0311 0312 token = QXmlStreamReader::readNext(); 0313 } 0314 0315 return list; 0316 } 0317 0318 QList<QString> SearchXmlReader::valueToStringOrStringList() 0319 { 0320 QList<QString> list; 0321 0322 // poke at next token 0323 QXmlStreamReader::TokenType token = QXmlStreamReader::readNext(); 0324 0325 // Found text? Treat text as with valueToString(), return single element list 0326 if (token == QXmlStreamReader::Characters) 0327 { 0328 list << text().toString(); 0329 readNext(); 0330 0331 return list; 0332 } 0333 0334 // treat as with valueToStringList() 0335 while (!atEnd()) 0336 { 0337 if (token != QXmlStreamReader::StartElement || name() != QLatin1String("listitem")) 0338 { 0339 break; 0340 } 0341 0342 list << readElementText(); 0343 0344 token = QXmlStreamReader::readNext(); 0345 } 0346 0347 return list; 0348 } 0349 0350 SearchXml::Operator SearchXmlReader::readOperator(const QString& attributeName, 0351 SearchXml::Operator defaultOperator) const 0352 { 0353 QStringView op = attributes().value(attributeName); 0354 0355 if (op == QLatin1String("and")) 0356 { 0357 return SearchXml::And; 0358 } 0359 else if (op == QLatin1String("or")) 0360 { 0361 return SearchXml::Or; 0362 } 0363 else if (op == QLatin1String("andnot")) 0364 { 0365 return SearchXml::AndNot; 0366 } 0367 else if (op == QLatin1String("ornot")) 0368 { 0369 return SearchXml::OrNot; 0370 } 0371 0372 return defaultOperator; 0373 } 0374 0375 SearchXml::Relation SearchXmlReader::readRelation(const QString& attributeName, 0376 SearchXml::Relation defaultRelation) const 0377 { 0378 QStringView relation = attributes().value(attributeName); 0379 0380 if (relation == QLatin1String("equal")) 0381 { 0382 return SearchXml::Equal; 0383 } 0384 0385 if (relation == QLatin1String("unequal")) 0386 { 0387 return SearchXml::Unequal; 0388 } 0389 else if (relation == QLatin1String("like")) 0390 { 0391 return SearchXml::Like; 0392 } 0393 else if (relation == QLatin1String("notlike")) 0394 { 0395 return SearchXml::NotLike; 0396 } 0397 else if (relation == QLatin1String("lessthan")) 0398 { 0399 return SearchXml::LessThan; 0400 } 0401 else if (relation == QLatin1String("greaterthan")) 0402 { 0403 return SearchXml::GreaterThan; 0404 } 0405 else if (relation == QLatin1String("lessthanequal")) 0406 { 0407 return SearchXml::LessThanOrEqual; 0408 } 0409 else if (relation == QLatin1String("greaterthanequal")) 0410 { 0411 return SearchXml::GreaterThanOrEqual; 0412 } 0413 else if (relation == QLatin1String("interval")) 0414 { 0415 return SearchXml::Interval; 0416 } 0417 else if (relation == QLatin1String("intervalopen")) 0418 { 0419 return SearchXml::IntervalOpen; 0420 } 0421 else if (relation == QLatin1String("oneof")) 0422 { 0423 return SearchXml::OneOf; 0424 } 0425 else if (relation == QLatin1String("allof")) 0426 { 0427 return SearchXml::AllOf; 0428 } 0429 else if (relation == QLatin1String("intree")) 0430 { 0431 return SearchXml::InTree; 0432 } 0433 else if (relation == QLatin1String("notintree")) 0434 { 0435 return SearchXml::NotInTree; 0436 } 0437 else if (relation == QLatin1String("near")) 0438 { 0439 return SearchXml::Near; 0440 } 0441 else if (relation == QLatin1String("inside")) 0442 { 0443 return SearchXml::Inside; 0444 } 0445 0446 return defaultRelation; 0447 } 0448 0449 bool SearchXmlReader::readToStartOfElement(const QString& elementName) 0450 { 0451 // go to next start element 0452 Q_FOREVER 0453 { 0454 bool atStart = isStartElement(); 0455 0456 if (atStart) 0457 { 0458 break; 0459 } 0460 0461 switch (QXmlStreamReader::readNext()) 0462 { 0463 case StartElement: 0464 { 0465 atStart = true; 0466 (void)atStart; // Remove clang warning. 0467 break; 0468 } 0469 case EndDocument: 0470 { 0471 return false; 0472 } 0473 default: 0474 { 0475 break; 0476 } 0477 } 0478 } 0479 0480 int stack = 1; 0481 0482 Q_FOREVER 0483 { 0484 switch (QXmlStreamReader::readNext()) 0485 { 0486 case StartElement: 0487 { 0488 if (name() == elementName) 0489 { 0490 return true; 0491 } 0492 0493 ++stack; 0494 break; 0495 } 0496 case EndElement: 0497 { 0498 if (!--stack) 0499 { 0500 return false; 0501 } 0502 0503 break; 0504 } 0505 case EndDocument: 0506 { 0507 return false; 0508 } 0509 default: 0510 { 0511 break; 0512 } 0513 } 0514 } 0515 0516 return false; 0517 } 0518 0519 void SearchXmlReader::readToEndOfElement() 0520 { 0521 if (isStartElement()) 0522 { 0523 int stack = 1; 0524 0525 Q_FOREVER 0526 { 0527 switch (QXmlStreamReader::readNext()) 0528 { 0529 case StartElement: 0530 { 0531 ++stack; 0532 break; 0533 } 0534 case EndElement: 0535 { 0536 if (!--stack) 0537 { 0538 return; 0539 } 0540 0541 break; 0542 } 0543 case EndDocument: 0544 { 0545 return; 0546 } 0547 default: 0548 { 0549 break; 0550 } 0551 } 0552 } 0553 } 0554 } 0555 0556 void SearchXmlReader::readToFirstField() 0557 { 0558 SearchXml::Element element; 0559 bool hasGroup = false; 0560 0561 while (!atEnd()) 0562 { 0563 element = readNext(); 0564 0565 if (element == SearchXml::Group) 0566 { 0567 hasGroup = true; 0568 } 0569 else if (hasGroup && element == SearchXml::Field) 0570 { 0571 return; 0572 } 0573 } 0574 } 0575 0576 // --------------------------------------------------------------------------------- 0577 0578 SearchXmlWriter::SearchXmlWriter() 0579 : QXmlStreamWriter(&m_xml) 0580 { 0581 writeStartDocument(); 0582 writeStartElement(QLatin1String("search")); 0583 } 0584 0585 QString SearchXmlWriter::xml() const 0586 { 0587 return m_xml; 0588 } 0589 0590 void SearchXmlWriter::writeGroup() 0591 { 0592 writeStartElement(QLatin1String("group")); 0593 } 0594 0595 void SearchXmlWriter::setGroupOperator(SearchXml::Operator op) 0596 { 0597 if (op != SearchXml::Or) 0598 { 0599 writeOperator(QLatin1String("operator"), op); 0600 } 0601 } 0602 0603 void SearchXmlWriter::setGroupCaption(const QString& caption) 0604 { 0605 if (!caption.isNull()) 0606 { 0607 writeAttribute(QLatin1String("caption"), caption); 0608 } 0609 } 0610 0611 void SearchXmlWriter::setDefaultFieldOperator(SearchXml::Operator op) 0612 { 0613 if (op != SearchXml::And) 0614 { 0615 writeOperator(QLatin1String("fieldoperator"), op); 0616 } 0617 } 0618 0619 void SearchXmlWriter::writeField(const QString& name, SearchXml::Relation relation) 0620 { 0621 writeStartElement(QLatin1String("field")); 0622 writeAttribute(QLatin1String("name"), name); 0623 writeRelation(QLatin1String("relation"), relation); 0624 } 0625 0626 void SearchXmlWriter::setFieldOperator(SearchXml::Operator op) 0627 { 0628 writeOperator(QLatin1String("operator"), op); 0629 } 0630 0631 void SearchXmlWriter::writeValue(const QString& value) 0632 { 0633 writeCharacters(value); 0634 } 0635 0636 void SearchXmlWriter::writeValue(int value) 0637 { 0638 writeCharacters(QString::number(value)); 0639 } 0640 0641 void SearchXmlWriter::writeValue(qlonglong value) 0642 { 0643 writeCharacters(QString::number(value)); 0644 } 0645 0646 void SearchXmlWriter::writeValue(float value, int precision) 0647 { 0648 writeCharacters(QString::number(value, 'g', precision)); 0649 } 0650 0651 void SearchXmlWriter::writeValue(double value, int precision) 0652 { 0653 writeCharacters(QString::number(value, 'g', precision)); 0654 } 0655 0656 void SearchXmlWriter::writeValue(const QDateTime& dateTime) 0657 { 0658 writeCharacters(dateTime.toString(Qt::ISODate)); 0659 } 0660 0661 void SearchXmlWriter::writeValue(const QList<int>& valueList) 0662 { 0663 QString listitem(QLatin1String("listitem")); 0664 0665 Q_FOREACH (int i, valueList) 0666 { 0667 writeTextElement(listitem, QString::number(i)); 0668 } 0669 } 0670 0671 void SearchXmlWriter::writeValue(const QList<qlonglong>& valueList) 0672 { 0673 QString listitem(QLatin1String("listitem")); 0674 0675 Q_FOREACH (int i, valueList) 0676 { 0677 writeTextElement(listitem, QString::number(i)); 0678 } 0679 } 0680 0681 void SearchXmlWriter::writeValue(const QList<float>& valueList, int precision) 0682 { 0683 QString listitem(QLatin1String("listitem")); 0684 0685 Q_FOREACH (double i, valueList) 0686 { 0687 writeTextElement(listitem, QString::number(i, 'g', precision)); 0688 } 0689 } 0690 0691 void SearchXmlWriter::writeValue(const QList<double>& valueList, int precision) 0692 { 0693 QString listitem(QLatin1String("listitem")); 0694 0695 Q_FOREACH (double i, valueList) 0696 { 0697 writeTextElement(listitem, QString::number(i, 'g', precision)); 0698 } 0699 } 0700 0701 void SearchXmlWriter::writeValue(const QList<QDateTime>& valueList) 0702 { 0703 QString listitem(QLatin1String("listitem")); 0704 0705 Q_FOREACH (const QDateTime& dt, valueList) 0706 { 0707 writeTextElement(listitem, dt.toString(Qt::ISODate)); 0708 } 0709 } 0710 0711 void SearchXmlWriter::writeValue(const QStringList& valueList) 0712 { 0713 QString listitem(QLatin1String("listitem")); 0714 0715 Q_FOREACH (const QString& str, valueList) 0716 { 0717 writeTextElement(listitem, str); 0718 } 0719 } 0720 0721 void SearchXmlWriter::finishField() 0722 { 0723 writeEndElement(); 0724 } 0725 0726 void SearchXmlWriter::finishGroup() 0727 { 0728 writeEndElement(); 0729 } 0730 0731 void SearchXmlWriter::finish() 0732 { 0733 writeEndDocument(); 0734 } 0735 0736 void SearchXmlWriter::writeOperator(const QString& attributeName, SearchXml::Operator op) 0737 { 0738 switch (op) 0739 { 0740 default: 0741 case SearchXml::And: 0742 writeAttribute(attributeName, QLatin1String("and")); 0743 break; 0744 case SearchXml::Or: 0745 writeAttribute(attributeName, QLatin1String("or")); 0746 break; 0747 case SearchXml::AndNot: 0748 writeAttribute(attributeName, QLatin1String("andnot")); 0749 break; 0750 case SearchXml::OrNot: 0751 writeAttribute(attributeName, QLatin1String("ornot")); 0752 break; 0753 } 0754 } 0755 0756 void SearchXmlWriter::writeRelation(const QString& attributeName, SearchXml::Relation op) 0757 { 0758 switch (op) 0759 { 0760 default: 0761 case SearchXml::Equal: 0762 writeAttribute(attributeName, QLatin1String("equal")); 0763 break; 0764 case SearchXml::Unequal: 0765 writeAttribute(attributeName, QLatin1String("unequal")); 0766 break; 0767 case SearchXml::Like: 0768 writeAttribute(attributeName, QLatin1String("like")); 0769 break; 0770 case SearchXml::NotLike: 0771 writeAttribute(attributeName, QLatin1String("notlike")); 0772 break; 0773 case SearchXml::LessThan: 0774 writeAttribute(attributeName, QLatin1String("lessthan")); 0775 break; 0776 case SearchXml::GreaterThan: 0777 writeAttribute(attributeName, QLatin1String("greaterthan")); 0778 break; 0779 case SearchXml::LessThanOrEqual: 0780 writeAttribute(attributeName, QLatin1String("lessthanequal")); 0781 break; 0782 case SearchXml::GreaterThanOrEqual: 0783 writeAttribute(attributeName, QLatin1String("greaterthanequal")); 0784 break; 0785 case SearchXml::Interval: 0786 writeAttribute(attributeName, QLatin1String("interval")); 0787 break; 0788 case SearchXml::IntervalOpen: 0789 writeAttribute(attributeName, QLatin1String("intervalopen")); 0790 break; 0791 case SearchXml::OneOf: 0792 writeAttribute(attributeName, QLatin1String("oneof")); 0793 break; 0794 case SearchXml::AllOf: 0795 writeAttribute(attributeName, QLatin1String("allof")); 0796 break; 0797 case SearchXml::InTree: 0798 writeAttribute(attributeName, QLatin1String("intree")); 0799 break; 0800 case SearchXml::NotInTree: 0801 writeAttribute(attributeName, QLatin1String("notintree")); 0802 break; 0803 case SearchXml::Near: 0804 writeAttribute(attributeName, QLatin1String("near")); 0805 break; 0806 case SearchXml::Inside: 0807 writeAttribute(attributeName, QLatin1String("inside")); 0808 break; 0809 } 0810 } 0811 0812 QString SearchXmlWriter::keywordSearch(const QString& keyword) 0813 { 0814 SearchXmlWriter writer; 0815 writer.writeGroup(); 0816 writer.writeField(QLatin1String("keyword"), SearchXml::Like); 0817 writer.writeValue(keyword); 0818 writer.finishField(); 0819 writer.finishGroup(); 0820 writer.finish(); 0821 0822 return writer.xml(); 0823 } 0824 0825 // --------------------------------------------------------------------------------- 0826 0827 QStringList KeywordSearch::split(const QString& keywords) 0828 { 0829 // get groups with quotation marks 0830 QStringList quotationMarkList = keywords.split(QLatin1Char('"'), QT_KEEP_EMPTY_PARTS); 0831 0832 // split down to single words 0833 QStringList keywordList; 0834 int quotationMarkCount = (keywords.startsWith(QLatin1Char('"')) ? 1 : 0); 0835 0836 Q_FOREACH (const QString& group, quotationMarkList) 0837 { 0838 if (quotationMarkCount % 2) 0839 { 0840 // inside marks: leave as is 0841 if (!group.isEmpty()) 0842 { 0843 keywordList << group; 0844 } 0845 } 0846 else 0847 { 0848 // not in quotation marks: split by whitespace 0849 keywordList << group.split(QRegularExpression(QLatin1String("\\s+")), QT_SKIP_EMPTY_PARTS); 0850 } 0851 0852 ++quotationMarkCount; 0853 } 0854 0855 return keywordList; 0856 } 0857 0858 QString KeywordSearch::merge(const QStringList& keywordList) 0859 { 0860 QStringList list(keywordList); 0861 0862 // group keyword with spaces in quotation marks 0863 for (QStringList::iterator it = list.begin() ; it != list.end() ; ++it) 0864 { 0865 if ((*it).contains(QLatin1Char(' '))) 0866 { 0867 *it = (*it).prepend(QLatin1Char('"')).append(QLatin1Char('"')); 0868 } 0869 } 0870 0871 // join in a string 0872 return list.join(QLatin1Char(' ')); 0873 } 0874 0875 QString KeywordSearch::merge(const QString& previousContent, const QString& newEntry) 0876 { 0877 QString ne(newEntry); 0878 QString pc(previousContent); 0879 0880 if (ne.contains(QLatin1Char(' '))) 0881 { 0882 ne = ne.prepend(QLatin1Char('"')).append(QLatin1Char('"')); 0883 } 0884 0885 return pc.append(QLatin1Char(' ')).append(ne); 0886 } 0887 0888 // --------------------------------------------------------------------------------- 0889 0890 KeywordSearchReader::KeywordSearchReader(const QString& xml) 0891 : SearchXmlReader(xml) 0892 { 0893 } 0894 0895 QStringList KeywordSearchReader::keywords() 0896 { 0897 QStringList list; 0898 0899 SearchXml::Element element; 0900 0901 while (!atEnd()) 0902 { 0903 element = readNext(); 0904 0905 if (element == SearchXml::Group) 0906 { 0907 readGroup(list); 0908 } 0909 } 0910 0911 return list; 0912 } 0913 0914 void KeywordSearchReader::readGroup(QStringList& list) 0915 { 0916 SearchXml::Element element; 0917 0918 while (!atEnd()) 0919 { 0920 element = readNext(); 0921 0922 if (element == SearchXml::Field) 0923 { 0924 QString value = readField(); 0925 0926 if (!value.isEmpty()) 0927 { 0928 list << value; 0929 } 0930 } 0931 0932 if (element == SearchXml::GroupEnd) 0933 { 0934 return; 0935 } 0936 } 0937 } 0938 0939 QString KeywordSearchReader::readField() 0940 { 0941 if (fieldName() == QLatin1String("keyword")) 0942 { 0943 return value(); 0944 } 0945 0946 return QString(); 0947 } 0948 0949 bool KeywordSearchReader::isSimpleKeywordSearch() 0950 { 0951 // Find out if this XML conforms to a simple keyword search, 0952 // as created with KeywordSearchWriter 0953 SearchXml::Element element; 0954 int groupCount = 0; 0955 0956 while (!atEnd()) 0957 { 0958 element = readNext(); 0959 0960 if (element == SearchXml::Group) 0961 { 0962 // only one group please 0963 if (++groupCount > 1) 0964 { 0965 return false; 0966 } 0967 0968 if (!isSimpleKeywordSearchGroup()) 0969 { 0970 return false; 0971 } 0972 } 0973 } 0974 0975 return true; 0976 } 0977 0978 bool KeywordSearchReader::isSimpleKeywordSearchGroup() 0979 { 0980 // Find out if the current group conforms to a simple keyword search, 0981 // as created with KeywordSearchWriter 0982 0983 if (groupOperator() != SearchXml::standardGroupOperator()) 0984 { 0985 return false; 0986 } 0987 0988 if (defaultFieldOperator() != SearchXml::standardFieldOperator()) 0989 { 0990 return false; 0991 } 0992 0993 SearchXml::Element element; 0994 0995 while (!atEnd()) 0996 { 0997 element = readNext(); 0998 0999 // subgroups not allowed 1000 if (element == SearchXml::Group) 1001 { 1002 return false; 1003 } 1004 1005 // only "keyword" fields allowed 1006 if (element == SearchXml::Field) 1007 { 1008 if (fieldName() != QLatin1String("keyword")) 1009 { 1010 return false; 1011 } 1012 1013 if (fieldRelation() != SearchXml::Like) 1014 { 1015 return false; 1016 } 1017 1018 if (fieldOperator() != SearchXml::standardFieldOperator()) 1019 { 1020 return false; 1021 } 1022 } 1023 1024 if (element == SearchXml::GroupEnd) 1025 { 1026 return true; 1027 } 1028 } 1029 1030 return true; 1031 } 1032 1033 // --------------------------------------------------------------------------------- 1034 1035 KeywordSearchWriter::KeywordSearchWriter() 1036 : SearchXmlWriter() 1037 { 1038 } 1039 1040 QString KeywordSearchWriter::xml(const QStringList& keywordList) 1041 { 1042 writeGroup(); 1043 1044 Q_FOREACH (const QString& keyword, keywordList) 1045 { 1046 writeField(QLatin1String("keyword"), SearchXml::Like); 1047 writeValue(keyword); 1048 finishField(); 1049 } 1050 1051 finishGroup(); 1052 finish(); 1053 1054 return SearchXmlWriter::xml(); 1055 } 1056 1057 // --------------------------------------------------------------------------------- 1058 1059 SearchXmlCachingReader::SearchXmlCachingReader(const QString& xml) 1060 : SearchXmlReader(xml), 1061 m_groupOperator(SearchXml::And), 1062 m_fieldOperator(SearchXml::And), 1063 m_fieldRelation(SearchXml::Equal), 1064 m_readValue(false) 1065 { 1066 } 1067 1068 SearchXml::Element SearchXmlCachingReader::readNext() 1069 { 1070 SearchXml::Element element = SearchXmlReader::readNext(); 1071 1072 if (element == SearchXml::Group) 1073 { 1074 m_groupOperator = SearchXmlReader::groupOperator(); 1075 m_groupCaption = SearchXmlReader::groupCaption(); 1076 } 1077 else if (element == SearchXml::Field) 1078 { 1079 m_fieldOperator = SearchXmlReader::fieldOperator(); 1080 m_fieldName = SearchXmlReader::fieldName(); 1081 m_fieldRelation = SearchXmlReader::fieldRelation(); 1082 m_readValue = false; 1083 } 1084 1085 return element; 1086 } 1087 1088 SearchXml::Operator SearchXmlCachingReader::groupOperator() const 1089 { 1090 return m_groupOperator; 1091 } 1092 1093 QString SearchXmlCachingReader::groupCaption() const 1094 { 1095 return m_groupCaption; 1096 } 1097 1098 SearchXml::Operator SearchXmlCachingReader::fieldOperator() const 1099 { 1100 return m_fieldOperator; 1101 } 1102 1103 QString SearchXmlCachingReader::fieldName() const 1104 { 1105 return m_fieldName; 1106 } 1107 1108 SearchXml::Relation SearchXmlCachingReader::fieldRelation() const 1109 { 1110 return m_fieldRelation; 1111 } 1112 1113 QString SearchXmlCachingReader::value() 1114 { 1115 if (!m_readValue) 1116 { 1117 m_value = SearchXmlReader::value(); 1118 m_readValue = true; 1119 } 1120 1121 return m_value.toString(); 1122 } 1123 1124 int SearchXmlCachingReader::valueToInt() 1125 { 1126 if (!m_readValue) 1127 { 1128 m_value = SearchXmlReader::valueToInt(); 1129 m_readValue = true; 1130 } 1131 1132 return m_value.toInt(); 1133 } 1134 1135 qlonglong SearchXmlCachingReader::valueToLongLong() 1136 { 1137 if (!m_readValue) 1138 { 1139 m_value = SearchXmlReader::valueToLongLong(); 1140 m_readValue = true; 1141 } 1142 1143 return m_value.toLongLong(); 1144 } 1145 1146 double SearchXmlCachingReader::valueToDouble() 1147 { 1148 if (!m_readValue) 1149 { 1150 m_value = SearchXmlReader::valueToDouble(); 1151 m_readValue = true; 1152 } 1153 1154 return m_value.toDouble(); 1155 } 1156 1157 QDateTime SearchXmlCachingReader::valueToDateTime() 1158 { 1159 if (!m_readValue) 1160 { 1161 m_value = SearchXmlReader::valueToDateTime(); 1162 m_readValue = true; 1163 } 1164 1165 return m_value.toDateTime(); 1166 } 1167 1168 QList<int> SearchXmlCachingReader::valueToIntList() 1169 { 1170 // with no QVariant support for QList<int>, 1171 // we convert here from string list (equivalent result) 1172 QStringList list = valueToStringList(); 1173 QList<int> intList; 1174 1175 Q_FOREACH (const QString& s, list) 1176 { 1177 double val = s.toDouble(); 1178 intList << (int)val; 1179 } 1180 1181 return intList; 1182 } 1183 1184 QList<qlonglong> SearchXmlCachingReader::valueToLongLongList() 1185 { 1186 // with no QVariant support for QList<qlonglong>, 1187 // we convert here from string list (equivalent result) 1188 QStringList list = valueToStringList(); 1189 QList<qlonglong> qlonglongList; 1190 1191 Q_FOREACH (const QString& s, list) 1192 { 1193 double val = s.toDouble(); 1194 qlonglongList << (qlonglong)val; 1195 } 1196 1197 return qlonglongList; 1198 } 1199 1200 QList<double> SearchXmlCachingReader::valueToDoubleList() 1201 { 1202 // with no QVariant support for QList<double>, 1203 // we convert here from string list (equivalent result) 1204 QStringList list = valueToStringList(); 1205 QList<double> doubleList; 1206 1207 Q_FOREACH (const QString& s, list) 1208 { 1209 doubleList << s.toDouble(); 1210 } 1211 1212 return doubleList; 1213 } 1214 1215 QList<QDateTime> SearchXmlCachingReader::valueToDateTimeList() 1216 { 1217 // with no QVariant support for QList<QDateTime>, 1218 // we convert here from string list (equivalent result) 1219 QStringList list = valueToStringList(); 1220 QList<QDateTime> doubleList; 1221 1222 Q_FOREACH (const QString& s, list) 1223 { 1224 doubleList << QDateTime::fromString(s, Qt::ISODate); 1225 } 1226 1227 return doubleList; 1228 } 1229 1230 QStringList SearchXmlCachingReader::valueToStringList() 1231 { 1232 if (!m_readValue) 1233 { 1234 m_value = SearchXmlReader::valueToStringList(); 1235 m_readValue = true; 1236 } 1237 1238 return m_value.toStringList(); 1239 } 1240 1241 QList<int> SearchXmlCachingReader::valueToIntOrIntList() 1242 { 1243 if (!m_readValue) 1244 { 1245 QList<int> intList = SearchXmlReader::valueToIntOrIntList(); 1246 QList<QVariant> varList; 1247 1248 Q_FOREACH (int v, intList) 1249 { 1250 varList << v; 1251 } 1252 1253 m_value = varList; 1254 m_readValue = true; 1255 1256 return intList; 1257 } 1258 1259 QList<int> intList; 1260 QList<QVariant> varList = m_value.toList(); 1261 1262 Q_FOREACH (const QVariant& var, varList) 1263 { 1264 intList << var.toInt(); 1265 } 1266 1267 return intList; 1268 } 1269 1270 QList<double> SearchXmlCachingReader::valueToDoubleOrDoubleList() 1271 { 1272 if (!m_readValue) 1273 { 1274 QList<double> doubleList = SearchXmlReader::valueToDoubleOrDoubleList(); 1275 QList<QVariant> varList; 1276 1277 Q_FOREACH (double v, doubleList) 1278 { 1279 varList << v; 1280 } 1281 1282 m_value = varList; 1283 m_readValue = true; 1284 1285 return doubleList; 1286 } 1287 1288 QList<double> doubleList; 1289 QList<QVariant> varList = m_value.toList(); 1290 1291 Q_FOREACH (const QVariant& var, varList) 1292 { 1293 doubleList << var.toDouble(); 1294 } 1295 1296 return doubleList; 1297 } 1298 1299 QList<QString> SearchXmlCachingReader::valueToStringOrStringList() 1300 { 1301 if (!m_readValue) 1302 { 1303 QList<QString> QStringList = SearchXmlReader::valueToStringOrStringList(); 1304 QList<QVariant> varList; 1305 1306 Q_FOREACH (const QString& v, QStringList) 1307 { 1308 varList << v; 1309 } 1310 1311 m_value = varList; 1312 m_readValue = true; 1313 return QStringList; 1314 } 1315 1316 QList<QString> lst; 1317 QList<QVariant> varList = m_value.toList(); 1318 1319 Q_FOREACH (const QVariant& var, varList) 1320 { 1321 lst << var.toString(); 1322 } 1323 1324 return lst; 1325 } 1326 1327 } // namespace Digikam