]> git.sesse.net Git - vlc/blobdiff - extras/MacOSX/Framework/Sources/VLCMediaListAspect.m
Don't include config.h from the headers - refs #297.
[vlc] / extras / MacOSX / Framework / Sources / VLCMediaListAspect.m
index 230115b5b1b66b88f494fad4cdf4ab9ee5332482..aa7411b98ca13854a892be9405cfe515211e08cc 100644 (file)
 #import "VLCLibrary.h"
 #import "VLCEventManager.h"
 #import "VLCLibVLCBridging.h"
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <vlc/vlc.h>
 #include <vlc/libvlc.h>
 
 @interface VLCMediaListAspect (Private)
 /* Initializers */
 - (void)initInternalMediaListView;
+
+- (void)mediaListViewItemAdded:(NSArray *)args;
+- (void)mediaListViewItemRemoved:(NSNumber *)index;
+@end
+
+@implementation VLCMediaListAspectNode
+@synthesize media;
+@synthesize children;
+
+- (BOOL)isLeaf
+{
+    return self.children == NULL;
+}
+
+-(void)dealloc
+{
+    [self.children release];
+    [super dealloc];
+}
 @end
 
 @implementation VLCMediaListAspect (KeyValueCodingCompliance)
-/* For the @"Media" key */
+/* For the @"media" key */
 - (int) countOfMedia
 {
-    return [self count];
+    return [cachedNode count];
 }
 - (id) objectInMediaAtIndex:(int)i
 {
-    return [self mediaAtIndex:i];
+    return [[cachedNode objectAtIndex:i] media];
 }
-@end
-
-/* libvlc event callback */
-static void HandleMediaListViewItemAdded(const libvlc_event_t *event, void *user_data)
+/* For the @"node" key */
+- (int) countOfNode
 {
-    id self = user_data;
-    int index = event->u.media_list_view_item_added.index;
-    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"Media"];
+    return [cachedNode count];
 }
-static void HandleMediaListViewWillAddItem(const libvlc_event_t *event, void *user_data)
+- (id) objectInNodeAtIndex:(int)i
 {
-    id self = user_data;
-    int index = event->u.media_list_view_will_add_item.index;
-    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"Media"];
+    return [cachedNode objectAtIndex:i];
 }
-static void HandleMediaListViewItemDeleted( const libvlc_event_t * event, void * user_data)
+@end
+
+/* libvlc event callback */
+static void HandleMediaListViewItemAdded(const libvlc_event_t * event, void * user_data)
 {
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
     id self = user_data;
-    int index = event->u.media_list_view_will_add_item.index;
-    [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"Media"];
+    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
+                                                 withMethod:@selector(mediaListViewItemAdded:) 
+                                       withArgumentAsObject:[NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                                          [VLCMedia mediaWithLibVLCMediaDescriptor:event->u.media_list_item_added.item], @"media",
+                                                          [NSNumber numberWithInt:event->u.media_list_item_added.index], @"index",
+                                                          nil]]];
+    [pool release];
 }
-static void HandleMediaListViewWillDeleteItem(const libvlc_event_t *event, void *user_data)
+
+static void HandleMediaListViewItemDeleted( const libvlc_event_t * event, void * user_data)
 {
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
     id self = user_data;
-    int index = event->u.media_list_view_will_add_item.index;
-    [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:[NSIndexSet indexSetWithIndex:index] forKey:@"Media"];
+    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
+                                                 withMethod:@selector(mediaListViewItemRemoved:) 
+                                       withArgumentAsObject:[NSNumber numberWithInt:event->u.media_list_item_deleted.index]];
+    [pool release];
 }
 
 @implementation VLCMediaListAspect
 - (void)dealloc
 {
     // Release allocated memory
-    libvlc_media_list_release(p_mlv);
-    
+    libvlc_media_list_view_release(p_mlv);
+    [cachedNode release];
+    if( ownHisMediaList )
+        [parentMediaList release];
     [super dealloc];
 }
