1 /****************************************************************************************
2 * Copyright (c) 2010 Maximilian Kossick <maximilian.kossick@googlemail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify it under *
5 * the terms of the GNU General Public License as published by the Free Software *
6 * Foundation; either version 2 of the License, or (at your option) any later *
7 * version. *
8 * *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY *
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
11 * PARTICULAR PURPOSE. See the GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License along with *
14 * this program. If not, see <http://www.gnu.org/licenses/>. *
15 ****************************************************************************************/
16
17 #include "MemoryQueryMakerInternal.h"
18
19 #include "MemoryCollection.h"
20 #include "MemoryCustomValue.h"
21 #include "MemoryFilter.h"
22 #include "MemoryMatcher.h"
23 #include "MemoryQueryMakerHelper.h"
24
25 #include "core/meta/Meta.h"
26
27 #include <QSharedPointer>
28
29 #include <KSortableList>
30
31 namespace Collections {
32
MemoryQueryMakerInternal(const QWeakPointer<MemoryCollection> & collection)33 MemoryQueryMakerInternal::MemoryQueryMakerInternal( const QWeakPointer<MemoryCollection> &collection )
34 : QObject()
35 , m_collection( collection )
36 , m_matchers( 0 )
37 , m_filters( 0 )
38 , m_maxSize( 0 )
39 , m_type( QueryMaker::None )
40 , m_albumQueryMode( QueryMaker::AllAlbums )
41 , m_orderDescending( false )
42 , m_orderByNumberField( false )
43 , m_orderByField( 0 )
44 {
45
46 }
47
~MemoryQueryMakerInternal()48 MemoryQueryMakerInternal::~MemoryQueryMakerInternal()
49 {
50 delete m_filters;
51 delete m_matchers;
52 qDeleteAll( m_returnFunctions );
53 qDeleteAll( m_returnValues );
54 }
55
56 void
runQuery()57 MemoryQueryMakerInternal::runQuery()
58 {
59 QSharedPointer<MemoryCollection> coll = m_collection.toStrongRef();
60 if( coll )
61 coll->acquireReadLock();
62 //naive implementation, fix this
63 if ( m_matchers )
64 {
65 Meta::TrackList result = coll ? m_matchers->match( coll.data() ) : Meta::TrackList();
66 if ( m_filters )
67 {
68 Meta::TrackList filtered;
69 foreach( Meta::TrackPtr track, result )
70 {
71 if( m_filters->filterMatches( track ) )
72 filtered.append( track );
73 }
74 handleResult( filtered );
75 }
76 else
77 handleResult( result );
78 }
79 else if ( m_filters )
80 {
81 Meta::TrackList tracks = coll ? coll->trackMap().values() : Meta::TrackList();
82 Meta::TrackList filtered;
83 foreach( const Meta::TrackPtr &track, tracks )
84 {
85 if ( m_filters->filterMatches( track ) )
86 filtered.append( track );
87 }
88 handleResult( filtered );
89 }
90 else
91 handleResult();
92 if( coll )
93 coll->releaseLock();
94 }
95
96 template<typename T>
reverse(const QList<T> & l)97 static inline QList<T> reverse(const QList<T> &l)
98 {
99 QList<T> ret;
100 for (int i=l.size() - 1; i>=0; --i)
101 ret.append(l.at(i));
102 return ret;
103 }
104
105 void
handleResult()106 MemoryQueryMakerInternal::handleResult()
107 {
108 QSharedPointer<MemoryCollection> coll = m_collection.toStrongRef();
109 //this gets called when we want to return all values for the given query type
110 switch( m_type )
111 {
112 case QueryMaker::Custom :
113 {
114 QStringList result;
115 Meta::TrackList tmpTracks = coll ? coll->trackMap().values() : Meta::TrackList();
116 Meta::TrackList tracks;
117 foreach( const Meta::TrackPtr &track, tmpTracks )
118 {
119 if( ( m_albumQueryMode == QueryMaker::AllAlbums
120 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && track->album()->isCompilation() )
121 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !track->album()->isCompilation()) ) &&
122 ( m_labelQueryMode == QueryMaker::NoConstraint
123 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
124 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
125 {
126 tracks.append( track );
127 }
128 }
129
130 if( !m_returnFunctions.empty() )
131 {
132 //no sorting necessary
133 foreach( CustomReturnFunction *function, m_returnFunctions )
134 {
135 result.append( function->value( tracks ) );
136 }
137 }
138 else if( !m_returnValues.empty() )
139 {
140 if( m_orderByField )
141 {
142 if( m_orderByNumberField )
143 tracks = MemoryQueryMakerHelper::orderListByNumber( tracks, m_orderByField, m_orderDescending );
144 else
145 tracks = MemoryQueryMakerHelper::orderListByString( tracks, m_orderByField, m_orderDescending );
146 }
147
148 int count = 0;
149 foreach( const Meta::TrackPtr &track, tracks )
150 {
151 if ( m_maxSize >= 0 && count == m_maxSize )
152 break;
153
154 foreach( CustomReturnValue *value, m_returnValues )
155 {
156 result.append( value->value( track ) );
157 }
158 count++;
159 }
160 }
161 Q_EMIT newResultReady( result );
162 break;
163 }
164 case QueryMaker::Track :
165 {
166 Meta::TrackList tracks;
167
168 Meta::TrackList tmpTracks = coll ? coll->trackMap().values() : Meta::TrackList();
169 foreach( Meta::TrackPtr track, tmpTracks )
170 {
171 Meta::AlbumPtr album = track->album();
172 if( ( m_albumQueryMode == QueryMaker::AllAlbums
173 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && (!album || album->isCompilation()) )
174 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && (album && !album->isCompilation()) ) ) &&
175 ( m_labelQueryMode == QueryMaker::NoConstraint
176 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
177 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
178 {
179 tracks.append( track );
180 }
181 }
182
183 if( m_orderByField )
184 {
185 if( m_orderByNumberField )
186 tracks = MemoryQueryMakerHelper::orderListByNumber( tracks, m_orderByField, m_orderDescending );
187 else
188 tracks = MemoryQueryMakerHelper::orderListByString( tracks, m_orderByField, m_orderDescending );
189 }
190
191 Q_EMIT newTracksReady( tracks );
192 break;
193 }
194 case QueryMaker::Album :
195 {
196 Meta::AlbumList albums;
197 Meta::AlbumList tmp = coll ? coll->albumMap().values() : Meta::AlbumList();
198 foreach( Meta::AlbumPtr album, tmp )
199 {
200 Meta::TrackList tracks = album->tracks();
201 foreach( Meta::TrackPtr track, tracks )
202 {
203 Meta::AlbumPtr album = track->album();
204 if( ( m_albumQueryMode == QueryMaker::AllAlbums
205 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && (!album || album->isCompilation()) )
206 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && (album && !album->isCompilation()) ) ) &&
207 ( m_labelQueryMode == QueryMaker::NoConstraint
208 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
209 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
210 {
211 albums.append( album );
212 break;
213 }
214 }
215 }
216
217 albums = MemoryQueryMakerHelper::orderListByName<Meta::AlbumPtr>( albums, m_orderDescending );
218
219 Q_EMIT newAlbumsReady( albums );
220 break;
221 }
222 case QueryMaker::Artist :
223 {
224 Meta::ArtistList artists;
225 Meta::ArtistList tmp = coll ? coll->artistMap().values() : Meta::ArtistList();
226 foreach( Meta::ArtistPtr artist, tmp )
227 {
228 Meta::TrackList tracks = artist->tracks();
229 foreach( Meta::TrackPtr track, tracks )
230 {
231 if( ( m_albumQueryMode == QueryMaker::AllAlbums
232 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && track->album()->isCompilation() )
233 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !track->album()->isCompilation()) ) &&
234 ( m_labelQueryMode == QueryMaker::NoConstraint
235 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
236 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
237 {
238 artists.append( artist );
239 break;
240 }
241 }
242 }
243 artists = MemoryQueryMakerHelper::orderListByName<Meta::ArtistPtr>( artists, m_orderDescending );
244 Q_EMIT newArtistsReady( artists );
245 break;
246 }
247 case QueryMaker::AlbumArtist :
248 {
249 Meta::ArtistList artists;
250 Meta::AlbumList tmp = coll ? coll->albumMap().values() : Meta::AlbumList();
251 foreach( Meta::AlbumPtr album, tmp )
252 {
253 if( !album->hasAlbumArtist() )
254 continue;
255
256 Meta::TrackList tracks = album->tracks();
257 foreach( Meta::TrackPtr track, tracks )
258 {
259 if( ( m_albumQueryMode == QueryMaker::AllAlbums
260 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && album->isCompilation() )
261 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !album->isCompilation()) ) &&
262 ( m_labelQueryMode == QueryMaker::NoConstraint
263 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
264 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
265 {
266 artists.append( album->albumArtist() );
267 break;
268 }
269 }
270 }
271 artists = MemoryQueryMakerHelper::orderListByName<Meta::ArtistPtr>( artists, m_orderDescending );
272 Q_EMIT newArtistsReady( artists );
273 break;
274 }
275 case QueryMaker::Composer :
276 {
277 Meta::ComposerList composers;
278 Meta::ComposerList tmp = coll ? coll->composerMap().values() : Meta::ComposerList();
279 foreach( Meta::ComposerPtr composer, tmp )
280 {
281 Meta::TrackList tracks = composer->tracks();
282 foreach( Meta::TrackPtr track, tracks )
283 {
284 if( ( m_albumQueryMode == QueryMaker::AllAlbums
285 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && track->album()->isCompilation() )
286 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !track->album()->isCompilation()) ) &&
287 ( m_labelQueryMode == QueryMaker::NoConstraint
288 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
289 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
290 {
291 composers.append( composer );
292 break;
293 }
294 }
295 }
296 composers = MemoryQueryMakerHelper::orderListByName<Meta::ComposerPtr>( composers, m_orderDescending );
297
298 Q_EMIT newComposersReady( composers );
299 break;
300 }
301 case QueryMaker::Genre :
302 {
303 Meta::GenreList genres;
304 Meta::GenreList tmp = coll ? coll->genreMap().values() : Meta::GenreList();
305 foreach( Meta::GenrePtr genre, tmp )
306 {
307 Meta::TrackList tracks = genre->tracks();
308 foreach( Meta::TrackPtr track, tracks )
309 {
310 if( ( m_albumQueryMode == QueryMaker::AllAlbums
311 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && track->album()->isCompilation() )
312 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !track->album()->isCompilation()) ) &&
313 ( m_labelQueryMode == QueryMaker::NoConstraint
314 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
315 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
316 {
317 genres.append( genre );
318 break;
319 }
320 }
321 }
322
323 genres = MemoryQueryMakerHelper::orderListByName<Meta::GenrePtr>( genres, m_orderDescending );
324
325 Q_EMIT newGenresReady( genres );
326 break;
327 }
328 case QueryMaker::Year :
329 {
330 Meta::YearList years;
331 Meta::YearList tmp = coll ? coll->yearMap().values() : Meta::YearList();
332 foreach( Meta::YearPtr year, tmp )
333 {
334 Meta::TrackList tracks = year->tracks();
335 foreach( Meta::TrackPtr track, tracks )
336 {
337 if( ( m_albumQueryMode == QueryMaker::AllAlbums
338 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && track->album()->isCompilation() )
339 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !track->album()->isCompilation()) ) &&
340 ( m_labelQueryMode == QueryMaker::NoConstraint
341 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
342 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
343 {
344 years.append( year );
345 break;
346 }
347 }
348 }
349
350 //this a special case which requires a bit of code duplication
351 //years have to be ordered as numbers, but orderListByNumber does not work for Meta::YearPtrs
352 if( m_orderByField == Meta::valYear )
353 {
354 years = MemoryQueryMakerHelper::orderListByYear( years, m_orderDescending );
355 }
356
357 Q_EMIT newYearsReady( years );
358 break;
359 }
360 case QueryMaker::Label:
361 {
362 Meta::LabelList labels;
363 Meta::LabelList tmp = coll ? coll->labelMap().values() : Meta::LabelList();
364 foreach( const Meta::LabelPtr &label, tmp )
365 {
366 Meta::TrackList tracks = coll ? coll->labelToTrackMap().value( label ) : Meta::TrackList();
367 foreach( const Meta::TrackPtr &track, tracks )
368 {
369 if( ( m_albumQueryMode == QueryMaker::AllAlbums
370 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && track->album()->isCompilation() )
371 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !track->album()->isCompilation()) ) &&
372 ( m_labelQueryMode == QueryMaker::NoConstraint
373 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
374 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
375 {
376 labels.append( label );
377 break;
378 }
379 }
380 }
381
382 labels = MemoryQueryMakerHelper::orderListByName<Meta::LabelPtr>( labels, m_orderDescending );
383
384 Q_EMIT newLabelsReady( labels );
385 break;
386 }
387 case QueryMaker::None :
388 //nothing to do
389 break;
390 }
391 }
392
393 void
handleResult(const Meta::TrackList & tmpTracks)394 MemoryQueryMakerInternal::handleResult( const Meta::TrackList &tmpTracks )
395 {
396 Meta::TrackList tracks;
397 foreach( const Meta::TrackPtr &track, tmpTracks )
398 {
399 if( ( m_albumQueryMode == QueryMaker::AllAlbums
400 || ( m_albumQueryMode == QueryMaker::OnlyCompilations && track->album()->isCompilation() )
401 || ( m_albumQueryMode == QueryMaker::OnlyNormalAlbums && !track->album()->isCompilation()) ) &&
402 ( m_labelQueryMode == QueryMaker::NoConstraint
403 || ( m_labelQueryMode == QueryMaker::OnlyWithLabels && track->labels().count() > 0 )
404 || ( m_labelQueryMode == QueryMaker::OnlyWithoutLabels && track->labels().isEmpty()) ) )
405 {
406 tracks.append( track );
407 }
408 }
409
410 switch( m_type )
411 {
412 case QueryMaker::Custom :
413 {
414 QStringList result;
415 if( !m_returnFunctions.empty() )
416 {
417 //no sorting necessary
418 foreach( CustomReturnFunction *function, m_returnFunctions )
419 {
420 result.append( function->value( tracks ) );
421 }
422 }
423 else if( !m_returnValues.empty() )
424 {
425 Meta::TrackList resultTracks = tracks;
426 if( m_orderByField )
427 {
428 if( m_orderByNumberField )
429 resultTracks = MemoryQueryMakerHelper::orderListByNumber( resultTracks, m_orderByField, m_orderDescending );
430 else
431 resultTracks = MemoryQueryMakerHelper::orderListByString( resultTracks, m_orderByField, m_orderDescending );
432 }
433
434 int count = 0;
435 foreach( const Meta::TrackPtr &track, resultTracks )
436 {
437 if ( m_maxSize >= 0 && count == m_maxSize )
438 break;
439
440 foreach( CustomReturnValue *value, m_returnValues )
441 {
442 result.append( value->value( track ) );
443 }
444 count++;
445 }
446 }
447 Q_EMIT newResultReady( result );
448 break;
449 }
450 case QueryMaker::Track :
451 {
452 Meta::TrackList newResult;
453
454 if( m_orderByField )
455 {
456 if( m_orderByNumberField )
457 newResult = MemoryQueryMakerHelper::orderListByNumber( tracks, m_orderByField, m_orderDescending );
458 else
459 newResult = MemoryQueryMakerHelper::orderListByString( tracks, m_orderByField, m_orderDescending );
460 }
461 else
462 newResult = tracks;
463
464 Q_EMIT newTracksReady( newResult );
465 break;
466 }
467 case QueryMaker::Album :
468 {
469 QSet<Meta::AlbumPtr> albumSet;
470 foreach( Meta::TrackPtr track, tracks )
471 {
472 albumSet.insert( track->album() );
473 }
474 Meta::AlbumList albumList = albumSet.toList();
475 albumList = MemoryQueryMakerHelper::orderListByName<Meta::AlbumPtr>( albumList, m_orderDescending );
476 Q_EMIT newAlbumsReady( albumList );
477 break;
478 }
479 case QueryMaker::Artist :
480 {
481 QSet<Meta::ArtistPtr> artistSet;
482 foreach( Meta::TrackPtr track, tracks )
483 {
484 artistSet.insert( track->artist() );
485 }
486 Meta::ArtistList list = artistSet.toList();
487 list = MemoryQueryMakerHelper::orderListByName<Meta::ArtistPtr>( list, m_orderDescending );
488 Q_EMIT newArtistsReady( list );
489 break;
490 }
491 case QueryMaker::AlbumArtist :
492 {
493 QSet<Meta::ArtistPtr> artistSet;
494 foreach( Meta::TrackPtr track, tracks )
495 {
496 if( !track->album().isNull() && track->album()->hasAlbumArtist() )
497 artistSet.insert( track->album()->albumArtist() );
498 }
499 Meta::ArtistList list = artistSet.toList();
500 list = MemoryQueryMakerHelper::orderListByName<Meta::ArtistPtr>( list, m_orderDescending );
501 Q_EMIT newArtistsReady( list );
502 break;
503 }
504 case QueryMaker::Genre :
505 {
506 QSet<Meta::GenrePtr> genreSet;
507 foreach( Meta::TrackPtr track, tracks )
508 {
509 genreSet.insert( track->genre() );
510 }
511 Meta::GenreList list = genreSet.toList();
512 list = MemoryQueryMakerHelper::orderListByName<Meta::GenrePtr>( list, m_orderDescending );
513 Q_EMIT newGenresReady( list );
514 break;
515 }
516 case QueryMaker::Composer :
517 {
518 QSet<Meta::ComposerPtr> composerSet;
519 foreach( Meta::TrackPtr track, tracks )
520 {
521 composerSet.insert( track->composer() );
522 }
523 Meta::ComposerList list = composerSet.toList();
524 list = MemoryQueryMakerHelper::orderListByName<Meta::ComposerPtr>( list, m_orderDescending );
525 Q_EMIT newComposersReady( list );
526 break;
527 }
528 case QueryMaker::Year :
529 {
530 QSet<Meta::YearPtr> yearSet;
531 foreach( Meta::TrackPtr track, tracks )
532 {
533 yearSet.insert( track->year() );
534 }
535 Meta::YearList years = yearSet.toList();
536 if( m_orderByField == Meta::valYear )
537 {
538 years = MemoryQueryMakerHelper::orderListByYear( years, m_orderDescending );
539 }
540
541 Q_EMIT newYearsReady( years );
542 break;
543 }
544 case QueryMaker::Label:
545 {
546 QSet<Meta::LabelPtr> labelSet;
547 foreach( const Meta::TrackPtr &track, tracks )
548 {
549 labelSet.unite( track->labels().toSet() );
550 }
551 Meta::LabelList labels = labelSet.toList();
552 if( m_orderByField == Meta::valLabel )
553 {
554 labels = MemoryQueryMakerHelper::orderListByName<Meta::LabelPtr>( labels, m_orderDescending );
555 }
556 Q_EMIT newLabelsReady( labels );
557 break;
558 }
559 case QueryMaker::None:
560 //should never happen, but handle error anyway
561 break;
562 }
563 }
564
565 void
setMatchers(MemoryMatcher * matchers)566 MemoryQueryMakerInternal::setMatchers( MemoryMatcher *matchers )
567 {
568 m_matchers = matchers;
569 }
570
571 void
setFilters(MemoryFilter * filters)572 MemoryQueryMakerInternal::setFilters( MemoryFilter *filters )
573 {
574 m_filters = filters;
575 }
576
577 void
setMaxSize(int maxSize)578 MemoryQueryMakerInternal::setMaxSize( int maxSize )
579 {
580 m_maxSize = maxSize;
581 }
582
583 void
setType(QueryMaker::QueryType type)584 MemoryQueryMakerInternal::setType( QueryMaker::QueryType type )
585 {
586 m_type = type;
587 }
588
589 void
setCustomReturnFunctions(const QList<CustomReturnFunction * > & functions)590 MemoryQueryMakerInternal::setCustomReturnFunctions( const QList<CustomReturnFunction *> &functions )
591 {
592 m_returnFunctions = functions;
593 }
594
595 void
setCustomReturnValues(const QList<CustomReturnValue * > & values)596 MemoryQueryMakerInternal::setCustomReturnValues( const QList<CustomReturnValue *> &values )
597 {
598 m_returnValues = values;
599 }
600
601 } //namespace Collections
602
603