#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;
}
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