Sort the playlist by album then by track number when sorting by album.
[vlc/pdherbemont.git] / src / playlist / sort.c
blob992b0357cb7662fd6b96aa2a145a34046e692041
1 /*****************************************************************************
2 * sort.c : Playlist sorting functions
3 *****************************************************************************
4 * Copyright (C) 1999-2007 the VideoLAN team
5 * $Id$
7 * Authors: Clément Stenac <zorglub@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc/vlc.h>
28 #include "vlc_playlist.h"
29 #include "playlist_internal.h"
32 static int playlist_ItemArraySort( playlist_t *p_playlist, int i_items,
33 playlist_item_t **pp_items, int i_mode,
34 int i_type );
36 /**
37 * Sort a node.
38 * This function must be entered with the playlist lock !
40 * \param p_playlist the playlist
41 * \param p_node the node to sort
42 * \param i_mode: SORT_ID, SORT_TITLE, SORT_ARTIST, SORT_ALBUM, SORT_RANDOM
43 * \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
44 * \return VLC_SUCCESS on success
46 static int playlist_NodeSort( playlist_t * p_playlist , playlist_item_t *p_node,
47 int i_mode, int i_type )
49 playlist_ItemArraySort( p_playlist,p_node->i_children,
50 p_node->pp_children, i_mode, i_type );
51 return VLC_SUCCESS;
54 /**
55 * Sort a node recursively.
57 * This function must be entered with the playlist lock !
59 * \param p_playlist the playlist
60 * \param p_node the node to sort
61 * \param i_mode: SORT_ID, SORT_TITLE, SORT_ARTIST, SORT_ALBUM, SORT_RANDOM
62 * \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
63 * \return VLC_SUCCESS on success
65 int playlist_RecursiveNodeSort( playlist_t *p_playlist, playlist_item_t *p_node,
66 int i_mode, int i_type )
68 int i;
69 playlist_NodeSort( p_playlist, p_node, i_mode, i_type );
70 for( i = 0 ; i< p_node->i_children; i++ )
72 if( p_node->pp_children[i]->i_children != -1 )
74 playlist_RecursiveNodeSort( p_playlist, p_node->pp_children[i],
75 i_mode,i_type );
78 return VLC_SUCCESS;
82 static int playlist_ItemArraySort( playlist_t *p_playlist, int i_items,
83 playlist_item_t **pp_items, int i_mode,
84 int i_type )
86 int i , i_small , i_position;
87 playlist_item_t *p_temp;
88 vlc_value_t val;
89 val.b_bool = VLC_TRUE;
91 (void)p_playlist; // a bit surprising we don't need p_playlist!
93 if( i_mode == SORT_RANDOM )
95 for( i_position = 0; i_position < i_items ; i_position ++ )
97 int i_new;
99 if( i_items > 1 )
100 i_new = rand() % (i_items - 1);
101 else
102 i_new = 0;
103 p_temp = pp_items[i_position];
104 pp_items[i_position] = pp_items[i_new];
105 pp_items[i_new] = p_temp;
108 return VLC_SUCCESS;
111 #define META_STRCASECMP_NAME( i, i_small ) { \
112 char *psz_i = input_item_GetName( pp_items[i]->p_input ); \
113 char *psz_ismall = input_item_GetName( pp_items[i_small]->p_input ); \
114 i_test = strcasecmp( psz_i, psz_ismall ); \
115 free( psz_i ); \
116 free( psz_ismall ); \
120 #define DO_META_SORT_ADV( node, integer ) { \
121 char *psz_a = input_item_GetMeta( pp_items[i]->p_input, vlc_meta_##node ); \
122 char *psz_b = input_item_GetMeta( pp_items[i_small]->p_input, vlc_meta_##node ); \
123 /* Nodes go first */ \
124 if( pp_items[i]->i_children == -1 && pp_items[i_small]->i_children >= 0 ) \
125 i_test = 1;\
126 else if( pp_items[i]->i_children >= 0 &&\
127 pp_items[i_small]->i_children == -1 ) \
128 i_test = -1; \
129 /* Both are nodes, sort by name */ \
130 else if( pp_items[i]->i_children >= 0 && \
131 pp_items[i_small]->i_children >= 0 ) \
133 META_STRCASECMP_NAME( i, i_small ) \
135 /* Both are items */ \
136 else if( psz_a == NULL && psz_b != NULL ) \
137 i_test = 1; \
138 else if( psz_a != NULL && psz_b == NULL ) \
139 i_test = -1;\
140 /* No meta, sort by name */ \
141 else if( psz_a == NULL && psz_b == NULL ) \
143 META_STRCASECMP_NAME( i, i_small ); \
145 else \
147 if( !integer ) i_test = strcmp( psz_a, psz_b ); \
148 else i_test = atoi( psz_a ) - atoi( psz_b ); \
150 free( psz_a ); \
151 free( psz_b ); \
153 #define DO_META_SORT( node ) DO_META_SORT_ADV( node, VLC_FALSE )
155 for( i_position = 0; i_position < i_items -1 ; i_position ++ )
157 i_small = i_position;
158 for( i = i_position + 1 ; i< i_items ; i++)
160 int i_test = 0;
162 if( i_mode == SORT_TITLE )
164 META_STRCASECMP_NAME( i, i_small );
166 else if( i_mode == SORT_TITLE_NUMERIC )
168 char *psz_i = input_item_GetName( pp_items[i]->p_input );
169 char *psz_ismall =
170 input_item_GetName( pp_items[i_small]->p_input );
171 i_test = atoi( psz_i ) - atoi( psz_ismall );
172 free( psz_i );
173 free( psz_ismall );
175 else if( i_mode == SORT_DURATION )
177 i_test = input_item_GetDuration( pp_items[i]->p_input ) -
178 input_item_GetDuration( pp_items[i_small]->p_input );
180 else if( i_mode == SORT_ARTIST )
182 DO_META_SORT( Artist );
184 else if( i_mode == SORT_GENRE )
186 DO_META_SORT( Genre );
188 else if( i_mode == SORT_ALBUM )
190 DO_META_SORT( Album );
191 /* Sort by tracknumber if albums are the same */
192 if( i_test == 0 )
193 DO_META_SORT_ADV( TrackNumber, VLC_TRUE );
195 else if( i_mode == SORT_TRACK_NUMBER )
197 DO_META_SORT_ADV( TrackNumber, VLC_TRUE );
199 else if( i_mode == SORT_DESCRIPTION )
201 DO_META_SORT( Description );
203 else if( i_mode == SORT_ID )
205 i_test = pp_items[i]->i_id - pp_items[i_small]->i_id;
207 else if( i_mode == SORT_TITLE_NODES_FIRST )
209 /* Alphabetic sort, all nodes first */
211 if( pp_items[i]->i_children == -1 &&
212 pp_items[i_small]->i_children >= 0 )
214 i_test = 1;
216 else if( pp_items[i]->i_children >= 0 &&
217 pp_items[i_small]->i_children == -1 )
219 i_test = -1;
221 else
223 i_test = strcasecmp( pp_items[i]->p_input->psz_name,
224 pp_items[i_small]->p_input->psz_name );
228 if( ( i_type == ORDER_NORMAL && i_test < 0 ) ||
229 ( i_type == ORDER_REVERSE && i_test > 0 ) )
231 i_small = i;
234 p_temp = pp_items[i_position];
235 pp_items[i_position] = pp_items[i_small];
236 pp_items[i_small] = p_temp;
238 #undef DO_META_SORT
239 #undef DO_META_SORT_ADV
241 return VLC_SUCCESS;