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