123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- /*****************************************************************************
- * VLCMediaListAspect.m: VLCKit.framework VLCMediaListAspect implementation
- *****************************************************************************
- * Copyright (C) 2007 Pierre d'Herbemont
- * Copyright (C) 2007 the VideoLAN team
- * $Id$
- *
- * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
- #import "VLCMediaListAspect.h"
- #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>
- // TODO: Documentation
- @interface VLCMediaListAspect (Private)
- /* Initializers */
- - (void)initInternalMediaListView;
- - (void)mediaListViewItemAdded:(NSArray *)args;
- - (void)mediaListViewItemRemoved:(NSNumber *)index;
- @end
- @implementation VLCMediaListAspectNode
- - (id)init
- {
- if(self = [super init])
- {
- media = nil;
- children = nil;
- }
- return self;
- }
- - (void)dealloc
- {
- [media release];
- [children release];
- [super dealloc];
- }
- @synthesize media;
- @synthesize children;
- - (BOOL)isLeaf
- {
- return self.children == nil;
- }
- @end
- @implementation VLCMediaListAspect (KeyValueCodingCompliance)
- /* For the @"media" key */
- - (int) countOfMedia
- {
- return [cachedNode count];
- }
- - (id) objectInMediaAtIndex:(int)i
- {
- return [[cachedNode objectAtIndex:i] media];
- }
- /* For the @"node" key */
- - (int) countOfNode
- {
- return [cachedNode count];
- }
- - (id) objectInNodeAtIndex:(int)i
- {
- return [cachedNode objectAtIndex:i];
- }
- @end
- /* libvlc event callback */
- static void HandleMediaListViewItemAdded(const libvlc_event_t * event, void * user_data)
- {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- id self = user_data;
- [[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 HandleMediaListViewItemDeleted( const libvlc_event_t * event, void * user_data)
- {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- id self = user_data;
- [[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_view_release(p_mlv);
- [cachedNode release];
- if( ownHisMediaList )
- [parentMediaList release];
- [super dealloc];
- }
- - (void)release
- {
- @synchronized(self)
- {
- if([self retainCount] <= 1)
- {
- /* We must make sure we won't receive new event after an upcoming dealloc
- * We also may receive a -retain in some event callback that may occcur
- * Before libvlc_event_detach. So this can't happen in dealloc */
- libvlc_event_manager_t * p_em = libvlc_media_list_view_event_manager(p_mlv);
- libvlc_event_detach(p_em, libvlc_MediaListViewItemDeleted, HandleMediaListViewItemDeleted, self, NULL);
- libvlc_event_detach(p_em, libvlc_MediaListViewItemAdded, HandleMediaListViewItemAdded, self, NULL);
- }
- [super release];
- }
- }
- - (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_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]];
- libvlc_media_list_view_t * p_sub_mlv = libvlc_media_list_view_children_for_item([self libVLCMediaListView], [node.media libVLCMediaDescriptor], NULL);
- if( p_sub_mlv )
- {
- [node setChildren:[VLCMediaListAspect mediaListAspectWithLibVLCMediaListView: p_sub_mlv]];
- libvlc_media_list_view_release(p_sub_mlv);
- }
- 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 );
- catch_exception( &p_e );
- return result;
- }
- - (VLCMediaList *)parentMediaList
- {
- return parentMediaList;
- }
- @end
- @implementation VLCMediaListAspect (LibVLCBridging)
- + (id)mediaListAspectWithLibVLCMediaListView:(libvlc_media_list_view_t *)p_new_mlv
- {
- return [[[VLCMediaListAspect alloc] initWithLibVLCMediaListView:p_new_mlv andMediaList:nil] autorelease];
- }
- + (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_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];
- if( p_sub_mlv ) NSAssert(![node isLeaf], @"Not leaf");
- [cachedNode addObject:node];
- libvlc_media_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_media_list_view_t *)libVLCMediaListView
- {
- return (libvlc_media_list_view_t *)p_mlv;
- }
- @end
- @implementation VLCMediaListAspect (Private)
- - (void)initInternalMediaListView
- {
- libvlc_exception_t e;
- libvlc_exception_init( &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_MediaListViewItemDeleted, HandleMediaListViewItemDeleted, self, &e );
- catch_exception( &e );
- }
- - (void)mediaListViewItemAdded:(NSArray *)arrayOfArgs
- {
- NSAssert([NSThread isMainThread], @"We are not on main thread");
- /* 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];
- /* Set the sub media list view we enventually have */
- libvlc_media_list_view_t * p_sub_mlv = libvlc_media_list_view_children_for_item([self libVLCMediaListView], [media libVLCMediaDescriptor], NULL);
- if( p_sub_mlv )
- {
- [node setChildren:[VLCMediaListAspect mediaListAspectWithLibVLCMediaListView: p_sub_mlv]];
- libvlc_media_list_view_release(p_sub_mlv);
- NSAssert(![node isLeaf], @"Not leaf");
- }
- /* 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"];
- }
- - (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
|