]> git.sesse.net Git - vlc/blob - src/playlist/sort.c
Last patch to close #1479 (add a column with the track id)
[vlc] / src / playlist / sort.c
1 /*****************************************************************************
2  * sort.c : Playlist sorting functions
3  *****************************************************************************
4  * Copyright (C) 1999-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *
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.
13  *
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.
18  *
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
26
27 #include <vlc/vlc.h>
28 #include "vlc_playlist.h"
29 #include "playlist_internal.h"
30
31
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 );
35
36 /**
37  * Sort a node.
38  * This function must be entered with the playlist lock !
39  *
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
45  */
46 static int playlist_NodeSort( playlist_t * p_playlist , playlist_item_t *p_node,
47                               int i_mode, int i_type )
48 {
49     playlist_ItemArraySort( p_playlist,p_node->i_children,
50                             p_node->pp_children, i_mode, i_type );
51     return VLC_SUCCESS;
52 }
53
54 /**
55  * Sort a node recursively.
56  *
57  * This function must be entered with the playlist lock !
58  *
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
64  */
65 int playlist_RecursiveNodeSort( playlist_t *p_playlist, playlist_item_t *p_node,
66                                 int i_mode, int i_type )
67 {
68     int i;
69     playlist_NodeSort( p_playlist, p_node, i_mode, i_type );
70     for( i = 0 ; i< p_node->i_children; i++ )
71     {
72         if( p_node->pp_children[i]->i_children != -1 )
73         {
74             playlist_RecursiveNodeSort( p_playlist, p_node->pp_children[i],
75                                         i_mode,i_type );
76         }
77     }
78     return VLC_SUCCESS;
79 }
80
81
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 )
85 {
86     int i , i_small , i_position;
87     playlist_item_t *p_temp;
88     vlc_value_t val;
89     val.b_bool = VLC_TRUE;
90
91     (void)p_playlist; // a bit surprising we don't need p_playlist!
92
93     if( i_mode == SORT_RANDOM )
94     {
95         for( i_position = 0; i_position < i_items ; i_position ++ )
96         {
97             int i_new;
98
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;
106         }
107
108         return VLC_SUCCESS;
109     }
110
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 ); \
117 }
118
119
120 #define DO_META_SORT( node ) { \
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 ) \
132     { \
133         META_STRCASECMP_NAME( i, i_small ) \
134     } \
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 ) \
142     { \
143         META_STRCASECMP_NAME( i, i_small ); \
144     } \
145     else \
146     { \
147         i_test = strcmp( psz_a, psz_b ); \
148     } \
149     free( psz_a ); \
150     free( psz_b ); \
151 }
152
153     for( i_position = 0; i_position < i_items -1 ; i_position ++ )
154     {
155         i_small  = i_position;
156         for( i = i_position + 1 ; i< i_items ; i++)
157         {
158             int i_test = 0;
159
160             if( i_mode == SORT_TITLE )
161             {
162                 META_STRCASECMP_NAME( i, i_small );
163             }
164             else if( i_mode == SORT_TITLE_NUMERIC )
165             {
166                 char *psz_i = input_item_GetName( pp_items[i]->p_input );
167                 char *psz_ismall =
168                         input_item_GetName( pp_items[i_small]->p_input );
169                 i_test = atoi( psz_i ) - atoi( psz_ismall );
170                 free( psz_i );
171                 free( psz_ismall );
172             }
173             else if( i_mode == SORT_DURATION )
174             {
175                 i_test = input_item_GetDuration( pp_items[i]->p_input ) -
176                          input_item_GetDuration( pp_items[i_small]->p_input );
177             }
178             else if( i_mode == SORT_ARTIST )
179             {
180                 DO_META_SORT( Artist );
181             }
182             else if( i_mode == SORT_GENRE )
183             {
184                 DO_META_SORT( Genre );
185             }
186             else if( i_mode == SORT_ALBUM )
187             {
188                 DO_META_SORT( Album );
189             }
190             else if( i_mode == SORT_TRACK_NUMBER )
191             {
192                 DO_META_SORT( TrackNumber );
193             }
194             else if( i_mode == SORT_DESCRIPTION )
195             {
196                 DO_META_SORT( Description );
197             }
198             else if( i_mode == SORT_RATING )
199             {
200                 DO_META_SORT( Rating );
201             }
202             else if( i_mode == SORT_ID )
203             {
204                 i_test = pp_items[i]->i_id - pp_items[i_small]->i_id;
205             }
206             else if( i_mode == SORT_TITLE_NODES_FIRST )
207             {
208                 /* Alphabetic sort, all nodes first */
209
210                 if( pp_items[i]->i_children == -1 &&
211                     pp_items[i_small]->i_children >= 0 )
212                 {
213                     i_test = 1;
214                 }
215                 else if( pp_items[i]->i_children >= 0 &&
216                          pp_items[i_small]->i_children == -1 )
217                 {
218                     i_test = -1;
219                 }
220                 else
221                 {
222                     i_test = strcasecmp( pp_items[i]->p_input->psz_name,
223                                          pp_items[i_small]->p_input->psz_name );
224                 }
225             }
226
227             if( ( i_type == ORDER_NORMAL  && i_test < 0 ) ||
228                 ( i_type == ORDER_REVERSE && i_test > 0 ) )
229             {
230                 i_small = i;
231             }
232         }
233         p_temp = pp_items[i_position];
234         pp_items[i_position] = pp_items[i_small];
235         pp_items[i_small] = p_temp;
236     }
237     return VLC_SUCCESS;
238 }