abc54411d7f1f1f6a21a9c4cdd402f3e3febaeb7
[vlc.git] / extras / MacOSX / Framework / Sources / VLCMediaListAspect.m
1 /*****************************************************************************
2  * VLCMediaList.m: VLC.framework VLCMediaList implementation
3  *****************************************************************************
4  * Copyright (C) 2007 Pierre d'Herbemont
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 #import "VLCMediaListAspect.h"
26 #import "VLCLibrary.h"
27 #import "VLCEventManager.h"
28 #import "VLCLibVLCBridging.h"
29 #include <vlc/vlc.h>
30 #include <vlc/libvlc.h>
31
32 // TODO: Documentation
33 @interface VLCMediaListAspect (Private)
34 /* Initializers */
35 - (void)initInternalMediaListView;
36
37 - (void)mediaListViewItemAdded:(NSDictionary *)args;
38 - (void)mediaListViewItemRemoved:(NSNumber *)index;
39 @end
40
41 @implementation VLCMediaListAspectNode
42 @synthesize media;
43 @synthesize children;
44
45 - (BOOL)isLeaf
46 {
47     return self.children == NULL;
48 }
49
50 -(void)dealloc
51 {
52     [self.children release];
53     [super dealloc];
54 }
55 @end
56
57 @implementation VLCMediaListAspect (KeyValueCodingCompliance)
58 /* For the @"media" key */
59 - (int) countOfMedia
60 {
61     return [cachedNode count];
62 }
63 - (id) objectInMediaAtIndex:(int)i
64 {
65     return [[cachedNode objectAtIndex:i] media];
66 }
67 /* For the @"node" key */
68 - (int) countOfNode
69 {
70     return [cachedNode count];
71 }
72 - (id) objectInNodeAtIndex:(int)i
73 {
74     return [cachedNode objectAtIndex:i];
75 }
76 @end
77
78 /* libvlc event callback */
79 static void HandleMediaListViewItemAdded(const libvlc_event_t *event, void *user_data)
80 {
81     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
82     id self = user_data;
83     [[VLCEventManager sharedManager] callOnMainThreadObject:self 
84                                                  withMethod:@selector(mediaListViewItemAdded:) 
85                                        withArgumentAsObject:[NSDictionary dictionaryWithObjectsAndKeys:
86                                                           [VLCMedia mediaWithLibVLCMediaDescriptor:event->u.media_list_item_added.item], @"media",
87                                                           [NSNumber numberWithInt:event->u.media_list_item_added.index], @"index",
88                                                           nil]];
89     [pool release];
90 }
91
92 static void HandleMediaListViewItemDeleted( const libvlc_event_t * event, void * user_data)
93 {
94     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
95     id self = user_data;
96     [[VLCEventManager sharedManager] callOnMainThreadObject:self 
97                                                  withMethod:@selector(mediaListViewItemRemoved:) 
98                                        withArgumentAsObject:[NSNumber numberWithInt:event->u.media_list_item_deleted.index]];
99     [pool release];
100 }
101
102 @implementation VLCMediaListAspect
103 - (void)dealloc
104 {
105     // Release allocated memory
106     libvlc_media_list_view_release(p_mlv);
107     [cachedNode release];
108     [parentMediaList release];
109     [super dealloc];
110 }
111 - (VLCMedia *)mediaAtIndex:(int)index
112 {
113     libvlc_exception_t p_e;
114     libvlc_exception_init( &p_e );
115     libvlc_media_descriptor_t *p_md = libvlc_media_list_view_item_at_index( p_mlv, index, &p_e );
116     quit_on_exception( &p_e );
117     
118     // Returns local object for media descriptor, searchs for user data first.  If not found it creates a 
119     // new cocoa object representation of the media descriptor.
120     return [VLCMedia mediaWithLibVLCMediaDescriptor:p_md];
121 }
122
123 - (VLCMediaListAspect *)childrenAtIndex:(int)index
124 {
125     libvlc_exception_t p_e;
126     libvlc_exception_init( &p_e );
127     libvlc_media_list_view_t *p_sub_mlv = libvlc_media_list_view_children_at_index( p_mlv, index, &p_e );
128     quit_on_exception( &p_e );
129
130     if( !p_sub_mlv )
131         return nil;
132
133     // Returns local object for media descriptor, searchs for user data first.  If not found it creates a 
134     // new cocoa object representation of the media descriptor.
135     return [VLCMediaListAspect mediaListAspectWithLibVLCMediaListView:p_sub_mlv];
136 }
137
138 - (VLCMediaListAspectNode *)nodeAtIndex:(int)index
139 {
140     VLCMediaListAspectNode * node = [[[VLCMediaListAspectNode alloc] init] autorelease];
141     [node setMedia:[self mediaAtIndex: index]];
142     return node;
143 }
144
145 - (int)count
146 {
147     libvlc_exception_t p_e;
148     libvlc_exception_init( &p_e );
149     int result = libvlc_media_list_view_count( p_mlv, &p_e );
150     quit_on_exception( &p_e );
151
152     return result;
153 }
154
155 - (VLCMediaList *)parentMediaList
156 {
157     return [[parentMediaList retain] autorelease];
158 }
159 @end
160
161 @implementation VLCMediaListAspect (LibVLCBridging)
162 + (id)mediaListAspectWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv;
163 {
164     return [[[VLCMediaListAspect alloc] initWithLibVLCMediaListView:p_new_mlv] autorelease];
165 }
166
167 - (id)initWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv;
168 {
169     if( self = [super init] )
170     {
171         p_mlv = p_new_mlv;
172         libvlc_media_list_view_retain(p_mlv);
173         libvlc_media_list_t * p_mlist = libvlc_media_list_view_parent_media_list(p_mlv, NULL);
174         parentMediaList = [[VLCMediaList mediaListWithLibVLCMediaList: p_mlist] retain];
175         libvlc_media_list_release( p_mlist );
176
177         //libvlc_media_list_lock(p_mlv->p_mlist);
178         cachedNode = [[NSMutableArray alloc] initWithCapacity:libvlc_media_list_view_count(p_mlv, NULL)];
179         int i, count = libvlc_media_list_view_count(p_mlv, NULL);
180         for( i = 0; i < count; i++ )
181         {
182             libvlc_media_descriptor_t * p_md = libvlc_media_list_view_item_at_index(p_mlv, i, NULL);
183             libvlc_media_list_view_t * p_sub_mlv = libvlc_media_list_view_children_at_index(p_mlv, i, NULL);
184             VLCMediaListAspectNode * node = [[[VLCMediaListAspectNode alloc] init] autorelease];
185             [node setMedia:[VLCMedia mediaWithLibVLCMediaDescriptor: p_md]];
186             [node setChildren: p_sub_mlv ? [VLCMediaListAspect mediaListAspectWithLibVLCMediaListView: p_sub_mlv] : nil];
187             [cachedNode addObject:node];
188             libvlc_media_descriptor_release(p_md);
189             if( p_sub_mlv ) libvlc_media_list_view_release(p_sub_mlv);
190         }
191         [self initInternalMediaListView];
192         //libvlc_media_list_unlock(p_mlv->p_mlist);
193     }
194     return self;
195 }
196
197 - (libvlc_media_list_view_t *)libVLCMediaListView
198 {
199     return (libvlc_media_list_view_t *)p_mlv;
200 }
201 @end
202
203 @implementation VLCMediaListAspect (Private)
204 - (void)initInternalMediaListView
205 {
206     libvlc_exception_t e;
207     libvlc_exception_init( &e );
208
209     libvlc_event_manager_t *p_em = libvlc_media_list_event_manager( p_mlv, &e );
210
211     /* Add internal callback */
212     libvlc_event_attach( p_em, libvlc_MediaListViewItemAdded,   HandleMediaListViewItemAdded,   self, &e );
213     libvlc_event_attach( p_em, libvlc_MediaListViewItemDeleted, HandleMediaListViewItemDeleted, self, &e );
214     quit_on_exception( &e );
215 }
216
217 - (void)mediaListViewItemAdded:(NSDictionary *)args
218 {
219     int index = [[args objectForKey:@"index"] intValue];
220     VLCMedia * media = [args objectForKey:@"media"];
221
222     VLCMediaListAspectNode * node = [[[VLCMediaListAspectNode alloc] init] autorelease];
223     [node setMedia:media];
224     [node setChildren:[self childrenAtIndex:index]];
225
226     [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"media"];
227     [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"node"];
228     [cachedNode insertObject:node atIndex:index];
229     [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"node"];
230     [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"media"];
231 }
232
233 - (void)mediaListViewItemRemoved:(NSNumber *)index
234 {
235     [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"media"];
236     [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"node"];
237     [cachedNode removeObjectAtIndex:[index intValue]];
238     [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"node"];
239     [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"media"];
240 }
241 @end