+- (NSString *)description
+{
+    NSMutableString * content = [NSMutableString string];
+    int i;
+    for( i = 0; i < [self count]; i++)
+    {
+        [content appendFormat:@"%@\n", [self mediaAtIndex: i]];
+    }
+    return [NSString stringWithFormat:@"<%@ %p> {\n%@}", [self className], self, content];
+}
+
 - (VLCMedia *)mediaAtIndex:(int)index
 {
     libvlc_exception_t p_e;
     libvlc_exception_init( &p_e );
-    libvlc_media_descriptor_t *p_md = libvlc_media_list_view_item_at_index( p_mlv, index, &p_e );
-    quit_on_exception( &p_e );
+    libvlc_media_descriptor_t * p_md = libvlc_media_list_view_item_at_index( p_mlv, index, &p_e );
+    catch_exception( &p_e );
     
     // Returns local object for media descriptor, searchs for user data first.  If not found it creates a 
     // new cocoa object representation of the media descriptor.
     return [VLCMedia mediaWithLibVLCMediaDescriptor:p_md];
 }
 
+- (VLCMediaListAspect *)childrenAtIndex:(int)index
+{
+    libvlc_exception_t p_e;
+    libvlc_exception_init( &p_e );
+    libvlc_media_list_view_t * p_sub_mlv = libvlc_media_list_view_children_at_index( p_mlv, index, &p_e );
+    catch_exception( &p_e );
+
+    if( !p_sub_mlv )
+        return nil;
+
+    // Returns local object for media descriptor, searchs for user data first.  If not found it creates a 
+    // new cocoa object representation of the media descriptor.
+    return [VLCMediaListAspect mediaListAspectWithLibVLCMediaListView:p_sub_mlv];
+}
+
+- (VLCMediaListAspectNode *)nodeAtIndex:(int)index
+{
+    VLCMediaListAspectNode * node = [[[VLCMediaListAspectNode alloc] init] autorelease];
+    [node setMedia:[self mediaAtIndex: index]];
+    return node;
+}
+
 - (int)count
 {
     libvlc_exception_t p_e;
     libvlc_exception_init( &p_e );
     int result = libvlc_media_list_view_count( p_mlv, &p_e );
-    quit_on_exception( &p_e );
+    catch_exception( &p_e );
 
     return result;
 }
+
+- (VLCMediaList *)parentMediaList
+{
+    return parentMediaList;
+}
 @end
 
 @implementation VLCMediaListAspect (LibVLCBridging)
-+ (id)mediaListAspectWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv;
++ (id)mediaListAspectWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv
 {
-    return [[[VLCMediaListAspect alloc] initWithLibVLCMediaListView:p_new_mlv] autorelease];
+    return [[[VLCMediaListAspect alloc] initWithLibVLCMediaListView:p_new_mlv andMediaList:nil] autorelease];
 }
 
