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