fed48995bca17c45ce350cbe467f88d7a0d1ea1d
[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 #include <vlc/libvlc.h>
26 #include <vlc/libvlc_media.h>
27 #include <vlc/libvlc_media_list.h>
28 #include <vlc/libvlc_media_list_view.h>
29
30 #include "media_internal.h" // Abuse, could ans should be removed
31 #include "media_list_internal.h" // Abuse, could ans should be removed
32 #include "media_list_view_internal.h"
33
34 /* FIXME: This version is probably a bit overheaded, and we may want to store
35  * the items in a vlc_array_t to speed everything up */
36
37 //#define DEBUG_HIERARCHICAL_VIEW
38
39 #ifdef DEBUG_HIERARCHICAL_VIEW
40 # define trace( fmt, ... ) printf( "[HIERARCHICAL_NODE] %s(): " fmt, __FUNCTION__, ##__VA_ARGS__ )
41 #else
42 # define trace( ... ) {}
43 #endif
44
45 /*
46  * Private functions
47  */
48
49 /**************************************************************************
50  *       flat_media_list_view_count  (private)
51  * (called by media_list_view_count)
52  **************************************************************************/
53 static int
54 hierarch_node_media_list_view_count( libvlc_media_list_view_t * p_mlv,
55                                 libvlc_exception_t * p_e )
56 {
57     /* FIXME: we may want to cache that */
58     int i, ret, count = libvlc_media_list_count( p_mlv->p_mlist, p_e );
59     libvlc_media_t * p_md;
60     libvlc_media_list_t * p_submlist;
61     ret = 0;
62     trace("\n");
63     for( i = 0; i < count; i++ )
64     {
65         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, p_e );
66         if( !p_md ) continue;
67         p_submlist = libvlc_media_subitems( p_md, p_e );
68         if( !p_submlist ) continue;
69         libvlc_media_release( p_md );
70         libvlc_media_list_release( p_submlist );
71         ret++;
72     }
73     return ret;
74 }
75
76 /**************************************************************************
77  *       flat_media_list_view_item_at_index  (private)
78  * (called by flat_media_list_view_item_at_index)
79  **************************************************************************/
80 static libvlc_media_t *
81 hierarch_node_media_list_view_item_at_index( libvlc_media_list_view_t * p_mlv,
82                                         int index,
83                                         libvlc_exception_t * p_e )
84 {
85     /* FIXME: we may want to cache that */
86     libvlc_media_t * p_md;
87     libvlc_media_list_t * p_submlist;
88     trace("%d\n", index);
89     int i, current_index, count = libvlc_media_list_count( p_mlv->p_mlist, p_e );
90     current_index = -1;
91     for( i = 0; i < count; i++ )
92     {
93         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, p_e );
94         if( !p_md ) continue;
95         p_submlist = libvlc_media_subitems( p_md, p_e );
96         if( !p_submlist ) continue;
97         libvlc_media_list_release( p_submlist );
98         current_index++;
99         if( current_index == index )
100             return p_md;
101         libvlc_media_release( p_md );
102     }
103
104     libvlc_exception_raise( p_e, "Index out of bound in Media List View" );
105     return NULL;
106 }
107
108 /**************************************************************************
109  *       flat_media_list_view_item_at_index  (private)
110  * (called by flat_media_list_view_item_at_index)
111  **************************************************************************/
112 static libvlc_media_list_view_t *
113 hierarch_node_media_list_view_children_at_index( libvlc_media_list_view_t * p_mlv,
114                                             int index,
115                                             libvlc_exception_t * p_e )
116 {
117     libvlc_media_t * p_md;
118     libvlc_media_list_t * p_submlist;
119     libvlc_media_list_view_t * p_ret;
120     p_md = hierarch_node_media_list_view_item_at_index( p_mlv, index, p_e );
121     if( !p_md ) return NULL;
122     p_submlist = libvlc_media_subitems( p_md, p_e );
123     libvlc_media_release( p_md );
124     if( !p_submlist ) return NULL;
125     p_ret = libvlc_media_list_hierarchical_node_view( p_submlist, p_e );
126     libvlc_media_list_release( p_submlist );
127
128     return p_ret;
129 }
130
131 /* Helper */
132 static int
133 index_of_item( libvlc_media_list_view_t * p_mlv, libvlc_media_t * p_md )
134 {
135     libvlc_media_t * p_iter_md;
136     libvlc_media_list_t * p_submlist;
137
138     int i, current_index, count = libvlc_media_list_count( p_mlv->p_mlist, NULL );
139     current_index = -1;
140     for( i = 0; i < count; i++ )
141     {
142         p_iter_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, NULL );
143         if( !p_iter_md ) continue;
144         p_submlist = libvlc_media_subitems( p_iter_md, NULL );
145         if( !p_submlist ) continue;
146         libvlc_media_list_release( p_submlist );
147         libvlc_media_release( p_iter_md );
148         current_index++;
149         if( p_md == p_iter_md )
150             return current_index;
151     }
152     return -1;
153 }
154
155 static bool
156 item_is_already_added( libvlc_media_t * p_md )
157 {
158     libvlc_media_list_t * p_submlist;
159
160     p_submlist = libvlc_media_subitems( p_md, NULL );
161     if( !p_submlist ) return false;
162     int count = libvlc_media_list_count( p_submlist, NULL );
163     libvlc_media_list_release( p_submlist );
164     return count > 1;
165 }
166
167
168 /**************************************************************************
169  *       media_list_(item|will)_* (private) (Event callback)
170  **************************************************************************/
171 static void
172 items_subitems_added( const libvlc_event_t * p_event, void * user_data )
173 {
174     libvlc_media_t * p_md;
175     libvlc_media_list_view_t * p_mlv = user_data;
176     int index;
177     p_md = p_event->p_obj;
178     if( !item_is_already_added( p_md ) )
179     {
180         index = index_of_item( p_mlv, p_md );
181         trace("%d\n", index);
182         if( index >= 0 )
183         {
184             libvlc_media_list_view_will_add_item( p_mlv, p_md, index );
185             libvlc_media_list_view_item_added( p_mlv, p_md, index );
186         }
187     }
188     else
189     {
190         trace("item already added\n");
191     }
192 }
193
194 static void
195 media_list_item_added( const libvlc_event_t * p_event, void * user_data )
196 {
197     libvlc_media_t * p_md;
198     libvlc_media_list_view_t * p_mlv = user_data;
199     int index;
200     p_md = p_event->u.media_list_item_added.item;
201     index = index_of_item( p_mlv, p_md );
202     trace("%d\n", index);
203     if( index >= 0)
204         libvlc_media_list_view_item_added( p_mlv, p_md, index );
205     libvlc_event_attach( p_md->p_event_manager, libvlc_MediaSubItemAdded,
206                          items_subitems_added, p_mlv, NULL );
207                          
208 }
209 static void
210 media_list_will_add_item( const libvlc_event_t * p_event, void * user_data )
211 {
212     libvlc_media_t * p_md;
213     libvlc_media_list_view_t * p_mlv = user_data;
214     int index;
215     p_md = p_event->u.media_list_will_add_item.item;
216     index = index_of_item( p_mlv, p_md );
217     trace("%d\n", index);
218     if( index >= 0)
219         libvlc_media_list_view_will_add_item( p_mlv, p_md, index );
220 }
221 static void
222 media_list_item_deleted( const libvlc_event_t * p_event, void * user_data )
223 {
224     libvlc_media_t * p_md;
225     libvlc_media_list_view_t * p_mlv = user_data;
226     int index;
227     p_md = p_event->u.media_list_item_deleted.item;
228     index = index_of_item( p_mlv, p_md );
229     trace("%d\n", index);
230     if( index >= 0)
231         libvlc_media_list_view_item_deleted( p_mlv, p_md, index );
232     libvlc_event_detach( p_md->p_event_manager, libvlc_MediaSubItemAdded,
233                          items_subitems_added, p_mlv, NULL );
234 }
235 static void
236 media_list_will_delete_item( const libvlc_event_t * p_event, void * user_data )
237 {
238     libvlc_media_t * p_md;
239     libvlc_media_list_view_t * p_mlv = user_data;
240     int index;
241     p_md = p_event->u.media_list_will_delete_item.item;
242     index = index_of_item( p_mlv, p_md );
243     trace("%d\n", index);
244     if( index >= 0)
245         libvlc_media_list_view_will_delete_item( p_mlv, p_md, index );
246 }
247
248
249 /*
250  * Public libvlc functions
251  */
252
253
254 /**************************************************************************
255  *       flat_media_list_view_release (private)
256  * (called by media_list_view_release)
257  **************************************************************************/
258 static void
259 hierarch_node_media_list_view_release( libvlc_media_list_view_t * p_mlv )
260 {
261     trace("\n");
262     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
263                          libvlc_MediaListItemAdded,
264                          media_list_item_added, p_mlv, NULL );
265     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
266                          libvlc_MediaListWillAddItem,
267                          media_list_will_add_item, p_mlv, NULL );
268     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
269                          libvlc_MediaListItemDeleted,
270                          media_list_item_deleted, p_mlv, NULL );
271     libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
272                          libvlc_MediaListWillDeleteItem,
273                          media_list_will_delete_item, p_mlv, NULL );
274 }
275
276 /**************************************************************************
277  *       libvlc_media_list_flat_view (Public)
278  **************************************************************************/
279 libvlc_media_list_view_t *
280 libvlc_media_list_hierarchical_node_view( libvlc_media_list_t * p_mlist,
281                                      libvlc_exception_t * p_e )
282 {
283     trace("\n");
284     libvlc_media_list_view_t * p_mlv;
285     p_mlv = libvlc_media_list_view_new( p_mlist,
286                                         hierarch_node_media_list_view_count,
287                                         hierarch_node_media_list_view_item_at_index,
288                                         hierarch_node_media_list_view_children_at_index,
289                                         libvlc_media_list_hierarchical_node_view,
290                                         hierarch_node_media_list_view_release,
291                                         NULL,
292                                         p_e );
293     libvlc_media_list_lock( p_mlist );
294     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
295                          libvlc_MediaListItemAdded,
296                          media_list_item_added, p_mlv, NULL );
297     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
298                          libvlc_MediaListWillAddItem,
299                          media_list_will_add_item, p_mlv, NULL );
300     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
301                          libvlc_MediaListItemDeleted,
302                          media_list_item_deleted, p_mlv, NULL );
303     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
304                          libvlc_MediaListWillDeleteItem,
305                          media_list_will_delete_item, p_mlv, NULL );
306     libvlc_media_list_unlock( p_mlist );
307     return p_mlv;
308 }