-- (id)initWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv;
++ (id)mediaListAspectWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv andMediaList:(VLCMediaList *)mediaList;
+{
+    return [[[VLCMediaListAspect alloc] initWithLibVLCMediaListView:p_new_mlv andMediaList:mediaList] autorelease];
+}
+
+- (id)initWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv andMediaList:(VLCMediaList *)mediaList;
 {
     if( self = [super init] )
     {
         p_mlv = p_new_mlv;
         libvlc_media_list_view_retain(p_mlv);
+
+        /* parentMediaList isn't retained, because we need a mediaList to exists, and not the contrary */
+        parentMediaList = mediaList;
+        ownHisMediaList = NO;
+        if( !parentMediaList )
+        {
+            /* We have to create it then */
+            libvlc_media_list_view_retain(p_mlv);
+            libvlc_media_list_t * p_mlist = libvlc_media_list_view_parent_media_list(p_mlv, NULL);
+            parentMediaList = [[VLCMediaList mediaListWithLibVLCMediaList: p_mlist] retain];
+            libvlc_media_list_release( p_mlist );
+            /* This is an exception, and we owns it here */
+            ownHisMediaList = YES;
+        }
+
+        cachedNode = [[NSMutableArray alloc] initWithCapacity:libvlc_media_list_view_count(p_mlv, NULL)];
+        libvlc_media_list_t * p_mlist;
+        p_mlist = libvlc_media_list_view_parent_media_list( p_mlv, NULL );
+        libvlc_media_list_lock( p_mlist );
+        int i, count = libvlc_media_list_view_count(p_mlv, NULL);
+        for( i = 0; i < count; i++ )
+        {
+            libvlc_media_descriptor_t * p_md = libvlc_media_list_view_item_at_index(p_mlv, i, NULL);
+            libvlc_media_list_view_t * p_sub_mlv = libvlc_media_list_view_children_at_index(p_mlv, i, NULL);
+            VLCMediaListAspectNode * node = [[[VLCMediaListAspectNode alloc] init] autorelease];
+            [node setMedia:[VLCMedia mediaWithLibVLCMediaDescriptor: p_md]];
+            [node setChildren: p_sub_mlv ? [VLCMediaListAspect mediaListAspectWithLibVLCMediaListView: p_sub_mlv] : nil];
+            [cachedNode addObject:node];
+            libvlc_media_descriptor_release(p_md);
+            if( p_sub_mlv ) libvlc_media_list_view_release(p_sub_mlv);
+        }
         [self initInternalMediaListView];
+        libvlc_media_list_unlock( p_mlist );
+        libvlc_media_list_release( p_mlist );
     }
     return self;
 }
@@ -133,15 +241,47 @@ static void HandleMediaListViewWillDeleteItem(const libvlc_event_t *event, void
     libvlc_exception_t e;
     libvlc_exception_init( &e );
 
-    libvlc_event_manager_t *p_em = libvlc_media_list_event_manager( p_mlv, &e );
+    libvlc_event_manager_t * p_em = libvlc_media_list_event_manager( p_mlv, &e );
 
     /* Add internal callback */
     libvlc_event_attach( p_em, libvlc_MediaListViewItemAdded,   HandleMediaListViewItemAdded,   self, &e );
-    libvlc_event_attach( p_em, libvlc_MediaListViewWillAddItem, HandleMediaListViewWillAddItem, self, &e );
     libvlc_event_attach( p_em, libvlc_MediaListViewItemDeleted, HandleMediaListViewItemDeleted, self, &e );
-    libvlc_event_attach( p_em, libvlc_MediaListViewWillDeleteItem, HandleMediaListViewWillDeleteItem, self, &e );
+    catch_exception( &e );
+}
+
+- (void)mediaListViewItemAdded:(NSArray *)arrayOfArgs
+{
+    NSAssert([NSThread isMainThread], @"We are not on main thread");
 
-    quit_on_exception( &e );
+    /* We hope to receive index in a nide range, that could change one day */
+    int start = [[[arrayOfArgs objectAtIndex: 0] objectForKey:@"index"] intValue];
+    int end = [[[arrayOfArgs objectAtIndex: [arrayOfArgs count]-1] objectForKey:@"index"] intValue];
+    NSRange range = NSMakeRange(start, end-start);
+
+    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] forKey:@"media"];
+    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] forKey:@"node"];
+    for( NSDictionary * args in arrayOfArgs )
+    {
+        int index = [[args objectForKey:@"index"] intValue];
+        VLCMedia * media = [args objectForKey:@"media"];
+        VLCMediaListAspectNode * node = [[[VLCMediaListAspectNode alloc] init] autorelease];
+        [node setMedia:media];
+        [node setChildren:[self childrenAtIndex:index]];
+        /* Sanity check */
+        if( index && index > [cachedNode count] )
+            index = [cachedNode count];
+        [cachedNode insertObject:node atIndex:index];
+    }
+    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] forKey:@"node"];
+    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] forKey:@"media"];
 }
-@end
 
+- (void)mediaListViewItemRemoved:(NSNumber *)index
+{
+    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"media"];
+    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"node"];
+    [cachedNode removeObjectAtIndex:[index intValue]];
+    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"node"];
+    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:[NSIndexSet indexSetWithIndex:[index intValue]] forKey:@"media"];
+}
+@end