libvlc: include config.h when needed
[vlc.git] / src / control / hierarchical_node_media_list_view.c
1 /*****************************************************************************
2  * hierarchical_node_media_list_view.c: libvlc hierarchical nodes media list
3  * view functs.
4  *****************************************************************************
5  * Copyright (C) 2007 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc/libvlc.h>
30 #include <vlc/libvlc_media.h>
31 #include <vlc/libvlc_media_list.h>
32 #include <vlc/libvlc_media_list_view.h>
33
34 #include "media_internal.h" // Abuse, could ans should be removed
35 #include "media_list_internal.h" // Abuse, could ans should be removed
36 #include "media_list_view_internal.h"
37
38 /* FIXME: This version is probably a bit overheaded, and we may want to store
39  * the items in a vlc_array_t to speed everything up */
40
41 //#define DEBUG_HIERARCHICAL_VIEW
42
43 #ifdef DEBUG_HIERARCHICAL_VIEW
44 # define trace( fmt, ... ) printf( "[HIERARCHICAL_NODE] %s(): " fmt, __FUNCTION__, ##__VA_ARGS__ )
45 #else
46 # define trace( ... ) {}
47 #endif
48
49 /*
50  * Private functions
51  */
52
53 /**************************************************************************
54  *       flat_media_list_view_count  (private)
55  * (called by media_list_view_count)
56  **************************************************************************/
57 static int
58 hierarch_node_media_list_view_count( libvlc_media_list_view_t * p_mlv,
59                                 libvlc_exception_t * p_e )
60 {
61     /* FIXME: we may want to cache that */
62     int i, ret, count = libvlc_media_list_count( p_mlv->p_mlist, p_e );
63     libvlc_media_t * p_md;
64     libvlc_media_list_t * p_submlist;
65     ret = 0;
66     trace("\n");
67     for( i = 0; i < count; i++ )
68     {
69         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, p_e );
70         if( !p_md ) continue;
71         p_submlist = libvlc_media_subitems( p_md, p_e );
72         if( !p_submlist ) continue;
73         libvlc_media_release( p_md );
74         libvlc_media_list_release( p_submlist );
75         ret++;
76     }
77     return ret;
78 }
79
80 /**************************************************************************
81  *       flat_media_list_view_item_at_index  (private)
82  * (called by flat_media_list_view_item_at_index)
83  **************************************************************************/
84 static libvlc_media_t *
85 hierarch_node_media_list_view_item_at_index( libvlc_media_list_view_t * p_mlv,
86                                         int index,
87                                         libvlc_exception_t * p_e )
88 {
89     /* FIXME: we may want to cache that */
90     libvlc_media_t * p_md;
91     libvlc_media_list_t * p_submlist;
92     trace("%d\n", index);
93     int i, current_index, count = libvlc_media_list_count( p_mlv->p_mlist, p_e );
94     current_index = -1;
95     for( i = 0; i < count; i++ )
96     {
97         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, p_e );
98         if( !p_md ) continue;
99         p_submlist = libvlc_media_subitems( p_md, p_e );
100         if( !p_submlist ) continue;
101         libvlc_media_list_release( p_submlist );
102         current_index++;
103         if( current_index == index )
104             return p_md;
105         libvlc_media_release( p_md );
106     }
107
108     libvlc_exception_raise( p_e, "Index out of bound in Media List View" );
109     return NULL;
110 }
111
112 /**************************************************************************
113  *       flat_media_list_view_item_at_index  (private)
114  * (called by flat_media_list_view_item_at_index)
115  **************************************************************************/
116 static libvlc_media_list_view_t *
117 hierarch_node_media_list_view_children_at_index( libvlc_media_list_view_t * p_mlv,
118                                             int index,
119                                             libvlc_exception_t * p_e )
120 {
121     libvlc_media_t * p_md;
122     libvlc_media_list_t * p_submlist;
123     libvlc_media_list_view_t * p_ret;
124     p_md = hierarch_node_media_list_view_item_at_index( p_mlv, index, p_e );
125     if( !p_md ) return NULL;
126     p_submlist = libvlc_media_subitems( p_md, p_e );
127     libvlc_media_release( p_md );
128     if( !p_submlist ) return NULL;
129     p_ret = libvlc_media_list_hierarchical_node_view( p_submlist, p_e );
130     libvlc_media_list_release( p_submlist );
131
132     return p_ret;
133 }
134
135 /* Helper */
136 static int
137 index_of_item( libvlc_media_list_view_t * p_mlv, libvlc_media_t * p_md )
138 {
139     libvlc_media_t * p_iter_md;
140     libvlc_media_list_t * p_submlist;
141
142     int i, current_index, count = libvlc_media_list_count( p_mlv->p_mlist, NULL );
143     current_index = -1;
144     for( i = 0; i < count; i++ )
145     {
146         p_iter_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, NULL );
147         if( !p_iter_md ) continue;
148         p_submlist = libvlc_media_subitems( p_iter_md, NULL );
149         if( !p_submlist ) continue;
150         libvlc_media_list_release( p_submlist );
151         libvlc_media_release( p_iter_md );
152         current_index++;
153         if( p_md == p_iter_md )
154             return current_index;
155     }
156     return -1;
157 }
158
159 static bool
160 item_is_already_added( libvlc_media_t * p_md )
161 {
162     libvlc_media_list_t * p_submlist;
163
164     p_submlist = libvlc_media_subitems( p_md, NULL );
165     if( !p_submlist ) return false;
166     int count = libvlc_media_list_count( p_submlist, NULL );
167     libvlc_media_list_release( p_submlist );
168     return count > 1;
169 }
170
171
172 /**************************************************************************
173  *       media_list_(item|will)_* (private) (Event callback)
174  **************************************************************************/
175 static void
176 items_subitems_added( const libvlc_event_t * p_event, void * user_data )
177 {
178     libvlc_media_t * p_md;
179     libvlc_media_list_view_t * p_mlv = user_data;
180     int index;
181     p_md = p_event->p_obj;
182     if( !item_is_already_added( p_md ) )
183     {
184         index = index_of_item( p_mlv, p_md );
185         trace("%d\n", index);
186         if( index >= 0 )
187         {
188             libvlc_media_list_view_will_add_item( p_mlv, p_md, index );
189             libvlc_media_list_view_item_added( p_mlv, p_md, index );
190         }
191     }
192     else
193     {
194         trace("item already added\n");
195     }
196 }
197
198 static void
199 media_list_item_added( const libvlc_event_t * p_event, void * user_data )
200 {
201     libvlc_media_t * p_md;
202     libvlc_media_list_view_t * p_mlv = user_data;
203     int index;
204     p_md = p_event->u.media_list_item_added.item;
205     index = index_of_item( p_mlv, p_md );
206     trace("%d\n", index);
207     if( index >= 0)
208         libvlc_media_list_view_item_added( p_mlv, p_md, index );
209     libvlc_event_attach( p_md->p_event_manager, libvlc_MediaSubItemAdded,
210                          items_subitems_added, p_mlv, NULL );
211                          
212 }
213 static void
214 media_list_will_add_item( const libvlc_event_t * p_event, void * user_data )
215 {
216     libvlc_media_t * p_md;
217     libvlc_media_list_view_t * p_mlv = user_data;
218     int index;
219     p_md = p_event->u.media_list_will_add_item.item;
220     index = index_of_item( p_mlv, p_md );
221     trace("%d\n", index);
222     if( index >= 0)
223         libvlc_media_list_view_will_add_item( p_mlv, p_md, index );
224 }
225 static void
226 media_list_item_deleted( const libvlc_event_t * p_event, void * user_data )
227 {
228     libvlc_media_t * p_md;
229     libvlc_media_list_view_t * p_mlv = user_data;
230     int index;
231     p_md = p_event->u.media_list_item_deleted.item;
232     index = index_of_item( p_mlv, p_md );
233     trace("%d\n", index);
234     if( index >= 0)
235         libvlc_media_list_view_item_deleted( p_mlv, p_md, index );
236     libvlc_event_detach( p_md->p_event_manager, libvlc_MediaSubItemAdded,
237                          items_subitems_added, p_mlv, NULL );
238 }
239 static void
240 media_list_will_delete_item( const libvlc_event_t * p_event, void * user_data )
241 {
242     libvlc_media_t * p_md;
243     libvlc_media_list_view_t * p_mlv = user_data;
244     int index;
245     p_md = p_event->u.media_list_will_delete_item.item;
246     index = index_of_item( p_mlv, p_md );
247     trace("%d\n", index);
248     if( index >= 0)
249         libvlc_media_list_view_will_delete_item( p_mlv, p_md, index );
250 }
251
252
253 /*
254  * Public libvlc functions
255  */
256
257
258 /**************************************************************************
259  *       flat_media_list_view_release (private)
260  * (called by media_list_view_release)
261  **************************************************************************/
262 static void
263 hierarch_node_media_list_view_release( libvlc_media_list_view_t * p_mlv )
264 {
265     trace("\n");
266     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
267                          libvlc_MediaListItemAdded,
268                          media_list_item_added, p_mlv, NULL );
269     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
270                          libvlc_MediaListWillAddItem,
271                          media_list_will_add_item, p_mlv, NULL );
272     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
273                          libvlc_MediaListItemDeleted,
274                          media_list_item_deleted, p_mlv, NULL );
275     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
276                          libvlc_MediaListWillDeleteItem,
277                          media_list_will_delete_item, p_mlv, NULL );
278 }
279
280 /**************************************************************************
281  *       libvlc_media_list_flat_view (Public)
282  **************************************************************************/
283 libvlc_media_list_view_t *
284 libvlc_media_list_hierarchical_node_view( libvlc_media_list_t * p_mlist,
285                                      libvlc_exception_t * p_e )
286 {
287     trace("\n");
288     libvlc_media_list_view_t * p_mlv;
289     p_mlv = libvlc_media_list_view_new( p_mlist,
290                                         hierarch_node_media_list_view_count,
291                                         hierarch_node_media_list_view_item_at_index,
292                                         hierarch_node_media_list_view_children_at_index,
293                                         libvlc_media_list_hierarchical_node_view,
294                                         hierarch_node_media_list_view_release,
295                                         NULL,
296                                         p_e );
297     libvlc_media_list_lock( p_mlist );
298     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
299                          libvlc_MediaListItemAdded,
300                          media_list_item_added, p_mlv, NULL );
301     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
302                          libvlc_MediaListWillAddItem,
303                          media_list_will_add_item, p_mlv, NULL );
304     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
305                          libvlc_MediaListItemDeleted,
306                          media_list_item_deleted, p_mlv, NULL );
307     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
308                          libvlc_MediaListWillDeleteItem,
309                          media_list_will_delete_item, p_mlv, NULL );
310     libvlc_media_list_unlock( p_mlist );
311     return p_mlv;
312 }