File indexing completed on 2024-05-19 04:49:18
0001 /**************************************************************************************** 0002 * Copyright (c) 2007-2008 Maximilian Kossick <maximilian.kossick@googlemail.com> * 0003 * Copyright (c) 2008 Daniel Caleb Jones <danielcjones@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #include "XmlQueryReader.h" 0019 0020 #include "core/support/Debug.h" 0021 #include "core-impl/collections/support/CollectionManager.h" 0022 0023 #include <QString> 0024 0025 struct XmlQueryReader::Private 0026 { 0027 ReturnValueEnum flag; 0028 Collections::QueryMaker *qm; 0029 QList<Filter> filters; 0030 }; 0031 0032 Collections::QueryMaker* 0033 XmlQueryReader::getQueryMaker( const QString &xmlData, ReturnValueEnum flag ) 0034 { 0035 Collections::QueryMaker *qm = CollectionManager::instance()->queryMaker(); 0036 XmlQueryReader reader( qm, flag ); 0037 if( reader.read( xmlData ) ) 0038 return qm; 0039 else 0040 return nullptr; 0041 } 0042 0043 XmlQueryReader::XmlQueryReader( Collections::QueryMaker *qm, ReturnValueEnum flag ) 0044 : QXmlStreamReader() 0045 , d( new Private ) 0046 { 0047 d->flag = flag; 0048 d->qm = qm; 0049 } 0050 0051 XmlQueryReader::~XmlQueryReader() 0052 { 0053 delete d; 0054 } 0055 0056 const QList<XmlQueryReader::Filter>& 0057 XmlQueryReader::getFilters() const 0058 { 0059 return d->filters; 0060 } 0061 0062 bool 0063 XmlQueryReader::read( const QString &xmlData ) 0064 { 0065 addData( xmlData ); 0066 int queryCount = 0; 0067 while( !atEnd() ) 0068 { 0069 readNext(); 0070 0071 if( isStartElement() ) 0072 { 0073 //we expect exactly one query definition in the xml data. 0074 //so fail if we find more than one 0075 if( name() == "query" ) 0076 { 0077 if( attributes().value( QStringLiteral("version") ) == "1.0" ) 0078 { 0079 queryCount++; 0080 readQuery(); 0081 } 0082 } 0083 } 0084 } 0085 0086 return queryCount == 1 && !error(); 0087 } 0088 0089 void 0090 XmlQueryReader::readQuery() 0091 { 0092 while( !atEnd() ) 0093 { 0094 readNext(); 0095 0096 if( isStartElement() ) 0097 { 0098 if( name() == "filters" ) 0099 readFilters(); 0100 else if( name() == "order" ) 0101 { 0102 QXmlStreamAttributes attr = attributes(); 0103 QStringRef fieldStr = attr.value( QStringLiteral("field") ); 0104 QStringRef valueStr = attr.value( QStringLiteral("value") ); 0105 0106 qint64 field = Meta::fieldForName( fieldStr.toString() ); 0107 bool descending = valueStr == "descending"; 0108 0109 if( field != 0 ) 0110 d->qm->orderBy( field, descending ); 0111 } 0112 else if( name() == "limit" ) 0113 { 0114 QStringRef value = attributes().value( QStringLiteral("value") ); 0115 if( !value.isEmpty() ) 0116 d->qm->limitMaxResultSize( value.toString().toInt() ); 0117 } 0118 else if( name() == "onlyCompilations" ) 0119 { 0120 d->qm->setAlbumQueryMode( Collections::QueryMaker::OnlyCompilations ); 0121 } 0122 else if( name() == "onlyNormalAlbums" ) 0123 { 0124 d->qm->setAlbumQueryMode( Collections::QueryMaker::OnlyNormalAlbums ); 0125 } 0126 else if( name() == "returnValues" ) 0127 readReturnValues(); 0128 //add more container elements here 0129 else 0130 ignoreElements(); 0131 } 0132 } 0133 } 0134 0135 void 0136 XmlQueryReader::ignoreElements() 0137 { 0138 //let QXmlStreamReader worry about the fell-formedness of the document 0139 int depth = 1; 0140 while( !atEnd() && depth > 0 ) 0141 { 0142 readNext(); 0143 if( isEndElement() ) 0144 depth--; 0145 if( isStartElement() ) 0146 depth++; 0147 } 0148 } 0149 0150 void 0151 XmlQueryReader::readReturnValues() 0152 { 0153 if( d->flag & XmlQueryReader::IgnoreReturnValues ) 0154 { 0155 ignoreElements(); 0156 return; 0157 } 0158 else 0159 { 0160 bool customQueryStarted = false; 0161 while( !atEnd() ) 0162 { 0163 readNext(); 0164 if( name() == "tracks" ) 0165 { 0166 d->qm->setQueryType( Collections::QueryMaker::Track ); 0167 } 0168 else if( name() == "artists" ) 0169 { 0170 d->qm->setQueryType( Collections::QueryMaker::Artist ); 0171 } 0172 else if( name() == "albums" ) 0173 { 0174 d->qm->setQueryType( Collections::QueryMaker::Album ); 0175 } 0176 else if( name() == "albumartist" ) 0177 { 0178 d->qm->setQueryType( Collections::QueryMaker::AlbumArtist ); 0179 } 0180 else if( name() == "genres" ) 0181 { 0182 d->qm->setQueryType( Collections::QueryMaker::Genre ); 0183 } 0184 else if( name() == "composers" ) 0185 { 0186 d->qm->setQueryType( Collections::QueryMaker::Composer ); 0187 } 0188 else if( name() == "year" ) 0189 { 0190 d->qm->setQueryType( Collections::QueryMaker::Year ); 0191 } 0192 else 0193 { 0194 if( !customQueryStarted ) 0195 { 0196 d->qm->setQueryType( Collections::QueryMaker::Custom ); 0197 } 0198 //TODO write a mapping function somewhere 0199 if( name() == "title" ) 0200 { 0201 d->qm->addReturnValue( Meta::valTitle ); 0202 } 0203 else if( name() == "artist" ) 0204 { 0205 d->qm->addReturnValue( Meta::valArtist ); 0206 } 0207 } 0208 } 0209 } 0210 } 0211 0212 void 0213 XmlQueryReader::readAndOr() 0214 { 0215 readFilters(); 0216 ignoreElements(); 0217 d->qm->endAndOr(); 0218 } 0219 0220 XmlQueryReader::Filter 0221 XmlQueryReader::readFilter(QXmlStreamReader *reader) 0222 { 0223 Filter filter; 0224 0225 QXmlStreamAttributes attr = reader->attributes(); 0226 0227 filter.exclude = (reader->name() != "include"); 0228 filter.field = Meta::fieldForName( attr.value( QStringLiteral("field") ).toString() ); 0229 filter.value = attr.value( QStringLiteral("value") ).toString(); 0230 0231 QStringRef compareStr = attr.value( QStringLiteral("compare") ); 0232 if( compareStr.isEmpty() ) 0233 filter.compare = -1; 0234 else 0235 filter.compare = compareVal( compareStr ); 0236 0237 return filter; 0238 } 0239 0240 void 0241 XmlQueryReader::readFilters() 0242 { 0243 while( !atEnd() ) 0244 { 0245 readNext(); 0246 if( isEndElement() ) 0247 { 0248 if( name() == "and" || name() == "or" ) 0249 { 0250 d->qm->endAndOr(); 0251 break; 0252 } 0253 else if( name() == "filters" ) 0254 { 0255 break; 0256 } 0257 else 0258 continue; 0259 } 0260 0261 if( name() == "include" || name() == "exclude" ) 0262 { 0263 Filter filter = readFilter(this); 0264 0265 if( filter.field == 0 ) 0266 break; 0267 0268 if( filter.compare != -1 ) 0269 { 0270 qint64 numValue = filter.value.toInt(); 0271 if( !filter.exclude ) 0272 { 0273 debug() << "XQR: number include filter:"; 0274 d->qm->addNumberFilter( filter.field, numValue, 0275 (Collections::QueryMaker::NumberComparison)filter.compare ); 0276 } 0277 else 0278 { 0279 debug() << "XQR: number exclude filter: "; 0280 d->qm->excludeNumberFilter( filter.field, numValue, 0281 (Collections::QueryMaker::NumberComparison)filter.compare ); 0282 } 0283 } 0284 else 0285 { 0286 if( !filter.exclude ) 0287 { 0288 debug() << "XQR: include filter"; 0289 d->qm->addFilter( filter.field, filter.value ); 0290 } 0291 else 0292 { 0293 debug() << "XQR: exclude filter"; 0294 d->qm->excludeFilter( filter.field, filter.value ); 0295 } 0296 } 0297 0298 d->filters.append( filter ); 0299 } 0300 else if( name() == "and" ) 0301 { 0302 d->qm->beginAnd(); 0303 readFilters(); 0304 } 0305 else if( name() == "or" ) 0306 { 0307 d->qm->beginOr(); 0308 readFilters(); 0309 } 0310 } 0311 } 0312 0313 int 0314 XmlQueryReader::compareVal( QStringRef compare ) 0315 { 0316 if( compare == "less" ) 0317 return Collections::QueryMaker::LessThan; 0318 else if( compare == "greater" ) 0319 return Collections::QueryMaker::GreaterThan; 0320 else if( compare == "equals" ) 0321 return Collections::QueryMaker::Equals; 0322 else 0323 return -1; 0324 }