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