added: initial work on mixed mode smart playlists
[xbmc:paulepanters-xbmc.git] / xbmc / SortFileItem.cpp
1 /*
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter
3  *      http://www.xboxmediacenter.com
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with GNU Make; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "stdafx.h"
23 #include "SortFileItem.h"
24 #include "Util.h"
25
26 inline int StartsWithToken(const CStdString& strLabel)
27 {
28   for (unsigned int i=0;i<g_advancedSettings.m_vecTokens.size();++i)
29   {
30     if (g_advancedSettings.m_vecTokens[i].size() < strLabel.size() && 
31         strnicmp(g_advancedSettings.m_vecTokens[i].c_str(), strLabel.c_str(), g_advancedSettings.m_vecTokens[i].size()) == 0)
32       return g_advancedSettings.m_vecTokens[i].size();
33   }
34   return 0;
35 }
36
37 // TODO:
38 // 1. See if the special case stuff can be moved out.  Problems are that you
39 //    have to keep the parent folder item separate from all other items in order
40 //    to guarantee correct sort order.
41 //
42 bool SSortFileItem::FileAscending(CFileItem *left, CFileItem *right)
43 {
44   // ignore the ".." item - that should always be on top
45   if (left->IsParentFolder()) return true;
46   if (right->IsParentFolder()) return false;
47   CURL lurl(left->m_strPath); CURL rurl(right->m_strPath);
48   int result = StringUtils::AlphaNumericCompare(lurl.GetFileNameWithoutPath().c_str(), rurl.GetFileNameWithoutPath().c_str());
49   if (result < 0) return true;
50   if (result > 0) return false;
51   return left->m_lStartOffset <= right->m_lStartOffset; // useful for .cue's in my music
52 }
53
54 bool SSortFileItem::FileDescending(CFileItem *left, CFileItem *right)
55 {
56   // ignore the ".." item - that should always be on top
57   if (left->IsParentFolder()) return true;
58   if (right->IsParentFolder()) return false;
59   CURL lurl(left->m_strPath); CURL rurl(right->m_strPath);
60   int result = StringUtils::AlphaNumericCompare(lurl.GetFileNameWithoutPath().c_str(), rurl.GetFileNameWithoutPath().c_str());
61   if (result < 0) return false;
62   if (result > 0) return true;
63   return left->m_lStartOffset >= right->m_lStartOffset;
64 }
65
66 bool SSortFileItem::SizeAscending(CFileItem *left, CFileItem *right)
67 {
68   // ignore the ".." item - that should always be on top
69   if (left->IsParentFolder()) return true;
70   if (right->IsParentFolder()) return false;
71   // only if they're both folders or both files do we do the full comparison
72   if (left->m_bIsFolder == right->m_bIsFolder)
73     return left->m_dwSize <= right->m_dwSize;
74   return left->m_bIsFolder;
75 }
76
77 bool SSortFileItem::SizeDescending(CFileItem *left, CFileItem *right)
78 {
79   // ignore the ".." item - that should always be on top
80   if (left->IsParentFolder()) return true;
81   if (right->IsParentFolder()) return false;
82   // only if they're both folders or both files do we do the full comparison
83   if (left->m_bIsFolder == right->m_bIsFolder)
84     return left->m_dwSize >= right->m_dwSize;
85   return left->m_bIsFolder;
86 }
87
88 bool SSortFileItem::DateAscending(CFileItem *left, CFileItem *right)
89 {
90   // ignore the ".." item - that should always be on top
91   if (left->IsParentFolder()) return true;
92   if (right->IsParentFolder()) return false;
93   if (left->m_bIsFolder == right->m_bIsFolder)
94   { // same category
95     if ( left->m_dateTime < right->m_dateTime ) return true;
96     if ( left->m_dateTime > right->m_dateTime ) return false;
97     // dates are the same, sort by label in reverse (as default sort
98     // method is descending for date, and ascending for label)
99     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) > 0;
100   }
101   return left->m_bIsFolder;
102 }
103
104 bool SSortFileItem::DateDescending(CFileItem *left, CFileItem *right)
105 {
106   // ignore the ".." item - that should always be on top
107   if (left->IsParentFolder()) return true;
108   if (right->IsParentFolder()) return false;
109   if (left->m_bIsFolder == right->m_bIsFolder)
110   { // same category
111     if ( left->m_dateTime < right->m_dateTime ) return false;
112     if ( left->m_dateTime > right->m_dateTime ) return true;
113     // dates are the same, sort by label in reverse (as default sort
114     // method is descending for date, and ascending for label)
115     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) < 0;
116   }
117   return left->m_bIsFolder;
118 }
119
120 bool SSortFileItem::DriveTypeAscending(CFileItem *left, CFileItem *right)
121 {
122   // ignore the ".." item - that should always be on top
123   if (left->IsParentFolder()) return true;
124   if (right->IsParentFolder()) return false;
125   if (left->m_bIsFolder == right->m_bIsFolder)
126   { // same category
127     if ( left->m_iDriveType < right->m_iDriveType ) return true;
128     if ( left->m_iDriveType > right->m_iDriveType ) return false;
129     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) <= 0;
130   }
131   return left->m_bIsFolder;
132 }
133
134 bool SSortFileItem::DriveTypeDescending(CFileItem *left, CFileItem *right)
135 {
136   // ignore the ".." item - that should always be on top
137   if (left->IsParentFolder()) return true;
138   if (right->IsParentFolder()) return false;
139   if (left->m_bIsFolder == right->m_bIsFolder)
140   { // same category
141     if ( left->m_iDriveType < right->m_iDriveType ) return false;
142     if ( left->m_iDriveType > right->m_iDriveType ) return true;
143     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) >= 0;
144   }
145   return left->m_bIsFolder;
146 }
147
148 bool SSortFileItem::LabelAscending(CFileItem *left, CFileItem *right)
149 {
150   // special items
151   if (left->IsParentFolder()) return true;
152   if (right->IsParentFolder()) return false;
153   // only if they're both folders or both files do we do the full comparison
154   if (left->m_bIsFolder == right->m_bIsFolder)
155     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(),right->GetLabel().c_str()) <= 0;
156   return left->m_bIsFolder;
157 }
158
159 bool SSortFileItem::LabelDescending(CFileItem *left, CFileItem *right)
160 {
161   // special items
162   if (left->IsParentFolder()) return true;
163   if (right->IsParentFolder()) return false;
164   // only if they're both folders or both files do we do the full comparison
165   if (left->m_bIsFolder == right->m_bIsFolder)
166     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(),right->GetLabel().c_str()) >= 0;
167   return left->m_bIsFolder;
168 }
169
170 bool SSortFileItem::LabelAscendingNoThe(CFileItem *left, CFileItem *right)
171 {
172   // special items
173   if (left->IsParentFolder()) return true;
174   if (right->IsParentFolder()) return false;
175   // only if they're both folders or both files do we do the full comparison
176   if (left->m_bIsFolder == right->m_bIsFolder)
177   {
178     char *l = (char *)left->GetLabel().c_str();
179     char *r = (char *)right->GetLabel().c_str();
180     l += StartsWithToken(left->GetLabel());
181     r += StartsWithToken(right->GetLabel());
182
183     return StringUtils::AlphaNumericCompare(l, r) <= 0;
184   }
185   return left->m_bIsFolder;
186 }
187
188 bool SSortFileItem::LabelDescendingNoThe(CFileItem *left, CFileItem *right)
189 {
190   // special items
191   if (left->IsParentFolder()) return true;
192   if (right->IsParentFolder()) return false;
193   // only if they're both folders or both files do we do the full comparison
194   if (left->m_bIsFolder == right->m_bIsFolder)
195   {
196     char *l = (char *)left->GetLabel().c_str();
197     char *r = (char *)right->GetLabel().c_str();
198     l += StartsWithToken(left->GetLabel());
199     r += StartsWithToken(right->GetLabel());
200
201     return StringUtils::AlphaNumericCompare(l, r) >= 0;
202   }
203   return left->m_bIsFolder;
204 }
205
206 bool SSortFileItem::SongTrackNumAscending(CFileItem *left, CFileItem *right)
207 {
208   // special items
209   if (left->IsParentFolder()) return true;
210   if (right->IsParentFolder()) return false;
211   // only if they're both folders or both files do we do the full comparison
212   if (left->m_bIsFolder == right->m_bIsFolder)
213     return left->GetMusicInfoTag()->GetTrackAndDiskNumber() <= right->GetMusicInfoTag()->GetTrackAndDiskNumber();
214   return left->m_bIsFolder;
215 }
216
217 bool SSortFileItem::SongTrackNumDescending(CFileItem *left, CFileItem *right)
218 {
219   // special items
220   if (left->IsParentFolder()) return true;
221   if (right->IsParentFolder()) return false;
222   // only if they're both folders or both files do we do the full comparison
223   if (left->m_bIsFolder == right->m_bIsFolder)
224     return left->GetMusicInfoTag()->GetTrackAndDiskNumber() >= right->GetMusicInfoTag()->GetTrackAndDiskNumber();
225   return left->m_bIsFolder;
226 }
227
228 bool SSortFileItem::EpisodeNumAscending(CFileItem *left, CFileItem *right)
229 {
230   // special items
231   if (left->IsParentFolder()) return true;
232   if (right->IsParentFolder()) return false;
233   // only if they're both folders or both files do we do the full comparison
234   if (left->m_bIsFolder == right->m_bIsFolder)
235   {
236     // we calculate an offset number based on the episode's
237     // sort season and episode values. in addition
238     // we include specials 'episode' numbers to get proper
239     // sorting of multiple specials in a row. each
240     // of these are given their particular ranges to semi-ensure uniqueness.
241     // theoretical problem: if a show has > 128 specials and two of these are placed
242     // after each other they will sort backwards. if a show has > 2^8-1 seasons
243     // or if a season has > 2^16-1 episodes strange things will happen (overflow)
244     unsigned int il;
245     unsigned int ir;
246     if (left->GetVideoInfoTag()->m_iSpecialSortEpisode > 0)
247       il = (left->GetVideoInfoTag()->m_iSpecialSortSeason<<24)+(left->GetVideoInfoTag()->m_iSpecialSortEpisode<<8)-(128-left->GetVideoInfoTag()->m_iEpisode);
248     else
249       il = (left->GetVideoInfoTag()->m_iSeason<<24)+(left->GetVideoInfoTag()->m_iEpisode<<8);
250     if (right->GetVideoInfoTag()->m_iSpecialSortEpisode > 0)
251       ir = (right->GetVideoInfoTag()->m_iSpecialSortSeason<<24)+(right->GetVideoInfoTag()->m_iSpecialSortEpisode<<8)-(128-right->GetVideoInfoTag()->m_iEpisode);
252     else
253       ir = (right->GetVideoInfoTag()->m_iSeason<<24)+(right->GetVideoInfoTag()->m_iEpisode<<8);
254     return il <= ir;
255   }
256   return left->m_bIsFolder;
257 }
258
259 bool SSortFileItem::EpisodeNumDescending(CFileItem *left, CFileItem *right)
260 {
261   // special items
262   if (left->IsParentFolder()) return true;
263   if (right->IsParentFolder()) return false;
264   // only if they're both folders or both files do we do the full comparison
265   if (left->m_bIsFolder == right->m_bIsFolder)
266   {
267     unsigned int il;
268     unsigned int ir;
269     if (left->GetVideoInfoTag()->m_iSpecialSortEpisode > 0)
270       il = (left->GetVideoInfoTag()->m_iSpecialSortSeason<<24)+(left->GetVideoInfoTag()->m_iSpecialSortEpisode<<8)-(128-left->GetVideoInfoTag()->m_iEpisode);
271     else
272       il = (left->GetVideoInfoTag()->m_iSeason<<24)+(left->GetVideoInfoTag()->m_iEpisode<<8);
273     if (right->GetVideoInfoTag()->m_iSpecialSortEpisode > 0)
274       ir = (right->GetVideoInfoTag()->m_iSpecialSortSeason<<24)+(right->GetVideoInfoTag()->m_iSpecialSortEpisode<<8)-(128-right->GetVideoInfoTag()->m_iEpisode);
275     else
276       ir = (right->GetVideoInfoTag()->m_iSeason<<24)+(right->GetVideoInfoTag()->m_iEpisode<<8);
277     return il >= ir;
278   }
279   return left->m_bIsFolder;
280 }
281
282 bool SSortFileItem::SongDurationAscending(CFileItem *left, CFileItem *right)
283 {
284   // special items
285   if (left->IsParentFolder()) return true;
286   if (right->IsParentFolder()) return false;
287   // only if they're both folders or both files do we do the full comparison
288   if (left->m_bIsFolder == right->m_bIsFolder)
289     return left->GetMusicInfoTag()->GetDuration() <= right->GetMusicInfoTag()->GetDuration();
290   return left->m_bIsFolder;
291 }
292
293 bool SSortFileItem::SongDurationDescending(CFileItem *left, CFileItem *right)
294 {
295   // special items
296   if (left->IsParentFolder()) return true;
297   if (right->IsParentFolder()) return false;
298   // only if they're both folders or both files do we do the full comparison
299   if (left->m_bIsFolder == right->m_bIsFolder)
300     return left->GetMusicInfoTag()->GetDuration() >= right->GetMusicInfoTag()->GetDuration();
301   return left->m_bIsFolder;
302 }
303
304 bool SSortFileItem::SongTitleAscending(CFileItem *left, CFileItem *right)
305 {
306   // special cases
307   if (left->IsParentFolder()) return true;
308   if (right->IsParentFolder()) return false;
309   // only if they're both folders or both files do we do the full comparison
310   if (left->m_bIsFolder == right->m_bIsFolder)
311   {
312     char *l = (char *)left->GetMusicInfoTag()->GetTitle().c_str();
313     char *r = (char *)right->GetMusicInfoTag()->GetTitle().c_str();
314     return StringUtils::AlphaNumericCompare(l, r) <= 0;
315   }
316   return left->m_bIsFolder;
317 }
318
319 bool SSortFileItem::SongTitleDescending(CFileItem *left, CFileItem *right)
320 {
321   // special cases
322   if (left->IsParentFolder()) return true;
323   if (right->IsParentFolder()) return false;
324   // only if they're both folders or both files do we do the full comparison
325   if (left->m_bIsFolder == right->m_bIsFolder)
326   {
327     char *l = (char *)left->GetMusicInfoTag()->GetTitle().c_str();
328     char *r = (char *)right->GetMusicInfoTag()->GetTitle().c_str();
329     return StringUtils::AlphaNumericCompare(l, r) >= 0;
330   }
331   return left->m_bIsFolder;
332 }
333
334 bool SSortFileItem::MovieTitleAscending(CFileItem *left, CFileItem *right)
335 {
336   // special cases
337   if (left->IsParentFolder()) return true;
338   if (right->IsParentFolder()) return false;
339   // only if they're both folders or both files do we do the full comparison
340   if (left->m_bIsFolder == right->m_bIsFolder)
341   {
342     char *l = (char *)left->GetVideoInfoTag()->m_strTitle.c_str();
343     char *r = (char *)right->GetVideoInfoTag()->m_strTitle.c_str();
344     return StringUtils::AlphaNumericCompare(l, r) <= 0;
345   }
346   return left->m_bIsFolder;
347 }
348
349 bool SSortFileItem::MovieTitleDescending(CFileItem *left, CFileItem *right)
350 {
351   // special cases
352   if (left->IsParentFolder()) return true;
353   if (right->IsParentFolder()) return false;
354   // only if they're both folders or both files do we do the full comparison
355   if (left->m_bIsFolder == right->m_bIsFolder)
356   {
357     char *l = (char *)left->GetVideoInfoTag()->m_strTitle.c_str();
358     char *r = (char *)right->GetVideoInfoTag()->m_strTitle.c_str();
359     return StringUtils::AlphaNumericCompare(l, r) >= 0;
360   }
361   return left->m_bIsFolder;
362 }
363
364 bool SSortFileItem::SongTitleAscendingNoThe(CFileItem *left, CFileItem *right)
365 {
366   // special cases
367   if (left->IsParentFolder()) return true;
368   if (right->IsParentFolder()) return false;
369   // only if they're both folders or both files do we do the full comparison
370   if (left->m_bIsFolder == right->m_bIsFolder)
371   {
372     char *l = (char *)left->GetMusicInfoTag()->GetTitle().c_str();
373     char *r = (char *)right->GetMusicInfoTag()->GetTitle().c_str();
374     l += StartsWithToken(left->GetMusicInfoTag()->GetTitle());
375     r += StartsWithToken(right->GetMusicInfoTag()->GetTitle());
376     
377     return StringUtils::AlphaNumericCompare(l, r) <= 0;
378   }
379   return left->m_bIsFolder;
380 }
381
382 bool SSortFileItem::SongTitleDescendingNoThe(CFileItem *left, CFileItem *right)
383 {
384   // special cases
385   if (left->IsParentFolder()) return true;
386   if (right->IsParentFolder()) return false;
387   // only if they're both folders or both files do we do the full comparison
388   if (left->m_bIsFolder == right->m_bIsFolder)
389   {
390     char *l = (char *)left->GetMusicInfoTag()->GetTitle().c_str();
391     char *r = (char *)right->GetMusicInfoTag()->GetTitle().c_str();
392     l += StartsWithToken(left->GetMusicInfoTag()->GetTitle());
393     r += StartsWithToken(right->GetMusicInfoTag()->GetTitle());
394     
395     return StringUtils::AlphaNumericCompare(l, r) >= 0;
396   }
397   return left->m_bIsFolder;
398 }
399
400 bool SSortFileItem::SongArtistAscending(CFileItem *left, CFileItem *right)
401 {
402   // special cases
403   if (left->IsParentFolder()) return true;
404   if (right->IsParentFolder()) return false;
405   // only if they're both folders or both files do we do the full comparison
406   if (left->m_bIsFolder == right->m_bIsFolder)
407   {
408     char *l;
409     CStdString strL;
410     if (left->HasMusicInfoTag())
411       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
412     else if (left->HasVideoInfoTag())
413     {
414       strL = left->GetVideoInfoTag()->GetArtist();
415       l = (char*)strL.c_str();
416     }
417     else
418       l = (char*)strL.c_str();
419     char *r;
420     CStdString strR;
421     if (right->HasMusicInfoTag())
422       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
423     else if (right->HasVideoInfoTag())
424     {
425       strR = right->GetVideoInfoTag()->GetArtist();
426       r = (char*)strR.c_str();
427     }
428     else
429       r = (char*)strR.c_str();
430     int result = StringUtils::AlphaNumericCompare(l, r);
431     if (result < 0) return true;
432     if (result > 0) return false;
433     // test year
434     if (g_advancedSettings.m_bMusicLibraryAlbumsSortByArtistThenYear)
435     {
436       if (left->HasMusicInfoTag())
437         l = (char *)left->GetMusicInfoTag()->GetYear().c_str();
438       else if (left->HasVideoInfoTag())
439       {
440         strL.Format("%i",left->GetVideoInfoTag()->m_iYear);
441         l = (char*)strL.c_str();
442       }
443       if (right->HasMusicInfoTag())
444         r = (char *)right->GetMusicInfoTag()->GetYear().c_str();
445       else if (right->HasVideoInfoTag())
446       {
447         strR.Format("%i",right->GetVideoInfoTag()->m_iYear);
448         r = (char*)strR.c_str();
449       }     
450       result = StringUtils::AlphaNumericCompare(l, r);
451       if (result < 0) return true;
452       if (result > 0) return false;
453     }
454     // artists agree, test the album
455     if (left->HasMusicInfoTag())
456       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
457     else if (left->HasVideoInfoTag())
458     {
459       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
460     }
461     if (right->HasMusicInfoTag())
462       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
463     else if (right->HasVideoInfoTag())
464     {
465       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
466     }
467
468     result = StringUtils::AlphaNumericCompare(l, r);
469     if (result < 0) return true;
470     if (result > 0) return false;
471     // artist and album agree, test the track number
472     int lt = 0, rt=0;
473     if (left->HasMusicInfoTag())
474       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
475     if (right->HasMusicInfoTag())
476       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
477     
478     return lt <= rt;
479   }
480   return left->m_bIsFolder;
481 }
482
483 bool SSortFileItem::SongArtistDescending(CFileItem *left, CFileItem *right)
484 {
485   // special cases
486   if (left->IsParentFolder()) return true;
487   if (right->IsParentFolder()) return false;
488   // only if they're both folders or both files do we do the full comparison
489   if (left->m_bIsFolder == right->m_bIsFolder)
490   {
491     char *l;
492     CStdString strL;
493     if (left->HasMusicInfoTag())
494       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
495     else if (left->HasVideoInfoTag())
496     {
497       strL = left->GetVideoInfoTag()->GetArtist();
498       l = (char*)strL.c_str();
499     }
500     else
501       l = (char*)strL.c_str();
502     char *r;
503     CStdString strR;
504     if (right->HasMusicInfoTag())
505       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
506     else if (right->HasVideoInfoTag())
507     {
508       strR = right->GetVideoInfoTag()->GetArtist();
509       r = (char*)strR.c_str();
510     }
511     else
512       r = (char*)strR.c_str();
513
514     int result = StringUtils::AlphaNumericCompare(l, r);
515     if (result > 0) return true;
516     if (result < 0) return false;
517     // test year
518     if (g_advancedSettings.m_bMusicLibraryAlbumsSortByArtistThenYear)
519     {
520       if (left->HasMusicInfoTag())
521         l = (char *)left->GetMusicInfoTag()->GetYear().c_str();
522       else if (left->HasVideoInfoTag())
523       {
524         strL.Format("%i",left->GetVideoInfoTag()->m_iYear);
525         l = (char*)strL.c_str();
526       }
527       if (right->HasMusicInfoTag())
528         r = (char *)right->GetMusicInfoTag()->GetYear().c_str();
529       else if (right->HasVideoInfoTag())
530       {
531         strR.Format("%i",right->GetVideoInfoTag()->m_iYear);
532         r = (char*)strR.c_str();
533       }     
534       result = StringUtils::AlphaNumericCompare(l, r);
535       if (result > 0) return true;
536       if (result < 0) return false;
537     }
538     // artists agree, test the album
539     if (left->HasMusicInfoTag())
540       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
541     else if (left->HasVideoInfoTag())
542     {
543       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
544     }
545     if (right->HasMusicInfoTag())
546       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
547     else if (right->HasVideoInfoTag())
548     {
549       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
550     }
551
552     result = StringUtils::AlphaNumericCompare(l, r);
553     if (result > 0) return true;
554     if (result < 0) return false;
555     // artist and album agree, test the track number
556     int lt = 0, rt=0;
557     if (left->HasMusicInfoTag())
558       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
559     if (right->HasMusicInfoTag())
560       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
561     
562     return rt <= lt;
563   }
564   return left->m_bIsFolder;
565 }
566
567 bool SSortFileItem::SongArtistAscendingNoThe(CFileItem *left, CFileItem *right)
568 {
569   // special cases
570   if (left->IsParentFolder()) return true;
571   if (right->IsParentFolder()) return false;
572   // only if they're both folders or both files do we do the full comparison
573   if (left->m_bIsFolder == right->m_bIsFolder)
574   {
575     char *l;
576     CStdString strL;
577     if (left->HasMusicInfoTag())
578       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
579     else if (left->HasVideoInfoTag())
580     {
581       strL = left->GetVideoInfoTag()->GetArtist();
582       l = (char*)strL.c_str();
583     }
584     else
585       l = (char*)strL.c_str();
586     char *r;
587     CStdString strR;
588     if (right->HasMusicInfoTag())
589       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
590     else if (right->HasVideoInfoTag())
591     {
592       strR = right->GetVideoInfoTag()->GetArtist();
593       r = (char*)strR.c_str();
594     }
595     else
596       r = (char*)strR.c_str();
597     l += StartsWithToken(l);
598     r += StartsWithToken(r);
599
600     int result = StringUtils::AlphaNumericCompare(l, r);
601     if (result < 0) return true;
602     if (result > 0) return false;
603     // test year
604     if (g_advancedSettings.m_bMusicLibraryAlbumsSortByArtistThenYear)
605     {
606       if (left->HasMusicInfoTag())
607         l = (char *)left->GetMusicInfoTag()->GetYear().c_str();
608       else if (left->HasVideoInfoTag())
609       {
610         strL.Format("%i",left->GetVideoInfoTag()->m_iYear);
611         l = (char*)strL.c_str();
612       }
613       if (right->HasMusicInfoTag())
614         r = (char *)right->GetMusicInfoTag()->GetYear().c_str();
615       else if (right->HasVideoInfoTag())
616       {
617         strR.Format("%i",right->GetVideoInfoTag()->m_iYear);
618         r = (char*)strR.c_str();
619       }     
620
621       result = StringUtils::AlphaNumericCompare(l, r);
622       if (result < 0) return true;
623       if (result > 0) return false;
624     }
625     // artists agree, test the album
626     if (left->HasMusicInfoTag())
627       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
628     else if (left->HasVideoInfoTag())
629       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
630     if (right->HasMusicInfoTag())
631       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
632     else if (right->HasVideoInfoTag())
633       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
634
635     l += StartsWithToken(l);
636     r += StartsWithToken(r);
637
638     result = StringUtils::AlphaNumericCompare(l, r);
639     if (result < 0) return true;
640     if (result > 0) return false;
641     // artist and album agree, test the track number
642     int lt = 0, rt=0;
643     if (left->HasMusicInfoTag())
644       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
645     if (right->HasMusicInfoTag())
646       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
647     return lt <= rt;
648   }
649   return left->m_bIsFolder;
650 }
651
652 bool SSortFileItem::SongArtistDescendingNoThe(CFileItem *left, CFileItem *right)
653 {
654   // special cases
655   if (left->IsParentFolder()) return true;
656   if (right->IsParentFolder()) return false;
657   // only if they're both folders or both files do we do the full comparison
658   if (left->m_bIsFolder == right->m_bIsFolder)
659   {
660     char *l;
661     CStdString strL;
662     if (left->HasMusicInfoTag())
663       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
664     else if (left->HasVideoInfoTag())
665     {
666       strL = left->GetVideoInfoTag()->GetArtist();
667       l = (char*)strL.c_str();
668     }
669     else
670       l = (char*)strL.c_str();
671     char *r;
672     CStdString strR;
673     if (right->HasMusicInfoTag())
674       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
675     else if (right->HasVideoInfoTag())
676     {
677       strR = right->GetVideoInfoTag()->GetArtist();
678       r = (char*)strR.c_str();
679     }
680     else
681       r = (char*)strR.c_str();
682     l += StartsWithToken(l);
683     r += StartsWithToken(r);
684
685     int result = StringUtils::AlphaNumericCompare(l, r);
686     if (result > 0) return true;
687     if (result < 0) return false;
688     // test year
689     if (g_advancedSettings.m_bMusicLibraryAlbumsSortByArtistThenYear)
690     {
691       if (left->HasMusicInfoTag())
692         l = (char *)left->GetMusicInfoTag()->GetYear().c_str();
693       else if (left->HasVideoInfoTag())
694       {
695         strL.Format("%i",left->GetVideoInfoTag()->m_iYear);
696         l = (char*)strL.c_str();
697       }
698       if (right->HasMusicInfoTag())
699         r = (char *)right->GetMusicInfoTag()->GetYear().c_str();
700       else if (right->HasVideoInfoTag())
701       {
702         strR.Format("%i",right->GetVideoInfoTag()->m_iYear);
703         r = (char*)strR.c_str();
704       }     
705
706       result = StringUtils::AlphaNumericCompare(l, r);
707       if (result > 0) return true;
708       if (result < 0) return false;
709     }
710     // artists agree, test the album
711     if (left->HasMusicInfoTag())
712       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
713     else if (left->HasVideoInfoTag())
714       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
715     if (right->HasMusicInfoTag())
716       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
717     else if (right->HasVideoInfoTag())
718       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
719
720     l += StartsWithToken(l);
721     r += StartsWithToken(r);
722
723     result = StringUtils::AlphaNumericCompare(l, r);
724     if (result > 0) return true;
725     if (result < 0) return false;
726     // artist and album agree, test the track number
727     int lt = 0, rt=0;
728     if (left->HasMusicInfoTag())
729       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
730     if (right->HasMusicInfoTag())
731       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
732     return rt <= lt;
733   }
734   return left->m_bIsFolder;}
735
736 bool SSortFileItem::SongAlbumAscending(CFileItem *left, CFileItem *right)
737 {
738   // special cases
739   if (left->IsParentFolder()) return true;
740   if (right->IsParentFolder()) return false;
741   // only if they're both folders or both files do we do the full comparison
742   if (left->m_bIsFolder == right->m_bIsFolder)
743   {
744     char *l;
745     CStdString strL;
746     if (left->HasMusicInfoTag())
747       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
748     else if (left->HasVideoInfoTag())
749       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
750     else
751       l = (char*)strL.c_str();
752     char *r;
753     CStdString strR;
754     if (right->HasMusicInfoTag())
755       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
756     else if (right->HasVideoInfoTag())
757       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
758     else
759       r = (char*)strR.c_str();
760     int result = StringUtils::AlphaNumericCompare(l, r);
761     if (result < 0) return true;
762     if (result > 0) return false;
763     // album names match, try the artist
764     if (left->HasMusicInfoTag())
765       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
766     else if (left->HasVideoInfoTag())
767     {
768       strL = left->GetVideoInfoTag()->GetArtist();
769       l = (char*)strL.c_str();
770     }
771     if (right->HasMusicInfoTag())
772       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
773     else if (right->HasVideoInfoTag())
774     {
775       strR = right->GetVideoInfoTag()->GetArtist();
776       r = (char*)strR.c_str();
777     }
778     result = StringUtils::AlphaNumericCompare(l, r);
779     if (result < 0) return true;
780     if (result > 0) return false;
781     // album and artist match - sort by track
782     int lt = 0, rt=0;
783     if (left->HasMusicInfoTag())
784       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
785     if (right->HasMusicInfoTag())
786       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
787     return lt <= rt;
788   }
789   return left->m_bIsFolder;
790 }
791
792 bool SSortFileItem::SongAlbumDescending(CFileItem *left, CFileItem *right)
793 {
794   // special cases
795   if (left->IsParentFolder()) return true;
796   if (right->IsParentFolder()) return false;
797   // only if they're both folders or both files do we do the full comparison
798   if (left->m_bIsFolder == right->m_bIsFolder)
799   {
800     char *l;
801     CStdString strL;
802     if (left->HasMusicInfoTag())
803       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
804     else if (left->HasVideoInfoTag())
805       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
806     else
807       l = (char*)strL.c_str();
808     char *r;
809     CStdString strR;
810     if (right->HasMusicInfoTag())
811       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
812     else if (right->HasVideoInfoTag())
813       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
814     else
815       r = (char*)strR.c_str();
816     int result = StringUtils::AlphaNumericCompare(l, r);
817     if (result > 0) return true;
818     if (result < 0) return false;
819     // album names match, try the artist
820     if (left->HasMusicInfoTag())
821       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
822     else if (left->HasVideoInfoTag())
823     {
824       strL = left->GetVideoInfoTag()->GetArtist();
825       l = (char*)strL.c_str();
826     }
827     if (right->HasMusicInfoTag())
828       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
829     else if (right->HasVideoInfoTag())
830     {
831       strR = right->GetVideoInfoTag()->GetArtist();
832       r = (char*)strR.c_str();
833     }
834     result = StringUtils::AlphaNumericCompare(l, r);
835     if (result > 0) return true;
836     if (result < 0) return false;
837     // album and artist match - sort by track
838     int lt = 0, rt=0;
839     if (left->HasMusicInfoTag())
840       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
841     if (right->HasMusicInfoTag())
842       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
843     return rt <= lt;
844   }
845   return left->m_bIsFolder;
846 }
847
848 bool SSortFileItem::SongAlbumAscendingNoThe(CFileItem *left, CFileItem *right)
849 {
850   // special cases
851   if (left->IsParentFolder()) return true;
852   if (right->IsParentFolder()) return false;
853   // only if they're both folders or both files do we do the full comparison
854   if (left->m_bIsFolder == right->m_bIsFolder)
855   {
856     char *l;
857     CStdString strL;
858     if (left->HasMusicInfoTag())
859       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
860     else if (left->HasVideoInfoTag())
861       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
862     else
863       l = (char*)strL.c_str();
864     char *r;
865     CStdString strR;
866     if (right->HasMusicInfoTag())
867       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
868     else if (right->HasVideoInfoTag())
869       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
870     else
871       r = (char*)strR.c_str();
872     l += StartsWithToken(l);
873     r += StartsWithToken(r);
874
875     int result = StringUtils::AlphaNumericCompare(l, r);
876     if (result < 0) return true;
877     if (result > 0) return false;
878     // album names match, try the artist
879     if (left->HasMusicInfoTag())
880       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
881     else if (left->HasVideoInfoTag())
882     {
883       strL = left->GetVideoInfoTag()->GetArtist();
884       l = (char*)strL.c_str();
885     }
886     if (right->HasMusicInfoTag())
887       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
888     else if (right->HasVideoInfoTag())
889     {
890       strR = right->GetVideoInfoTag()->GetArtist();
891       r = (char*)strR.c_str();
892     }
893     l += StartsWithToken(l);
894     r += StartsWithToken(r);
895
896     result = StringUtils::AlphaNumericCompare(l, r);
897     if (result < 0) return true;
898     if (result > 0) return false;
899     // album and artist match - sort by track
900     int lt = 0, rt=0;
901     if (left->HasMusicInfoTag())
902       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
903     if (right->HasMusicInfoTag())
904       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
905
906     return lt <= rt;
907   }
908   return left->m_bIsFolder;
909 }
910
911 bool SSortFileItem::SongAlbumDescendingNoThe(CFileItem *left, CFileItem *right)
912 {
913   // special cases
914   if (left->IsParentFolder()) return true;
915   if (right->IsParentFolder()) return false;
916   // only if they're both folders or both files do we do the full comparison
917   if (left->m_bIsFolder == right->m_bIsFolder)
918   {
919     char *l;
920     CStdString strL;
921     if (left->HasMusicInfoTag())
922       l = (char *)left->GetMusicInfoTag()->GetAlbum().c_str();
923     else if (left->HasVideoInfoTag())
924       l = (char*)left->GetVideoInfoTag()->m_strAlbum.c_str();
925     else
926       l = (char*)strL.c_str();
927     char *r;
928     CStdString strR;
929     if (right->HasMusicInfoTag())
930       r = (char *)right->GetMusicInfoTag()->GetAlbum().c_str();
931     else if (right->HasVideoInfoTag())
932       r = (char*)right->GetVideoInfoTag()->m_strAlbum.c_str();
933     else
934       r = (char*)strR.c_str();
935     l += StartsWithToken(l);
936     r += StartsWithToken(r);
937
938     int result = StringUtils::AlphaNumericCompare(l, r);
939     if (result > 0) return true;
940     if (result < 0) return false;
941     // album names match, try the artist
942     if (left->HasMusicInfoTag())
943       l = (char *)left->GetMusicInfoTag()->GetArtist().c_str();
944     else if (left->HasVideoInfoTag())
945     {
946       strL = left->GetVideoInfoTag()->GetArtist();
947       l = (char*)strL.c_str();
948     }
949     if (right->HasMusicInfoTag())
950       r = (char *)right->GetMusicInfoTag()->GetArtist().c_str();
951     else if (right->HasVideoInfoTag())
952     {
953       strR = right->GetVideoInfoTag()->GetArtist();
954       r = (char*)strR.c_str();
955     }
956     l += StartsWithToken(l);
957     r += StartsWithToken(r);
958
959     result = StringUtils::AlphaNumericCompare(l, r);
960     if (result > 0) return true;
961     if (result < 0) return false;
962     // album and artist match - sort by track
963     int lt = 0, rt=0;
964     if (left->HasMusicInfoTag())
965       lt = left->GetMusicInfoTag()->GetTrackAndDiskNumber();
966     if (right->HasMusicInfoTag())
967       rt = right->GetMusicInfoTag()->GetTrackAndDiskNumber();
968
969     return rt <= lt;
970   }
971   return left->m_bIsFolder;
972 }
973
974 bool SSortFileItem::SongGenreAscending(CFileItem *left, CFileItem *right)
975 {
976   // special items
977   if (left->IsParentFolder()) return true;
978   if (right->IsParentFolder()) return false;
979   // only if they're both folders or both files do we do the full comparison
980   if (left->m_bIsFolder == right->m_bIsFolder)
981     return StringUtils::AlphaNumericCompare(left->GetMusicInfoTag()->GetGenre().c_str(),right->GetMusicInfoTag()->GetGenre().c_str()) <= 0;
982   return left->m_bIsFolder;
983 }
984
985 bool SSortFileItem::SongGenreDescending(CFileItem *left, CFileItem *right)
986 {
987   // special items
988   if (left->IsParentFolder()) return true;
989   if (right->IsParentFolder()) return false;
990   // only if they're both folders or both files do we do the full comparison
991   if (left->m_bIsFolder == right->m_bIsFolder)
992     return StringUtils::AlphaNumericCompare(left->GetMusicInfoTag()->GetGenre().c_str(),right->GetMusicInfoTag()->GetGenre().c_str()) >= 0;
993   return left->m_bIsFolder;
994 }
995
996 bool SSortFileItem::ProgramCountAscending(CFileItem *left, CFileItem *right)
997 {
998   // ignore the ".." item - that should always be on top
999   if (left->IsParentFolder()) return true;
1000   if (right->IsParentFolder()) return false;
1001   if (left->m_bIsFolder == right->m_bIsFolder)
1002     return left->m_iprogramCount <= right->m_iprogramCount;
1003   return left->m_bIsFolder;
1004 }
1005
1006 bool SSortFileItem::ProgramCountDescending(CFileItem *left, CFileItem *right)
1007 {
1008   // ignore the ".." item - that should always be on top
1009   if (left->IsParentFolder()) return true;
1010   if (right->IsParentFolder()) return false;
1011   if (left->m_bIsFolder == right->m_bIsFolder)
1012     return left->m_iprogramCount >= right->m_iprogramCount;
1013   return left->m_bIsFolder;
1014 }
1015
1016 bool SSortFileItem::MovieYearAscending(CFileItem *left, CFileItem *right)
1017 {
1018   // ignore the ".." item - that should always be on top
1019   if (left->IsParentFolder()) return true;
1020   if (right->IsParentFolder()) return false;
1021   if (left->m_bIsFolder == right->m_bIsFolder)
1022   {
1023     if (left->GetVideoInfoTag()->m_iYear > 0)
1024     {
1025       int result = left->GetVideoInfoTag()->m_iYear-right->GetVideoInfoTag()->m_iYear;
1026       if (result < 0) return true;
1027       if (result > 0) return false;
1028       return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) <= 0;
1029     }
1030     if (!left->GetVideoInfoTag()->m_strPremiered.IsEmpty())
1031       return StringUtils::AlphaNumericCompare(left->GetVideoInfoTag()->m_strPremiered.c_str(), right->GetVideoInfoTag()->m_strPremiered.c_str()) <= 0;
1032     if (!left->GetVideoInfoTag()->m_strFirstAired.IsEmpty())
1033       return StringUtils::AlphaNumericCompare(left->GetVideoInfoTag()->m_strFirstAired.c_str(), right->GetVideoInfoTag()->m_strFirstAired.c_str()) <= 0;
1034   }
1035   return left->m_bIsFolder;
1036 }
1037
1038 bool SSortFileItem::MovieYearDescending(CFileItem *left, CFileItem *right)
1039 {
1040   // ignore the ".." item - that should always be on top
1041   if (left->IsParentFolder()) return true;
1042   if (right->IsParentFolder()) return false;
1043   if (left->m_bIsFolder == right->m_bIsFolder)
1044   {
1045     if (left->GetVideoInfoTag()->m_iYear > 0)
1046     {
1047      int result = left->GetVideoInfoTag()->m_iYear-right->GetVideoInfoTag()->m_iYear;
1048      if (result < 0) return false;
1049      if (result > 0) return true;
1050      return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) >= 0;
1051     }
1052     if (!left->GetVideoInfoTag()->m_strPremiered.IsEmpty())
1053       return StringUtils::AlphaNumericCompare(left->GetVideoInfoTag()->m_strPremiered.c_str(), right->GetVideoInfoTag()->m_strPremiered.c_str()) >= 0;
1054     if (!left->GetVideoInfoTag()->m_strFirstAired.IsEmpty())
1055       return StringUtils::AlphaNumericCompare(left->GetVideoInfoTag()->m_strFirstAired.c_str(), right->GetVideoInfoTag()->m_strFirstAired.c_str()) >= 0;
1056   }
1057   return left->m_bIsFolder;
1058 }
1059
1060 bool SSortFileItem::ProductionCodeAscending(CFileItem *left, CFileItem *right)
1061 {
1062   // ignore the ".." item - that should always be on top
1063   if (left->IsParentFolder()) return true;
1064   if (right->IsParentFolder()) return false;
1065   if (left->m_bIsFolder == right->m_bIsFolder)
1066   {
1067     return StringUtils::AlphaNumericCompare(left->GetVideoInfoTag()->m_strProductionCode.c_str(),right->GetVideoInfoTag()->m_strProductionCode.c_str()) <= 0;
1068   }
1069   return left->m_bIsFolder;
1070 }
1071
1072 bool SSortFileItem::ProductionCodeDescending(CFileItem *left, CFileItem *right)
1073 {
1074   // ignore the ".." item - that should always be on top
1075   if (left->IsParentFolder()) return true;
1076   if (right->IsParentFolder()) return false;
1077   if (left->m_bIsFolder == right->m_bIsFolder)
1078   {
1079     return StringUtils::AlphaNumericCompare(left->GetVideoInfoTag()->m_strProductionCode.c_str(),right->GetVideoInfoTag()->m_strProductionCode.c_str()) >= 0;
1080   }
1081   return left->m_bIsFolder;
1082 }
1083
1084 bool SSortFileItem::MovieRatingAscending(CFileItem *left, CFileItem *right)
1085 {
1086   // ignore the ".." item - that should always be on top
1087   if (left->IsParentFolder()) return true;
1088   if (right->IsParentFolder()) return false;
1089   if (left->m_bIsFolder == right->m_bIsFolder)
1090   {
1091     if (left->m_fRating < right->m_fRating) return true;
1092     if (left->m_fRating > right->m_fRating) return false;
1093     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) <= 0;
1094   }
1095   return left->m_bIsFolder;
1096 }
1097
1098 bool SSortFileItem::MovieRatingDescending(CFileItem *left, CFileItem *right)
1099 {
1100   // ignore the ".." item - that should always be on top
1101   if (left->IsParentFolder()) return true;
1102   if (right->IsParentFolder()) return false;
1103   if (left->m_bIsFolder == right->m_bIsFolder)
1104   {
1105     if (left->m_fRating < right->m_fRating) return false;
1106     if (left->m_fRating > right->m_fRating) return true;
1107     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) >= 0;
1108   }
1109   return left->m_bIsFolder;
1110 }
1111
1112 bool SSortFileItem::MPAARatingAscending(CFileItem *left, CFileItem *right)
1113 {
1114   // ignore the ".." item - that should always be on top
1115   if (left->IsParentFolder()) return true;
1116   if (right->IsParentFolder()) return false;
1117   if (left->m_bIsFolder == right->m_bIsFolder)
1118   {
1119     if (left->GetVideoInfoTag()->m_strMPAARating < right->GetVideoInfoTag()->m_strMPAARating) return true;
1120     if (left->GetVideoInfoTag()->m_strMPAARating > right->GetVideoInfoTag()->m_strMPAARating) return false;
1121     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) <= 0;
1122   }
1123   return left->m_bIsFolder;
1124 }
1125
1126 bool SSortFileItem::MPAARatingDescending(CFileItem *left, CFileItem *right)
1127 {
1128   // ignore the ".." item - that should always be on top
1129   if (left->IsParentFolder()) return true;
1130   if (right->IsParentFolder()) return false;
1131   if (left->m_bIsFolder == right->m_bIsFolder)
1132   {
1133     if (left->GetVideoInfoTag()->m_strMPAARating < right->GetVideoInfoTag()->m_strMPAARating) return false;
1134     if (left->GetVideoInfoTag()->m_strMPAARating > right->GetVideoInfoTag()->m_strMPAARating) return true;
1135     return StringUtils::AlphaNumericCompare(left->GetLabel().c_str(), right->GetLabel().c_str()) >= 0;
1136   }
1137   return left->m_bIsFolder;
1138 }
1139
1140 bool SSortFileItem::SongRatingAscending(CFileItem *left, CFileItem *right)
1141 {
1142   // ignore the ".." item - that should always be on top
1143   if (left->IsParentFolder()) return true;
1144   if (right->IsParentFolder()) return false;
1145   if (left->m_bIsFolder == right->m_bIsFolder)
1146   {
1147     if (left->GetMusicInfoTag()->GetRating() < right->GetMusicInfoTag()->GetRating()) return true;
1148     if (left->GetMusicInfoTag()->GetRating() > right->GetMusicInfoTag()->GetRating()) return false;
1149     return StringUtils::AlphaNumericCompare(left->GetMusicInfoTag()->GetTitle().c_str(), right->GetMusicInfoTag()->GetTitle().c_str()) >= 0;
1150   }
1151   return left->m_bIsFolder;
1152 }
1153
1154 bool SSortFileItem::SongRatingDescending(CFileItem *left, CFileItem *right)
1155 {
1156   // ignore the ".." item - that should always be on top
1157   if (left->IsParentFolder()) return true;
1158   if (right->IsParentFolder()) return false;
1159   if (left->m_bIsFolder == right->m_bIsFolder)
1160   {
1161     // currently we just compare rating, then title
1162     if (left->GetMusicInfoTag()->GetRating() < right->GetMusicInfoTag()->GetRating()) return false;
1163     if (left->GetMusicInfoTag()->GetRating() > right->GetMusicInfoTag()->GetRating()) return true;
1164     return StringUtils::AlphaNumericCompare(left->GetMusicInfoTag()->GetTitle().c_str(), right->GetMusicInfoTag()->GetTitle().c_str()) <= 0;
1165   }
1166   return left->m_bIsFolder;
1167 }
1168
1169 bool SSortFileItem::MovieRuntimeAscending(CFileItem *left, CFileItem *right)
1170 {
1171   // special cases
1172   if (left->IsParentFolder()) return true;
1173   if (right->IsParentFolder()) return false;
1174   // only if they're both folders or both files do we do the full comparison
1175   if (left->m_bIsFolder == right->m_bIsFolder)
1176   {
1177     char *l = (char *)left->GetVideoInfoTag()->m_strRuntime.c_str();
1178     char *r = (char *)right->GetVideoInfoTag()->m_strRuntime.c_str();
1179     return StringUtils::AlphaNumericCompare(l, r) <= 0;
1180   }
1181   return left->m_bIsFolder;
1182 }
1183
1184 bool SSortFileItem::MovieRuntimeDescending(CFileItem *left, CFileItem *right)
1185 {
1186   // special cases
1187   if (left->IsParentFolder()) return true;
1188   if (right->IsParentFolder()) return false;
1189   // only if they're both folders or both files do we do the full comparison
1190   if (left->m_bIsFolder == right->m_bIsFolder)
1191   {
1192     char *l = (char *)left->GetVideoInfoTag()->m_strRuntime.c_str();
1193     char *r = (char *)right->GetVideoInfoTag()->m_strRuntime.c_str();
1194     return StringUtils::AlphaNumericCompare(l, r) >= 0;
1195   }
1196   return left->m_bIsFolder;
1197 }
1198
1199 bool SSortFileItem::StudioAscending(CFileItem *left, CFileItem *right)
1200 {
1201   // special cases
1202   if (left->IsParentFolder()) return true;
1203   if (right->IsParentFolder()) return false;
1204   // only if they're both folders or both files do we do the full comparison
1205   if (left->m_bIsFolder == right->m_bIsFolder)
1206   {
1207     char *l = (char *)left->GetVideoInfoTag()->m_strStudio.c_str();
1208     char *r = (char *)right->GetVideoInfoTag()->m_strStudio.c_str();
1209     return StringUtils::AlphaNumericCompare(l, r) <= 0;
1210   }
1211   return left->m_bIsFolder;
1212 }
1213
1214 bool SSortFileItem::StudioDescending(CFileItem *left, CFileItem *right)
1215 {
1216   // special cases
1217   if (left->IsParentFolder()) return true;
1218   if (right->IsParentFolder()) return false;
1219   // only if they're both folders or both files do we do the full comparison
1220   if (left->m_bIsFolder == right->m_bIsFolder)
1221   {
1222     char *l = (char *)left->GetVideoInfoTag()->m_strStudio.c_str();
1223     char *r = (char *)right->GetVideoInfoTag()->m_strStudio.c_str();
1224     return StringUtils::AlphaNumericCompare(l, r) >= 0;
1225   }
1226   return left->m_bIsFolder;
1227 }
1228
1229 bool SSortFileItem::StudioAscendingNoThe(CFileItem *left, CFileItem *right)
1230 {
1231   // special cases
1232   if (left->IsParentFolder()) return true;
1233   if (right->IsParentFolder()) return false;
1234   // only if they're both folders or both files do we do the full comparison
1235   if (left->m_bIsFolder == right->m_bIsFolder)
1236   {
1237     char *l = (char *)left->GetVideoInfoTag()->m_strStudio.c_str();
1238     char *r = (char *)right->GetVideoInfoTag()->m_strStudio.c_str();
1239     l += StartsWithToken(left->GetVideoInfoTag()->m_strStudio);
1240     r += StartsWithToken(right->GetVideoInfoTag()->m_strStudio);
1241     
1242     return StringUtils::AlphaNumericCompare(l, r) <= 0;
1243   }
1244   return left->m_bIsFolder;
1245 }
1246
1247 bool SSortFileItem::StudioDescendingNoThe(CFileItem *left, CFileItem *right)
1248 {
1249   // special cases
1250   if (left->IsParentFolder()) return true;
1251   if (right->IsParentFolder()) return false;
1252   // only if they're both folders or both files do we do the full comparison
1253   if (left->m_bIsFolder == right->m_bIsFolder)
1254   {
1255     char *l = (char *)left->GetVideoInfoTag()->m_strStudio.c_str();
1256     char *r = (char *)right->GetVideoInfoTag()->m_strStudio.c_str();
1257     l += StartsWithToken(left->GetVideoInfoTag()->m_strStudio);
1258     r += StartsWithToken(right->GetVideoInfoTag()->m_strStudio);
1259     
1260     return StringUtils::AlphaNumericCompare(l, r) >= 0;
1261   }
1262   return left->m_bIsFolder;
1263 }