1 /****************************************************************************************
2  * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org>                                *
3  * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com>            *
4  *                                                                                      *
5  * This program is free software; you can redistribute it and/or modify it under        *
6  * the terms of the GNU General Public License as published by the Free Software        *
7  * Foundation; either version 2 of the License, or (at your option) any later           *
8  * version.                                                                             *
9  *                                                                                      *
10  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
12  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
13  *                                                                                      *
14  * You should have received a copy of the GNU General Public License along with         *
15  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
16  ****************************************************************************************/
17 
18 #include "MemoryMatcher.h"
19 
20 using namespace Meta;
21 
MemoryMatcher()22 MemoryMatcher::MemoryMatcher()
23     : m_next( 0 )
24 {
25 }
26 
~MemoryMatcher()27 MemoryMatcher::~MemoryMatcher()
28 {
29     delete m_next;
30 }
31 
32 bool
isLast() const33 MemoryMatcher::isLast() const
34 {
35     return !m_next;
36 }
37 
38 MemoryMatcher*
next() const39 MemoryMatcher::next() const
40 {
41     return m_next;
42 }
43 
44 void
setNext(MemoryMatcher * next)45 MemoryMatcher::setNext( MemoryMatcher *next )
46 {
47     delete m_next;
48     m_next = next;
49 }
50 
TrackMatcher(const TrackPtr & track)51 TrackMatcher::TrackMatcher( const TrackPtr &track )
52     : MemoryMatcher()
53     , m_track( track )
54 {}
55 
match(Collections::MemoryCollection * memColl)56 TrackList TrackMatcher::match( Collections::MemoryCollection *memColl )
57 {
58     if( !m_track || !memColl )
59         return TrackList();
60     TrackMap trackMap = memColl->trackMap();
61     TrackList result;
62     if ( trackMap.contains( m_track->uidUrl()  ) )
63         result.append( trackMap.value( m_track->uidUrl() ) );
64     return result; //checking for another matcher is not necessary
65 }
66 
match(const TrackList & tracks)67 TrackList TrackMatcher::match( const TrackList &tracks )
68 {
69     if( !m_track )
70         return TrackList();
71     TrackList result;
72     QString url = m_track->uidUrl();
73     foreach( TrackPtr track, tracks )
74         if ( track->uidUrl() == url )
75         {
76             result.append( track );
77             break;
78         }
79     return result; //checking for another matcher is not necessary
80 }
81 
82 
83 
ArtistMatcher(const ArtistPtr & artist,Collections::QueryMaker::ArtistMatchBehaviour artistMode)84 ArtistMatcher::ArtistMatcher( const ArtistPtr &artist, Collections::QueryMaker::ArtistMatchBehaviour artistMode )
85     : MemoryMatcher()
86     , m_artist( artist )
87     , m_queryMode( artistMode )
88 {}
89 
match(Collections::MemoryCollection * memColl)90 TrackList ArtistMatcher::match( Collections::MemoryCollection *memColl )
91 {
92     if( !m_artist || !memColl )
93         return TrackList();
94 
95     if( !memColl->artistMap().contains( m_artist->name() ) )
96         return TrackList();
97 
98     ArtistPtr artist = memColl->artistMap().value( m_artist->name() );
99 
100     TrackList matchingTracks;
101     switch( m_queryMode )
102     {
103         case Collections::QueryMaker::AlbumOrTrackArtists:
104         case Collections::QueryMaker::AlbumArtists:
105             foreach( AlbumPtr album, memColl->albumMap() )
106                 if( album->albumArtist() == artist )
107                     matchingTracks.append( album->tracks() );
108             if( m_queryMode != Collections::QueryMaker::AlbumOrTrackArtists )
109                 break;
110             Q_FALLTHROUGH();
111         case Collections::QueryMaker::TrackArtists:
112             matchingTracks.append( artist->tracks() );
113     }
114 
115     if( isLast() || matchingTracks.isEmpty() )
116         return matchingTracks;
117     else
118         return next()->match( matchingTracks );
119 }
120 
121 
match(const TrackList & tracks)122 TrackList ArtistMatcher::match( const TrackList &tracks )
123 {
124     if( !m_artist )
125         return TrackList();
126     TrackList matchingTracks;
127     QString name = m_artist->name();
128     foreach( TrackPtr track, tracks )
129         switch( m_queryMode )
130         {
131             case Collections::QueryMaker::AlbumOrTrackArtists:
132             case Collections::QueryMaker::AlbumArtists:
133                 if( track->album()->hasAlbumArtist() &&
134                     track->album()->albumArtist()->name() == name )
135                     matchingTracks.append( track );
136                 if( m_queryMode != Collections::QueryMaker::AlbumOrTrackArtists )
137                     break;
138                 Q_FALLTHROUGH();
139             case Collections::QueryMaker::TrackArtists:
140                 if( track->artist()->name() == name )
141                     matchingTracks.append( track );
142         }
143 
144     if( isLast() || matchingTracks.isEmpty() )
145         return matchingTracks;
146     else
147         return next()->match( matchingTracks );
148 }
149 
150 
151 
AlbumMatcher(const AlbumPtr & album)152 AlbumMatcher::AlbumMatcher( const AlbumPtr &album )
153     : MemoryMatcher()
154     , m_album( album )
155 {}
156 
match(Collections::MemoryCollection * memColl)157 TrackList AlbumMatcher::match( Collections::MemoryCollection *memColl )
158 {
159     if( !m_album || !memColl )
160         return TrackList();
161     AlbumMap albumMap = memColl->albumMap();
162     if ( albumMap.contains( m_album ) ) // compares albums by value
163     {
164         AlbumPtr album = albumMap.value( m_album ); // compares albums by value, too
165         TrackList matchingTracks = album->tracks();
166         if ( isLast() )
167             return matchingTracks;
168         else
169             return next()->match( matchingTracks );
170     }
171     else
172         return TrackList();
173 }
174 
match(const TrackList & tracks)175 TrackList AlbumMatcher::match( const TrackList &tracks )
176 {
177     if( !m_album )
178         return TrackList();
179     TrackList matchingTracks;
180     QString name = m_album->name();
181     foreach( TrackPtr track, tracks )
182         if ( track->album()->name() == name )
183             matchingTracks.append( track );
184     if ( isLast() || matchingTracks.isEmpty())
185         return matchingTracks;
186     else
187         return next()->match( matchingTracks );
188 }
189 
190 
191 
GenreMatcher(const GenrePtr & genre)192 GenreMatcher::GenreMatcher( const GenrePtr &genre )
193     : MemoryMatcher()
194     , m_genre( genre )
195 {}
196 
match(Collections::MemoryCollection * memColl)197 TrackList GenreMatcher::match( Collections::MemoryCollection *memColl )
198 {
199     if( !m_genre || !memColl )
200         return TrackList();
201     GenreMap genreMap = memColl->genreMap();
202     if ( genreMap.contains( m_genre->name() ) )
203     {
204         GenrePtr genre = genreMap.value( m_genre->name() );
205         TrackList matchingTracks = genre->tracks();
206         if ( isLast() )
207             return matchingTracks;
208         else
209             return next()->match( matchingTracks );
210     }
211     else
212         return TrackList();
213 }
214 
match(const TrackList & tracks)215 TrackList GenreMatcher::match( const TrackList &tracks )
216 {
217     if( !m_genre )
218         return TrackList();
219     TrackList matchingTracks;
220     QString name = m_genre->name();
221     foreach( TrackPtr track, tracks )
222         if ( track->genre()->name() == name )
223             matchingTracks.append( track );
224     if ( isLast() || matchingTracks.isEmpty())
225         return matchingTracks;
226     else
227         return next()->match( matchingTracks );
228 }
229 
230 
231 
ComposerMatcher(const ComposerPtr & composer)232 ComposerMatcher::ComposerMatcher( const ComposerPtr &composer )
233     : MemoryMatcher()
234     , m_composer( composer )
235 {}
236 
match(Collections::MemoryCollection * memColl)237 TrackList ComposerMatcher::match( Collections::MemoryCollection *memColl )
238 {
239     if( !m_composer || !memColl )
240         return TrackList();
241     ComposerMap composerMap = memColl->composerMap();
242     if ( composerMap.contains( m_composer->name() ) )
243     {
244         ComposerPtr composer = composerMap.value( m_composer->name() );
245         TrackList matchingTracks = composer->tracks();
246         if ( isLast() )
247             return matchingTracks;
248         else
249             return next()->match( matchingTracks );
250     }
251     else
252         return TrackList();
253 }
254 
match(const TrackList & tracks)255 TrackList ComposerMatcher::match( const TrackList &tracks )
256 {
257     if( !m_composer )
258         return TrackList();
259     TrackList matchingTracks;
260     QString name = m_composer->name();
261     foreach( TrackPtr track, tracks )
262         if ( track->composer()->name() == name )
263             matchingTracks.append( track );
264     if ( isLast() || matchingTracks.isEmpty())
265         return matchingTracks;
266     else
267         return next()->match( matchingTracks );
268 }
269 
270 
271 
YearMatcher(const YearPtr & year)272 YearMatcher::YearMatcher( const YearPtr &year )
273     : MemoryMatcher()
274     , m_year( year )
275 {}
276 
match(Collections::MemoryCollection * memColl)277 TrackList YearMatcher::match( Collections::MemoryCollection *memColl )
278 {
279     if( !m_year || !memColl )
280         return TrackList();
281     YearMap yearMap = memColl->yearMap();
282     if ( yearMap.contains( m_year->year() ) )
283     {
284         YearPtr year = yearMap.value( m_year->year() );
285         TrackList matchingTracks = year->tracks();
286         if ( isLast() )
287             return matchingTracks;
288         else
289             return next()->match( matchingTracks );
290     }
291     else
292         return TrackList();
293 }
294 
match(const TrackList & tracks)295 TrackList YearMatcher::match( const TrackList &tracks )
296 {
297     if( !m_year )
298         return TrackList();
299     TrackList matchingTracks;
300     int year = m_year->year();
301     foreach( TrackPtr track, tracks )
302         if ( track->year()->year() == year )
303             matchingTracks.append( track );
304     if ( isLast() || matchingTracks.isEmpty())
305         return matchingTracks;
306     else
307         return next()->match( matchingTracks );
308 }
309 
LabelMatcher(const Meta::LabelPtr & label)310 LabelMatcher::LabelMatcher( const Meta::LabelPtr &label )
311     : MemoryMatcher()
312     , m_label( label )
313 {
314     //nothing to do
315 }
316 
317 Meta::TrackList
match(const Meta::TrackList & tracks)318 LabelMatcher::match( const Meta::TrackList &tracks )
319 {
320     if( !m_label )
321         return Meta::TrackList();
322 
323     Meta::TrackList matchingTracks;
324     QString name = m_label->name();
325     //not really efficient...
326     foreach( const Meta::TrackPtr &track, tracks )
327     {
328         foreach( const Meta::LabelPtr &label, track->labels() )
329         {
330             if( name == label->name() )
331             {
332                 matchingTracks << track;
333                 break;
334             }
335         }
336     }
337     if( isLast() || matchingTracks.isEmpty() )
338         return matchingTracks;
339     else
340         return next()->match( matchingTracks );
341 }
342 
343 Meta::TrackList
match(Collections::MemoryCollection * memColl)344 LabelMatcher::match( Collections::MemoryCollection *memColl )
345 {
346     if( !m_label )
347         return Meta::TrackList();
348 
349     Meta::TrackList matchingTracks;
350 
351     if( memColl->labelMap().contains( m_label->name() ) )
352     {
353         //m_label might actually be a proxy label
354         Meta::LabelPtr realLabel = memColl->labelMap().value( m_label->name() );
355         matchingTracks = memColl->labelToTrackMap().value( realLabel );
356     }
357     if( isLast() || matchingTracks.isEmpty() )
358         return matchingTracks;
359     else
360         return next()->match( matchingTracks );
361 }
362 
363 
364 
365 
366 
367