MacOSX/VLC_app: Initial import. Big playlist still causes memory and cpu high load...
authorPierre d'Herbemont <pdherbemont@videolan.org>
Tue, 1 Jan 2008 15:34:28 +0000 (15:34 +0000)
committerPierre d'Herbemont <pdherbemont@videolan.org>
Tue, 1 Jan 2008 15:34:28 +0000 (15:34 +0000)
25 files changed:
extras/MacOSX/VLC_app/English.lproj/MainMenu.nib/classes.nib
extras/MacOSX/VLC_app/English.lproj/MainMenu.nib/info.nib
extras/MacOSX/VLC_app/English.lproj/MainMenu.nib/keyedobjects.nib
extras/MacOSX/VLC_app/Icons/applications-internet.png [new file with mode: 0644]
extras/MacOSX/VLC_app/Icons/dialog-error.png [new file with mode: 0644]
extras/MacOSX/VLC_app/Info.plist
extras/MacOSX/VLC_app/Sources/ImageAndTextCell.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/ImageAndTextCell.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCAppAdditions.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCAppAdditions.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCAppBindings.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCAppBindings.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCBrowsableVideoView.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCBrowsableVideoView.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCController.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCController.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCExceptionHandler.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCExceptionHandler.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCMainWindow.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCMainWindow.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCMediaArrayController.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCMediaArrayController.m [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCValueTransformer.h [new file with mode: 0644]
extras/MacOSX/VLC_app/Sources/VLCValueTransformer.m [new file with mode: 0644]
extras/MacOSX/VLC_app/VLC.xcodeproj/project.pbxproj

index de4dad6..5c4af24 100644 (file)
@@ -5,14 +5,13 @@
        <key>IBClasses</key>
        <array>
                <dict>
-                       <key>CLASS</key>
-                       <string>VLCCategoryOutlineView</string>
-                       <key>LANGUAGE</key>
-                       <string>ObjC</string>
-                       <key>SUPERCLASS</key>
-                       <string>NSOutlineView</string>
-               </dict>
-               <dict>
+                       <key>ACTIONS</key>
+                       <dict>
+                               <key>detailListItemDoubleClicked</key>
+                               <string>id</string>
+                               <key>newMainWindow</key>
+                               <string>id</string>
+                       </dict>
                        <key>CLASS</key>
                        <string>VLCController</string>
                        <key>LANGUAGE</key>
                        <dict>
                                <key>categoryList</key>
                                <string>id</string>
+                               <key>detailItemFetchedStatus</key>
+                               <string>id</string>
+                               <key>detailItemsCount</key>
+                               <string>id</string>
                                <key>detailList</key>
                                <string>id</string>
                                <key>detailSearchField</key>
                                <string>id</string>
-                               <key>videoView</key>
+                               <key>fillScreenButton</key>
                                <string>id</string>
+                               <key>videoView</key>
+                               <string>VLCBrowsableVideoView</string>
                        </dict>
                        <key>SUPERCLASS</key>
                        <string>NSObject</string>
                        <key>SUPERCLASS</key>
                        <string>NSObject</string>
                </dict>
+               <dict>
+                       <key>ACTIONS</key>
+                       <dict>
+                               <key>moveDown</key>
+                               <string>id</string>
+                               <key>moveUp</key>
+                               <string>id</string>
+                       </dict>
+                       <key>CLASS</key>
+                       <string>VLCBrowsableVideoView</string>
+                       <key>LANGUAGE</key>
+                       <string>ObjC</string>
+                       <key>OUTLETS</key>
+                       <dict>
+                               <key>selectedObject</key>
+                               <string>id</string>
+                               <key>target</key>
+                               <string>id</string>
+                       </dict>
+                       <key>SUPERCLASS</key>
+                       <string>VLCVideoView</string>
+               </dict>
                <dict>
                        <key>CLASS</key>
                        <string>VLCVideoView</string>
index b07e64e..7db0647 100644 (file)
@@ -10,7 +10,7 @@
        <integer>5</integer>
        <key>IBOpenObjects</key>
        <array>
-               <integer>253</integer>
+               <integer>81</integer>
        </array>
        <key>IBSystem Version</key>
        <string>9B18</string>
index 7393aaf..038b0d6 100644 (file)
Binary files a/extras/MacOSX/VLC_app/English.lproj/MainMenu.nib/keyedobjects.nib and b/extras/MacOSX/VLC_app/English.lproj/MainMenu.nib/keyedobjects.nib differ
diff --git a/extras/MacOSX/VLC_app/Icons/applications-internet.png b/extras/MacOSX/VLC_app/Icons/applications-internet.png
new file mode 100644 (file)
index 0000000..d4bfb82
Binary files /dev/null and b/extras/MacOSX/VLC_app/Icons/applications-internet.png differ
diff --git a/extras/MacOSX/VLC_app/Icons/dialog-error.png b/extras/MacOSX/VLC_app/Icons/dialog-error.png
new file mode 100644 (file)
index 0000000..3bbbb4a
Binary files /dev/null and b/extras/MacOSX/VLC_app/Icons/dialog-error.png differ
index 212304d..8437fc7 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
        <key>CFBundleDevelopmentRegion</key>
@@ -9,7 +9,7 @@
        <key>CFBundleIconFile</key>
        <string></string>
        <key>CFBundleIdentifier</key>
-       <string>com.yourcompany.VLC</string>
+       <string>org.videolan.vlc</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundleName</key>
diff --git a/extras/MacOSX/VLC_app/Sources/ImageAndTextCell.h b/extras/MacOSX/VLC_app/Sources/ImageAndTextCell.h
new file mode 100644 (file)
index 0000000..0c11eb0
--- /dev/null
@@ -0,0 +1,42 @@
+/*****************************************************************************
+ * ImageAndTextCell.h: Helpful cell to display an image and a text.
+ * Borrowed from Apple's sample code for most part.
+ *****************************************************************************
+ * 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 <Cocoa/Cocoa.h>
+
+
+@interface ImageAndTextCell : NSTextFieldCell {
+    NSString *imageKeyPath;
+    id representedObject;
+}
+
+/* Will be set at creation time */
+@property (copy) NSString * imageKeyPath;
+
+/* Will be set through an outlineView delegate. Represent an object that respond
+ * to the imageKeyPath. Text is displayed through the usual super class
+ * @"value" bindings */
+@property (retain) id representedObject;
+
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/ImageAndTextCell.m b/extras/MacOSX/VLC_app/Sources/ImageAndTextCell.m
new file mode 100644 (file)
index 0000000..83ce808
--- /dev/null
@@ -0,0 +1,126 @@
+/*****************************************************************************
+ * ImageAndTextCell.h: Helpful cell to display an image and a text.
+ * Borrowed from Apple's sample code for most part.
+ *****************************************************************************
+ * 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 "ImageAndTextCell.h"
+
+@implementation ImageAndTextCell
+
+@synthesize imageKeyPath;
+@synthesize representedObject;
+
+- (id)init {
+    if (self = [super init]) {
+        [self setLineBreakMode:NSLineBreakByTruncatingTail];
+        [self setSelectable:YES];
+    }
+    return self;
+}
+
+- (void)dealloc {
+    [imageKeyPath release];
+    [super dealloc];
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+    ImageAndTextCell *cell = (ImageAndTextCell *)[super copyWithZone:zone];
+    cell->imageKeyPath = [imageKeyPath copy];
+    cell->representedObject = [representedObject retain];
+    return cell;
+}
+
+- (NSImage *)cellImage
+{
+    return imageKeyPath ? [[self representedObject] valueForKeyPath: imageKeyPath] : nil;
+}
+
+- (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent {
+    NSRect textFrame, imageFrame;
+    NSImage * image = [self cellImage];
+    NSDivideRect (aRect, &imageFrame, &textFrame, 6 + [image size].width, NSMinXEdge);
+    [super editWithFrame: textFrame inView: controlView editor:textObj delegate:anObject event: theEvent];
+}
+
+- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength {
+    NSRect textFrame, imageFrame;
+    NSImage * image = [self cellImage];
+    NSDivideRect (aRect, &imageFrame, &textFrame, 6 + [image size].width, NSMinXEdge);
+    [super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength];
+}
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
+    NSImage * image = [self cellImage];
+    if (image != nil) {
+        NSRect imageFrame;
+        NSSize imageSize = [image size];
+        NSDivideRect(cellFrame, &imageFrame, &cellFrame, 6 + imageSize.width, NSMinXEdge);
+        if ([self drawsBackground]) {
+            [[self backgroundColor] set];
+            NSRectFill(imageFrame);
+        }
+        imageFrame.origin.x += 3;
+        imageFrame.size = imageSize;
+
+        if ([controlView isFlipped])
+            imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
+        else
+            imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
+
+        [image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
+    }
+    [super drawWithFrame:cellFrame inView:controlView];
+}
+
+- (NSSize)cellSize {
+    NSImage * image = [self cellImage];
+    NSSize cellSize = [super cellSize];
+    cellSize.width += (image ? [image size].width : 0) + 6;
+    return cellSize;
+}
+
+- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView {
+    NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil];
+    NSImage * image = [self cellImage];
+    // If we have an image, we need to see if the user clicked on the image portion.
+    if (image != nil) {
+        // This code closely mimics drawWithFrame:inView:
+        NSSize imageSize = [image size];
+        NSRect imageFrame;
+        NSDivideRect(cellFrame, &imageFrame, &cellFrame, 6 + imageSize.width, NSMinXEdge);
+        
+        imageFrame.origin.x += 3;
+        imageFrame.size = imageSize;
+        // If the point is in the image rect, then it is a content hit
+        if (NSMouseInRect(point, imageFrame, [controlView isFlipped])) {
+            // We consider this just a content area. It is not trackable, nor it it editable text. If it was, we would or in the additional items.
+            // By returning the correct parts, we allow NSTableView to correctly begin an edit when the text portion is clicked on.
+            return NSCellHitContentArea;
+        }        
+    }
+    // At this point, the cellFrame has been modified to exclude the portion for the image. Let the superclass handle the hit testing at this point.
+    return [super hitTestForEvent:event inRect:cellFrame ofView:controlView];    
+}
+
+
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCAppAdditions.h b/extras/MacOSX/VLC_app/Sources/VLCAppAdditions.h
new file mode 100644 (file)
index 0000000..0cfbbbd
--- /dev/null
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * VLCAppAdditions.m: Helpful additions to NS* classes
+ *****************************************************************************
+ * 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 <Cocoa/Cocoa.h>
+
+@interface NSIndexPath (VLCAppAddition)
+- (NSIndexPath *)indexPathByRemovingFirstIndex;
+- (NSUInteger)lastIndex;
+@end
+
+@interface NSArray (VLCAppAddition)
+- (id)objectAtIndexPath:(NSIndexPath *)path withNodeKeyPath:(NSString *)nodeKeyPath;
+@end
+
+@interface NSView (VLCAppAdditions)
+- (void)moveSubviewsToVisible;
+@end
+
+/* Split view that supports slider animation */
+@interface VLCOneSplitView : NSSplitView
+- (float)sliderPosition;
+- (void)setSliderPosition:(float)newPosition;
+@end
\ No newline at end of file
diff --git a/extras/MacOSX/VLC_app/Sources/VLCAppAdditions.m b/extras/MacOSX/VLC_app/Sources/VLCAppAdditions.m
new file mode 100644 (file)
index 0000000..f5e58d3
--- /dev/null
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * VLCAppAdditions.m: Helpful additions to NS* classes
+ *****************************************************************************
+ * 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 "VLCAppAdditions.h"
+#import <QuartzCore/QuartzCore.h>
+
+@implementation NSIndexPath (VLCAppAddition)
+- (NSIndexPath *)indexPathByRemovingFirstIndex
+{
+    if( [self length] <= 1 )
+        return [[[NSIndexPath alloc] init] autorelease];
+
+    NSIndexPath * ret;
+    NSUInteger * ints = malloc(sizeof(NSUInteger)*[self length]);
+    if( !ints ) return nil;
+    [self getIndexes:ints];
+
+    ret = [NSIndexPath indexPathWithIndexes:ints+1 length:[self length]-1];
+
+    free(ints);
+    return ret;
+}
+- (NSUInteger)lastIndex
+{
+    if(![self length])
+        return 0;
+    return [self indexAtPosition:[self length]-1];
+}
+@end
+
+@implementation NSArray (VLCAppAddition)
+- (id)objectAtIndexPath:(NSIndexPath *)path withNodeKeyPath:(NSString *)nodeKeyPath
+{
+    if( ![path length] || !nodeKeyPath )
+        return self;
+
+    id object = [self objectAtIndex:[path indexAtPosition:0]];
+    id subarray = [object valueForKeyPath:nodeKeyPath];
+    if([path length] == 1)
+        return subarray ? subarray : object;
+
+    if(!subarray)
+        return object;
+    return [subarray objectAtIndexPath:[path indexPathByRemovingFirstIndex] withNodeKeyPath:nodeKeyPath];
+}
+@end
+
+@implementation NSView (VLCAppAdditions)
+- (void)moveSubviewsToVisible
+{
+    for(NSView * view in [self subviews])
+    {
+        if( ([view autoresizingMask] & NSViewHeightSizable) &&
+            !NSContainsRect([view frame], [self bounds]) )
+        {
+            NSRect newFrame = NSIntersectionRect( [self bounds], [view frame] );
+            if( !NSIsEmptyRect(newFrame) )
+                [view setFrame:NSIntersectionRect( [self bounds], [view frame] )];
+        }
+    }
+}
+@end
+
+/* Split view that supports slider animation */
+@implementation VLCOneSplitView
+- (float)sliderPosition
+{
+    return [[[self subviews] objectAtIndex:0] frame].size.height;
+}
+- (void)setSliderPosition:(float)newPosition
+{
+    [self setPosition:newPosition ofDividerAtIndex:0];
+}
++ (id)defaultAnimationForKey:(NSString *)key
+{
+    if([key isEqualToString:@"sliderPosition"])
+    {
+        return [CABasicAnimation animation];
+    }
+    return [super defaultAnimationForKey: key];
+}
+@end
+
diff --git a/extras/MacOSX/VLC_app/Sources/VLCAppBindings.h b/extras/MacOSX/VLC_app/Sources/VLCAppBindings.h
new file mode 100644 (file)
index 0000000..2bd5876
--- /dev/null
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * VLCAppBindings.m: Helpful addition code related to bindings uses
+ *****************************************************************************
+ * 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 <Cocoa/Cocoa.h>
+#import <VLC/VLC.h>
+
+/* We do implement some category functions,
+ * But we don't publicise them, as they should
+ * only be used with bindings. */
+
+@interface VLCMediaDiscoverer (VLCAppBindings)
+@end
+
+@interface VLCMedia (VLCAppBindings)
+@end
+
+@interface VLCMediaPlayer (VLCAppBindings)
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCAppBindings.m b/extras/MacOSX/VLC_app/Sources/VLCAppBindings.m
new file mode 100644 (file)
index 0000000..5c66ccc
--- /dev/null
@@ -0,0 +1,208 @@
+/*****************************************************************************
+ * VLCAppBindings.m: Helpful addition code related to bindings uses
+ *****************************************************************************
+ * 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 "VLCAppBindings.h"
+
+/* This is globally a big hack to ease binding uses */
+
+
+/******************************************************************************
+ * VLCMediaDiscoverer (MasterViewBindings)
+ */
+@implementation VLCMediaDiscoverer (MasterViewBindings)
++(void)initialize
+{
+    [VLCMediaDiscoverer setKeys:[NSArray arrayWithObject:@"running"] triggerChangeNotificationsForDependentKey:@"currentlyFetchingItems"];
+}
+
++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
+{
+    /* Thanks to Julien Robert, we'll have some nice auto triggered KVO event from here */
+    static NSDictionary * dict = nil;
+    if( !dict )
+    {
+        dict = [[NSDictionary dictionaryWithObjectsAndKeys:
+            [NSSet setWithObject:@"discoveredMedia.flatAspect"], @"childrenInMasterViewForDetailView",
+            nil] retain];
+    }
+    return [dict objectForKey: key];
+}
+
+/* General shortcuts */
+- (BOOL)currentlyFetchingItems
+{
+    return [self isRunning];
+}
+- (NSImage *)image
+{
+    static NSImage * sdImage = nil;
+    if( !sdImage )
+        sdImage = [[NSImage imageNamed:@"applications-internet.png"] retain];
+    return sdImage;
+}
+
+/* MasterView specific bindings */
+- (NSArray *)childrenInMasterView
+{
+    return nil;
+}
+- (NSString *)descriptionInMasterView
+{
+    return [self localizedName];
+}
+- (VLCMediaListAspect *)childrenInMasterViewForDetailView
+{
+    return [[self discoveredMedia] flatAspect];
+}
+- (BOOL)editableInMasterView
+{
+    return NO;
+}
+- (BOOL)selectableInMasterView
+{
+    return YES;
+}
+
+/* VideoView specific bindings */
+- (NSArray *)childrenInVideoView
+{
+    return [[[self discoveredMedia] flatAspect] valueForKeyPath:@"media"];
+}
+
+- (NSString *)descriptionInVideoView
+{
+    return [self localizedName];
+}
+- (BOOL)isLeaf
+{
+    return YES;
+}
+
+@end
+
+/******************************************************************************
+ * VLCMedia (VLCAppBindings)
+ */
+@implementation VLCMedia (VLCAppBindings)
+
++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
+{
+    /* Thanks to Julien Robert, we'll have some nice auto triggered KVO event from here */
+    static NSDictionary * dict = nil;
+    if( !dict )
+    {
+        dict = [[NSDictionary dictionaryWithObjectsAndKeys:
+            [NSSet setWithObject:@"subitems.hierarchicalNodeAspect.media"], @"childrenInMasterView",
+            [NSSet setWithObject:@"metaDictionary.title"], @"descriptionInMasterView",
+            [NSSet setWithObject:@"subitems.flatAspect"], @"childrenInMasterViewForDetailView",
+            [NSSet setWithObject:@"metaDictionary.title"], @"descriptionInVideoView",
+            [NSSet setWithObject:@"state"], @"stateAsImage",
+            nil] retain];
+    }
+    return [dict objectForKey: key];
+}
+
+/* MasterView specific bindings */
+- (NSArray *)childrenInMasterView
+{
+    return [[[self subitems] hierarchicalNodeAspect] valueForKeyPath:@"media"];
+}
+- (void)setDescriptionInMasterView:(NSString *)description
+{
+    NSLog(@"unimplemented: meta edition");
+}
+- (NSString *)descriptionInMasterView
+{
+    return [[self metaDictionary] objectForKey:@"title"];
+}
+- (VLCMediaListAspect *)childrenInMasterViewForDetailView
+{
+    return [[self subitems] flatAspect];
+}
+- (BOOL)editableInMasterView
+{
+    return YES;
+}
+- (BOOL)selectableInMasterView
+{
+    return YES;
+}
+- (BOOL)currentlyFetchingItems
+{
+    return NO;
+}
+- (NSImage *)image
+{
+    static NSImage * playlistImage = nil;
+    if( !playlistImage )
+        playlistImage = [[NSImage imageNamed:@"type_playlist.png"] retain];
+    return playlistImage;
+}
+
+/* VideoView specific bindings */
+- (NSArray *)childrenInVideoView
+{
+    return [[[self subitems] flatAspect] valueForKeyPath:@"media"];
+}
+- (NSString *)descriptionInVideoView
+{
+    return [[self metaDictionary] objectForKey:@"title"];
+}
+
+/* DetailList specific bindings */
+- (NSImage *)stateAsImage
+{
+    static NSImage * playing = nil;
+    static NSImage * error = nil;
+
+    if(!playing)
+        playing = [[NSImage imageNamed:@"volume_high.png"] retain];
+    if(!error)
+        error = [[NSImage imageNamed:@"dialog-error.png"] retain];
+
+    if( [self state] == VLCMediaStatePlaying )
+        return playing;
+    else if( [self state] == VLCMediaStateBuffering )
+        return playing;
+    else if( [self state] == VLCMediaStateError )
+        return error;
+
+    return nil;
+}
+@end
+
+@implementation VLCMediaPlayer (VLCAppBindings)
++ (void)initialize
+{
+    [self setKeys:[NSArray arrayWithObjects:@"playing", @"media", nil] triggerChangeNotificationsForDependentKey:@"description"];
+}
+
+- (NSString *)description
+{
+    if([self media])
+        return [self valueForKeyPath:@"media.metaDictionary.title"];
+    else
+        return @"VLC Media Player";
+}
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCBrowsableVideoView.h b/extras/MacOSX/VLC_app/Sources/VLCBrowsableVideoView.h
new file mode 100644 (file)
index 0000000..d8f3d5d
--- /dev/null
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * VLCBrowsableVideoView.h: VideoView subclasses that allow fullscreen
+ * browsing
+ *****************************************************************************
+ * 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 <QuartzCore/QuartzCore.h>
+#import <VLC/VLC.h>
+
+@interface VLCBrowsableVideoView : VLCVideoView {
+    BOOL            menuDisplayed;
+    NSArray *       itemsTree;
+    NSRange         displayedItems;
+    NSInteger       selectedIndex;
+    CALayer *       selectionLayer;
+    CALayer *       backLayer;
+    CALayer *       menuLayer;
+    NSIndexPath *   selectedPath;
+    NSString *      nodeKeyPath;
+    NSString *      contentKeyPath;
+    id              selectedObject;
+
+    /* Actions on non-node items*/
+    id target;
+    SEL action;
+}
+
+/* Binds an nsarray to that property. But don't forget the set the access keys. */
+@property (retain) NSArray * itemsTree;
+@property (copy) NSString * nodeKeyPath;
+@property (copy) NSString * contentKeyPath;
+
+@property (readonly, retain) id selectedObject;
+
+/* Set up a specific action to do, on items that don't have node.
+ * action first argument is the browsableVideoView. You can get the selected object,
+ * with -selectedObject */
+@property (retain) id target;
+@property  SEL action;
+
+- (void)toggleMenu;
+- (void)displayMenu;
+- (void)hideMenu;
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCBrowsableVideoView.m b/extras/MacOSX/VLC_app/Sources/VLCBrowsableVideoView.m
new file mode 100644 (file)
index 0000000..aaf2a8d
--- /dev/null
@@ -0,0 +1,403 @@
+/*****************************************************************************
+ * VLCBrowsableVideoView.h: VideoView subclasses that allow fullscreen
+ * browsing
+ *****************************************************************************
+ * 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 "VLCBrowsableVideoView.h"
+#import "VLCAppAdditions.h"
+
+/* TODO: We may want to clean up the private functions a bit... */
+
+@interface VLCBrowsableVideoView ()
+/* Property */
+@property (readwrite, retain) id selectedObject;
+@end
+
+@interface VLCBrowsableVideoView (Private)
+
+/* Methods */
++ (CAScrollLayer *)menuLayer;
++ (CALayer *)backLayer;
+
+- (void)loadItemsAtIndexPath:(NSIndexPath *)path inLayer:(CALayer *)layer;
+- (void)changeSelectedIndex:(NSInteger)i;
+- (void)changeSelectedPath:(NSIndexPath *)newPath withSelectedIndex:(NSUInteger)newIndex;
+
+- (void)displayEmptyView;
+@end
+
+
+/******************************************************************************
+ * VLCBrowsableVideoView
+ */
+@implementation VLCBrowsableVideoView
+
+/* Property */
+@synthesize nodeKeyPath;
+@synthesize contentKeyPath;
+@synthesize selectedObject;
+@synthesize target;
+@synthesize action;
+
+- (NSArray *)itemsTree {
+    return itemsTree;
+}
+- (void)setItemsTree:(NSArray *)newItemsTree
+{
+    [itemsTree release];
+    itemsTree = [newItemsTree retain];
+    [self changeSelectedPath:[[[NSIndexPath alloc] init] autorelease] withSelectedIndex:0];
+}
+
+/* Initializer */
+- (void)awakeFromNib
+{
+    // FIXME: do that in -initWithFrame:
+    [self setWantsLayer:YES];
+    menuDisplayed = NO;
+    displayedItems = NSMakeRange( -1, 0 );
+    selectedIndex = -1;
+    selectionLayer = backLayer = nil;
+    menuLayer = nil;
+    selectedPath = [[NSIndexPath alloc] init];
+    /* Observe our bindings */
+    //[self displayMenu];
+    //[self changeSelectedIndex:0];
+}
+
+
+/* Hiding/Displaying the menu */
+
+- (void)hideMenu
+{
+    if( !menuDisplayed )
+        return; /* Nothing to do */
+
+    [menuLayer removeFromSuperlayer];
+    [selectionLayer removeFromSuperlayer];
+    [backLayer removeFromSuperlayer];
+    //[menuLayer autorelease]; /* Need gc for that */
+    //[selectionLayer autorelease];
+    //[backLayer autorelease];
+    selectionLayer = backLayer = nil;
+    menuLayer = nil;
+    menuDisplayed = NO;
+}
+
+- (void)displayMenu
+{
+    if( menuDisplayed || !self.itemsTree )
+        return; /* Nothing to do */
+
+    if( !menuLayer )
+    {
+        CALayer * rootLayer = [self layer];
+        rootLayer.backgroundColor = CGColorGetConstantColor(kCGColorBlack);
+        rootLayer.layoutManager = [CAConstraintLayoutManager layoutManager];
+        menuLayer = [VLCBrowsableVideoView menuLayer];
+        [self loadItemsAtIndexPath: selectedPath inLayer: menuLayer];
+    }
+    if( !backLayer )
+    {
+        backLayer = [[VLCBrowsableVideoView backLayer] retain];
+    }
+    [[self layer] addSublayer:backLayer];
+    [[self layer] addSublayer:menuLayer];
+
+    [[self layer] setNeedsLayout];
+    [[self layer] setNeedsDisplay];
+
+    menuDisplayed = YES;
+    [self changeSelectedPath:selectedPath withSelectedIndex:selectedIndex];
+}
+
+- (void)toggleMenu
+{
+    if( menuDisplayed )
+        [self hideMenu];
+    else
+        [self displayMenu];
+}
+
+
+/* Event handling */
+
+- (BOOL)acceptsFirstResponder
+{
+    return YES;
+}
+
+-(void)moveUp:(id)sender
+{
+    [self changeSelectedIndex:selectedIndex-1];
+}
+
+-(void)moveDown:(id)sender
+{
+    [self changeSelectedIndex:selectedIndex+1];
+}
+
+- (void)keyDown:(NSEvent *)theEvent
+{
+    if(([[theEvent charactersIgnoringModifiers] characterAtIndex:0] == 13) && menuDisplayed)
+    {
+        [self changeSelectedPath:[selectedPath indexPathByAddingIndex:selectedIndex] withSelectedIndex:0];
+    }
+    else if([[theEvent charactersIgnoringModifiers] characterAtIndex:0] ==  NSLeftArrowFunctionKey && menuDisplayed)
+    {
+        if( [selectedPath length] > 0 )
+            [self changeSelectedPath:[selectedPath indexPathByRemovingLastIndex] withSelectedIndex:[selectedPath lastIndex]];
+        else
+            [self hideMenu];
+    }
+    else if(!menuDisplayed)
+    {
+        [self displayMenu];
+    }
+    else
+        [super keyDown: theEvent];
+
+}
+@end
+
+/******************************************************************************
+ * VLCBrowsableVideoView (Private)
+ */
+@implementation VLCBrowsableVideoView (Private)
++ (CAScrollLayer *)menuLayer
+{
+    CAScrollLayer * layer = [CAScrollLayer layer];
+    layer.scrollMode = kCAScrollVertically;
+            
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMaxY]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMaxX]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMinX]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMinY]];
+    return layer;
+}
+
++ (CALayer *)backLayer
+{
+    CALayer * layer = [CALayer layer];
+            
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMaxY]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMaxX]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMinX]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMinY]];
+
+    layer.opacity = 1.0;
+    layer.backgroundColor = CGColorCreateGenericRGB(0., 0., 0., .5);
+    return layer;
+}
+
+
+- (void)loadItemsAtIndexPath:(NSIndexPath *)path inLayer:(CALayer *)layer
+{
+    const CGFloat height=70.0;
+    const CGFloat fontSize=48.0;
+    NSArray * items = [self.itemsTree objectAtIndexPath:path withNodeKeyPath:self.nodeKeyPath]; 
+    int i;
+
+    for( i = 0; i < [items count]; i++ )
+    {
+        CATextLayer *menuItemLayer=[CATextLayer layer];
+        id item = [items objectAtIndex: i];
+        menuItemLayer.string = self.contentKeyPath ? [item valueForKeyPath:self.contentKeyPath] : @"No content Key path set";
+        menuItemLayer.font = @"BankGothic-Light";
+        menuItemLayer.fontSize = fontSize;
+        menuItemLayer.foregroundColor = CGColorCreateGenericRGB(1.0,1.0,1.0,1.0);
+        menuItemLayer.shadowColor = CGColorCreateGenericRGB(0.0,0.0,0.0,1.0);
+        menuItemLayer.shadowOpacity = 0.7;
+        menuItemLayer.shadowRadius = 2.0;
+
+        menuItemLayer.frame = CGRectMake( 40., height*(-i) + layer.visibleRect.size.height, 500.0f,70.);
+        [layer addSublayer: menuItemLayer];
+    }
+
+/*    for(i=0; i < [[layer sublayers] count]; i++)
+        NSLog(@"%d, %@", i, [[[layer sublayers] objectAtIndex: i] string]);
+    NSLog(@"---");*/
+}
+
+- (void)changeSelectedIndex:(NSInteger)i
+{
+    BOOL justCreatedSelectionLayer = NO;
+    if( !menuDisplayed )
+    {
+        selectedIndex = i;
+        return;
+    }
+
+    if( !selectionLayer )
+    {
+        justCreatedSelectionLayer = YES;
+        /* Rip-off from Apple's Sample code */
+        selectionLayer=[[CALayer layer] retain];
+        
+        selectionLayer.borderWidth=2.0;
+        selectionLayer.borderColor=CGColorCreateGenericRGB(1.0f,1.0f,1.0f,1.0f);
+        selectionLayer.backgroundColor=CGColorCreateGenericRGB(.9f,1.0f,1.0f,.1f);
+        
+        CIFilter *filter = [CIFilter filterWithName:@"CIBloom"];
+        [filter setDefaults];
+        [filter setValue:[NSNumber numberWithFloat:5.0] forKey:@"inputRadius"];
+        
+        [filter setName:@"pulseFilter"];
+        
+        [selectionLayer setFilters:[NSArray arrayWithObject:filter]];
+        
+        CABasicAnimation* pulseAnimation = [CABasicAnimation animation];
+        
+        pulseAnimation.keyPath = @"filters.pulseFilter.inputIntensity";
+        
+        pulseAnimation.fromValue = [NSNumber numberWithFloat: 0.0];
+        pulseAnimation.toValue = [NSNumber numberWithFloat: 3.0];
+        
+        pulseAnimation.duration = 2.0;
+        pulseAnimation.repeatCount = 1e100f;
+        pulseAnimation.autoreverses = YES;
+        
+        pulseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:
+                                         kCAMediaTimingFunctionEaseInEaseOut];
+        
+        [selectionLayer addAnimation:pulseAnimation forKey:@"pulseAnimation"];
+        [[self layer] addSublayer:selectionLayer];
+    }
+    NSArray * items = [self.itemsTree objectAtIndexPath:selectedPath withNodeKeyPath:self.nodeKeyPath];
+    if( i < 0 ) i = 0;
+    if( i >= [items count] ) i = [items count] - 1;
+
+    CALayer * layer = [[menuLayer sublayers] objectAtIndex: i];
+    CGRect frame = layer.frame;
+    if( i == 0 )
+    {
+        frame.origin.y -= [self layer].bounds.size.height - frame.size.height;
+        frame.size.height = [self layer].bounds.size.height;
+    }
+    [(CAScrollLayer*)menuLayer scrollToRect:frame];
+
+    if( !justCreatedSelectionLayer ) /* Get around an artifact on first launch */
+        [CATransaction flush]; /* Make sure we get the "right" layer.frame */
+
+    frame = [[self layer] convertRect:layer.frame fromLayer:[layer superlayer]];
+    frame.size.width += 200.;
+    frame.origin.x -= 100.f;
+    selectionLayer.frame = frame;
+    
+    selectionLayer.cornerRadius = selectionLayer.bounds.size.height / 2.;
+    selectedIndex = i;
+}
+
+- (void)changeSelectedPath:(NSIndexPath *)newPath withSelectedIndex:(NSUInteger)newIndex
+{
+    if( menuDisplayed )
+    {
+        id object = [itemsTree objectAtIndexPath:newPath withNodeKeyPath:nodeKeyPath];
+        /* Make sure we are in a node */
+        if( ![object isKindOfClass:[NSArray class]] )
+        {
+            self.selectedObject = object;
+            if( !self.target || !self.action )
+            {
+                [NSException raise:@"VLCBrowsableVideoViewNoActionSpecified" format:@"*** Exception [%@]: No action specified.", [self class]];
+                return;
+            }
+            void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[self.target methodForSelector: self.action];
+
+            method( self.target, self.action, self);
+
+            [self hideMenu];
+            return;
+        }
+        
+        /* Make sure the node isn't empty */
+        if( ![object count] )
+        {
+            [self displayEmptyView];
+        }
+        else
+        {
+            CALayer * newMenuLayer = [VLCBrowsableVideoView menuLayer];
+            if( menuLayer )
+                newMenuLayer.bounds = menuLayer.bounds; /* Get around some artifacts */
+            [self loadItemsAtIndexPath:newPath inLayer:newMenuLayer];
+            if( menuLayer )
+                [[self layer] replaceSublayer:menuLayer with:newMenuLayer];
+            else
+                [[self layer] addSublayer:newMenuLayer];
+            //[menuLayer autorelease]; /* warn: we need gc for that */
+            menuLayer = [newMenuLayer retain];
+        }
+    }
+    [selectedPath release];
+    selectedPath = [newPath retain];
+    [self changeSelectedIndex:newIndex];
+}
+
+- (void)displayEmptyView
+{
+    CALayer * layer = [CALayer layer];
+    layer.layoutManager = [CAConstraintLayoutManager layoutManager];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMaxY]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMaxX]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMinX]];
+    [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMinY]];
+        
+    CATextLayer *menuItemLayer=[CATextLayer layer];
+    menuItemLayer.string = @"Empty";
+    menuItemLayer.font = @"BankGothic-Light";
+    menuItemLayer.fontSize = 48.f;
+    menuItemLayer.foregroundColor = CGColorCreateGenericRGB(1.0,1.0,1.0,1.0);
+    menuItemLayer.shadowColor = CGColorCreateGenericRGB(0.0,0.0,0.0,1.0);
+    menuItemLayer.shadowOpacity = 0.7;
+    menuItemLayer.shadowRadius = 2.0;
+
+    [menuItemLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMidX]];
+    [menuItemLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY
+                                       relativeTo:@"superlayer" attribute:kCAConstraintMidY]];
+    [layer addSublayer:menuItemLayer];
+
+    if( menuLayer )
+        [[self layer] replaceSublayer:menuLayer with:layer];
+    else
+        [[self layer] addSublayer:layer];
+    [selectionLayer removeFromSuperlayer];
+    //[selectionLayer autorelease] /* need gc */
+    //[menuLayer autorelease] /* need gc */
+    menuLayer = layer;
+    selectionLayer = nil;
+}
+@end
\ No newline at end of file
diff --git a/extras/MacOSX/VLC_app/Sources/VLCController.h b/extras/MacOSX/VLC_app/Sources/VLCController.h
new file mode 100644 (file)
index 0000000..3003cbc
--- /dev/null
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ * VLCController.h: VLC.app main controller
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id: VLCController.h 21565 2007-08-29 21:10:20Z pdherbemont $
+ *
+ * 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 <Cocoa/Cocoa.h>
+#import <VLC/VLC.h>
+
+#import "VLCMediaArrayController.h"
+#import "VLCBrowsableVideoView.h"
+
+@class VLCMainWindow;
+
+#define VLCPanic( ex ) __VLCPanic( ex, __FUNCTION__, __FILE__, __LINE__ )
+static inline void __VLCPanic( const char * str, const char * function, const char * file, int line_number )
+{
+    NSRunCriticalAlertPanel( @"Error", [NSString stringWithFormat:@"The following error was encountered: %s (%s:%d %s)", str, file, line_number, function], @"Quit", nil, nil );
+    exit( -1 );
+}
+
+@interface VLCController : NSObject
+{
+    NSMutableArray * arrayOfPlaylists;
+    NSArray * arrayOfMasters;
+    NSArray * arrayOfVideoViewMasters;
+}
+@property (readonly, retain) NSArray * arrayOfMasters;
+@property (readonly, retain) NSArray * arrayOfVideoViewMasters;
+
+- (void)newMainWindow:(id)sender;
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCController.m b/extras/MacOSX/VLC_app/Sources/VLCController.m
new file mode 100644 (file)
index 0000000..2f71c31
--- /dev/null
@@ -0,0 +1,121 @@
+/*****************************************************************************
+ * VLCController.m: VLC.app main controller
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id: VLCController.m 23286 2007-11-23 21:40:20Z pdherbemont $
+ *
+ * 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 <VLC/VLC.h>
+
+#import "VLCController.h" 
+#import "VLCAppAdditions.h" 
+#import "VLCValueTransformer.h" 
+
+@interface VLCController ()
+@property (readwrite,retain) NSArray * arrayOfMasters;
+@property (readwrite,retain) NSArray * arrayOfVideoViewMasters;
+@end
+
+/******************************************************************************
+ * VLCBrowsableVideoView
+ */
+@implementation VLCController
+@synthesize arrayOfMasters;
+@synthesize arrayOfVideoViewMasters;
+
+- (void)awakeFromNib
+{
+    /***********************************
+     * Register our bindings value transformer
+     */
+    VLCFloat10000FoldTransformer *float100fold;
+    float100fold = [[[VLCFloat10000FoldTransformer alloc] init] autorelease];
+    [NSValueTransformer setValueTransformer:(id)float100fold forName:@"Float10000FoldTransformer"];
+    VLCNonNilAsBoolTransformer *nonNilAsBool;
+    nonNilAsBool = [[[VLCNonNilAsBoolTransformer alloc] init] autorelease];
+    [NSValueTransformer setValueTransformer:(id)nonNilAsBool forName:@"NonNilAsBoolTransformer"];
+
+    /***********************************
+     * arrayOfMasters: MasterView OutlineView content
+     */
+    NSArray * arrayOfMediaDiscoverer = [NSArray arrayWithObjects:
+        [[[VLCMediaDiscoverer alloc] initWithName:@"shoutcasttv"] autorelease],
+        [[[VLCMediaDiscoverer alloc] initWithName:@"shoutcast"] autorelease],
+        [[[VLCMediaDiscoverer alloc] initWithName:@"sap"] autorelease],
+        [[[VLCMediaDiscoverer alloc] initWithName:@"freebox"] autorelease], nil];
+
+    arrayOfPlaylists = [NSMutableArray arrayWithObjects:[VLCMedia mediaAsNodeWithName:@"Default Playlist"], nil];
+
+    NSDictionary * playlists = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                [@"Playlists" uppercaseString], @"descriptionInMasterView",
+                                [@"Playlists" uppercaseString], @"descriptionInVideoView",
+                                [NSNumber numberWithBool:NO], @"selectableInMasterView",
+                                arrayOfPlaylists, @"childrenInMasterView",
+                                arrayOfPlaylists, @"childrenInVideoView",
+                                nil];
+
+    self.arrayOfMasters = [NSArray arrayWithObjects:
+                    [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                        [@"Service Discovery" uppercaseString], @"descriptionInMasterView",
+                        [NSNumber numberWithBool:NO], @"selectableInMasterView",
+                        arrayOfMediaDiscoverer, @"childrenInMasterView",
+                        nil],
+                    playlists,
+                    nil];
+    
+
+    /***********************************
+     * videoView setup
+     */
+    self.arrayOfVideoViewMasters = [NSArray arrayWithObjects:
+                    [NSDictionary dictionaryWithObjectsAndKeys:
+                        @"Service Discovery", @"descriptionInVideoView",
+                        arrayOfMediaDiscoverer, @"childrenInVideoView",
+                        nil],
+                    playlists,
+                    nil];
+
+    /* Execution will continue in applicationDidFinishLaunching */
+    [NSApp setDelegate:self];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notification
+{
+    [self newMainWindow: self];
+}
+
+- (void)newMainWindow:(id)sender
+{
+    if (![NSBundle loadNibNamed:@"MainWindow" owner:self])
+    {
+        NSLog(@"Warning! Could not load MainWindow file.\n");
+    }
+    /* We are done. Should be on screen if Visible at launch time is checked */
+}
+
+- (void)addPlaylist:(id)sender
+{
+    [[arrayOfMasters mutableArrayValueForKey:@"[0].childrenInMasterView"] addObject:[VLCMedia mediaAsNodeWithName:@"Untitled Playlist"]];
+}
+
+@end
+
+@implementation VLCController (ExceptionHandlerDelegating)
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCExceptionHandler.h b/extras/MacOSX/VLC_app/Sources/VLCExceptionHandler.h
new file mode 100644 (file)
index 0000000..cbed1de
--- /dev/null
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ * VLCExceptionHandler.h: VLCExceptionHandler implementation
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id: VLCController.h 21565 2007-08-29 21:10:20Z pdherbemont $
+ *
+ * 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 <Cocoa/Cocoa.h>
+
+
+@interface VLCExceptionHandler : NSObject {
+
+}
+- (void)printStackTrace:(NSException *)e;
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCExceptionHandler.m b/extras/MacOSX/VLC_app/Sources/VLCExceptionHandler.m
new file mode 100644 (file)
index 0000000..828bb1d
--- /dev/null
@@ -0,0 +1,75 @@
+/*****************************************************************************
+ * VLCExceptionHandler.m: VLCExceptionHandler implementation
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id: VLCController.h 21565 2007-08-29 21:10:20Z pdherbemont $
+ *
+ * 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 "VLCExceptionHandler.h"
+#import <ExceptionHandling/ExceptionHandling.h>
+
+
+@implementation VLCExceptionHandler
++ (void)initialize
+{
+    [[NSExceptionHandler defaultExceptionHandler] setDelegate:[[VLCExceptionHandler alloc] init]];
+    [[NSExceptionHandler defaultExceptionHandler] setExceptionHandlingMask:
+                0xffff /* Catch all */ ];
+
+    [[NSExceptionHandler defaultExceptionHandler] setExceptionHangingMask:
+                NSHangOnUncaughtExceptionMask|
+                NSHangOnUncaughtSystemExceptionMask|
+                NSHangOnUncaughtRuntimeErrorMask|
+                NSHangOnTopLevelExceptionMask|
+                NSHangOnOtherExceptionMask];
+}
+
+/* From Apple's guide on exception */
+- (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldLogException:(NSException *)exception mask:(unsigned int)aMask
+{
+    [self printStackTrace:exception];
+    return YES;
+}
+- (void)printStackTrace:(NSException *)e
+{
+    NSString *stack = [[e userInfo] objectForKey:NSStackTraceKey];
+    if (!stack)
+    {
+        NSLog(@"No stack trace available.");
+        return;
+    }
+
+    NSTask *ls = [[NSTask alloc] init];
+    NSString *pid = [[NSNumber numberWithInt:[[NSProcessInfo processInfo] processIdentifier]] stringValue];
+    NSMutableArray *args = [NSMutableArray arrayWithCapacity:20];
+
+    [args addObject:@"-p"];
+    [args addObject:pid];
+    [args addObjectsFromArray:[stack componentsSeparatedByString:@"  "]];
+    /* Note: function addresses are separated by double spaces, not a single space. */
+
+    [ls setLaunchPath:@"/usr/bin/atos"];
+    [ls setArguments:args];
+    [ls launch];
+    [ls release];
+}
+
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCMainWindow.h b/extras/MacOSX/VLC_app/Sources/VLCMainWindow.h
new file mode 100644 (file)
index 0000000..dd954ed
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * VLCMainWindow.h: VLCMainWindow implementation
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id: VLCController.h 21565 2007-08-29 21:10:20Z pdherbemont $
+ *
+ * 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 <Cocoa/Cocoa.h>
+#import "VLCController.h"
+#import "VLCMediaArrayController.h"
+
+@interface VLCMainWindow : NSWindow {
+    /* IB elements */
+    IBOutlet id detailItemFetchedStatus;
+    IBOutlet id detailItemsCount;
+    IBOutlet id detailSearchField;
+
+    IBOutlet NSOutlineView * categoryList;
+    IBOutlet NSTableView * detailList;
+
+    IBOutlet VLCBrowsableVideoView * videoView;
+    IBOutlet id fillScreenButton;
+    IBOutlet id fullScreenButton;
+    IBOutlet NSSlider * mediaReadingProgressSlider;
+    IBOutlet NSTextField * mediaReadingProgressText;
+    IBOutlet NSTextField * mediaDescriptionText;
+
+    IBOutlet id navigatorViewToggleButton;
+    IBOutlet NSSplitView * mainSplitView;
+    IBOutlet NSView * navigatorView;
+    IBOutlet NSView * videoPlayerAndControlView;
+    IBOutlet NSView * controlView;
+
+    IBOutlet NSButton * addPlaylistButton;
+    IBOutlet NSButton * removePlaylistButton;
+
+    VLCMediaPlayer * mediaPlayer;
+    
+    IBOutlet VLCController * controller; /* This is a VLCController binded to the File's Owner of the nib */
+
+    /* Controllers */
+    NSTreeController * treeController;
+    VLCMediaArrayController * mediaArrayController;
+    
+    /* Window state */
+    CGFloat navigatorHeight;
+}
+
+@property BOOL navigatorViewVisible;
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCMainWindow.m b/extras/MacOSX/VLC_app/Sources/VLCMainWindow.m
new file mode 100644 (file)
index 0000000..fc87df9
--- /dev/null
@@ -0,0 +1,301 @@
+/*****************************************************************************
+ * VLCMainWindow.m: VLCMainWindow implementation
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id: VLCController.h 21565 2007-08-29 21:10:20Z pdherbemont $
+ *
+ * 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 "VLCMainWindow.h"
+#import "ImageAndTextCell.h"
+#import "VLCMediaArrayController.h"
+#import "VLCBrowsableVideoView.h"
+#import "VLCAppAdditions.h"
+
+/******************************************************************************
+ * VLCMainWindow (MasterViewDataSource)
+ */
+@implementation VLCMainWindow (MasterViewDataSource)
+- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
+{
+    return [[item representedObject] isKindOfClass:[NSDictionary class]];
+}
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
+{
+    return !([[item representedObject] isKindOfClass:[NSDictionary class]]);
+}
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+    [cell setRepresentedObject:[item representedObject]];
+}
+@end
+
+/******************************************************************************
+ * VLCMainWindow
+ */
+@implementation VLCMainWindow
+- (void)awakeFromNib;
+{
+    NSTableColumn * tableColumn;
+    
+    /* This one will be removable, so we keep a reference of it so we can safely call removeFromSuperview */
+    [navigatorView retain];    
+
+    /* Check ib outlets */
+    NSAssert( mainSplitView, @"No split view or wrong split view");
+    NSAssert( fullScreenButton, @"No fullscreen button");
+
+    /***********************************
+     * Init the media player
+     */
+    mediaPlayer = [[VLCMediaPlayer alloc] initWithVideoView:videoView];
+
+    /***********************************
+     * MasterView OutlineView content
+     */
+    /* treeController */ 
+    treeController = [[NSTreeController alloc] init];
+    [treeController setContent:controller.arrayOfMasters];
+  
+    [treeController setChildrenKeyPath:@"childrenInMasterView"];
+    //[treeController bind:@"contentArray" toObject:controller withKeyPath:@"arrayOfMasters" options:nil];
+
+    /* Bind the "name" table column */
+    tableColumn = [categoryList tableColumnWithIdentifier:@"name"];
+       [tableColumn bind:@"value" toObject: treeController withKeyPath:@"arrangedObjects.descriptionInMasterView" options:nil];
+    [tableColumn setEditable:YES];
+    /* FIXME: this doesn't work obviously. */
+       [tableColumn bind:@"editable" toObject: treeController withKeyPath:@"arrangedObjects.editableInMasterView" options:nil];
+
+    /* Use an ImageAndTextCell in the "name" table column */
+    ImageAndTextCell * cell = [[ImageAndTextCell alloc] init];
+    [cell setFont:[[tableColumn dataCell] font]];
+    [cell setImageKeyPath:@"image"];
+
+    [tableColumn setDataCell:cell];
+
+    /* Other setup */
+    [categoryList setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
+    [categoryList setDelegate:self];
+
+
+    /***********************************
+     * detailList setup
+     */
+
+    mediaArrayController = [[VLCMediaArrayController alloc] init];
+
+    /* 1- Drag and drop */
+    [detailList registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]];
+    [detailList setDataSource:mediaArrayController];
+
+    /* 2- Double click */
+    [detailList setTarget:self];
+    [detailList setDoubleAction:@selector(detailListItemDoubleClicked:)];
+
+       /* 3- binding for "title" column */
+    tableColumn = [detailList tableColumnWithIdentifier:@"title"];
+       [tableColumn bind:@"value" toObject: mediaArrayController withKeyPath:@"arrangedObjects.metaDictionary.title" options:nil];
+
+       /* 4- binding for "state" column */
+    tableColumn = [detailList tableColumnWithIdentifier:@"state"];
+       [tableColumn bind:@"value" toObject: mediaArrayController withKeyPath:@"arrangedObjects.stateAsImage" options:nil];
+
+    /* 5- Search & Predicate */
+    NSMutableDictionary * bindingOptions = [NSMutableDictionary dictionary];
+    [bindingOptions setObject:@"metaDictionary.title contains[c] $value" forKey:NSPredicateFormatBindingOption];
+    [bindingOptions setObject:@"No Title" forKey:NSDisplayNameBindingOption];
+    [detailSearchField bind:@"predicate" toObject: mediaArrayController withKeyPath:@"filterPredicate" options:bindingOptions];
+    
+    /* 6- Bind the @"contentArray" and contentMediaList of the mediaArrayController */
+    [mediaArrayController bind:@"contentArray" toObject:treeController withKeyPath:@"selection.childrenInMasterViewForDetailView.media" options:nil];
+    [mediaArrayController bind:@"contentMediaList" toObject:treeController withKeyPath:@"selection.childrenInMasterViewForDetailView.parentMediaList" options:nil];
+    
+    /* 7- Aspect */
+    [detailList setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
+    [detailList setAllowsTypeSelect:YES];
+
+    /***********************************
+     * videoView setup
+     */
+    [videoView setItemsTree:controller.arrayOfVideoViewMasters];
+    [videoView setNodeKeyPath:@"childrenInVideoView"];
+    [videoView setContentKeyPath:@"descriptionInVideoView"];
+    [videoView setTarget:self];
+    [videoView setAction:@selector(videoViewItemClicked:)];
+    
+
+    /***********************************
+     * Other interface element setup
+     */
+
+    [detailItemsCount bind:@"displayPatternValue1" toObject:mediaArrayController withKeyPath:@"arrangedObjects.@count" options:[NSDictionary dictionaryWithObject:@"%{value1}@ items" forKey:NSDisplayPatternBindingOption]];
+    [detailItemFetchedStatus bind:@"animate" toObject:treeController withKeyPath:@"selection.currentlyFetchingItems" options:[NSDictionary dictionaryWithObject:@"%{value1}@ items" forKey:NSDisplayPatternBindingOption]];
+
+    [fillScreenButton bind:@"value" toObject:videoView withKeyPath:@"fillScreen" options: [NSDictionary dictionaryWithObject:NSNegateBooleanTransformerName forKey:NSValueTransformerNameBindingOption]];
+    [fullScreenButton bind:@"value" toObject:videoView withKeyPath:@"fullScreen" options: nil];
+    [fullScreenButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"playing" options: nil];
+    [fillScreenButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"playing" options: nil];
+
+    [mediaReadingProgressSlider bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
+    [mediaReadingProgressSlider bind:@"enabled2" toObject:mediaPlayer withKeyPath:@"seekable" options: nil];
+
+    [mediaReadingProgressSlider bind:@"value" toObject:mediaPlayer withKeyPath:@"position" options:
+        [NSDictionary dictionaryWithObjectsAndKeys:@"Float10000FoldTransformer", NSValueTransformerNameBindingOption,
+                                                  [NSNumber numberWithBool:NO], NSConditionallySetsEnabledBindingOption, nil ]];
+    [mediaReadingProgressText bind:@"value" toObject:mediaPlayer withKeyPath:@"time.stringValue" options: nil];
+    [mediaDescriptionText bind:@"value" toObject:mediaPlayer withKeyPath:@"description" options: nil];
+
+    [navigatorViewToggleButton bind:@"value" toObject:self withKeyPath:@"navigatorViewVisible" options: nil];
+
+    /* Playlist buttons */
+    [removePlaylistButton bind:@"enabled" toObject:treeController withKeyPath:@"selection.editableInMasterView" options: nil];
+    [removePlaylistButton setTarget:treeController];
+    [removePlaylistButton setAction:@selector(remove:)];
+    [addPlaylistButton setTarget:controller];
+    [addPlaylistButton setAction:@selector(addPlaylist:)];
+
+    [mainSplitView setDelegate:self];
+
+    /* Last minute setup */
+    [categoryList expandItem:nil expandChildren:YES];
+    [categoryList selectRowIndexes:[NSIndexSet indexSetWithIndex:[categoryList numberOfRows] > 0 ? [categoryList numberOfRows]-1 : 0] byExtendingSelection:NO];
+}
+
+- (void)dealloc
+{
+    [navigatorView release];
+    [mediaPlayer release];
+    [treeController release];
+    [mediaArrayController release];
+    [super dealloc];
+}
+
+- (void)detailListItemDoubleClicked:(id)sender
+{
+    [mediaPlayer setMedia:[[mediaArrayController selectedObjects] objectAtIndex:0]];
+    [mediaPlayer play];
+}
+
+- (void)videoViewItemClicked:(id)sender
+{
+    id object = [sender selectedObject];
+    NSAssert( [object isKindOfClass:[VLCMedia class]], @"Object is not a VLCMedia" );
+
+    [mediaPlayer setMedia:object];
+    [mediaPlayer play];
+}
+
+- (BOOL)videoViewVisible
+{
+    NSAssert( mainSplitView && [[mainSplitView subviews] count] == 2, @"No split view or wrong split view");
+    return  ([[[mainSplitView subviews] objectAtIndex:0] frame].size.height > 50.);
+}
+
+- (BOOL)navigatorViewVisible
+{
+    NSAssert( mainSplitView && [[mainSplitView subviews] count] == 2, @"No split view or wrong split view");
+    return  ([[[mainSplitView subviews] objectAtIndex:1] frame].size.height > 6.);
+}
+
+
+- (void)setNavigatorViewVisible:(BOOL)visible
+{
+    NSAssert( mainSplitView && [[mainSplitView subviews] count] == 2, @"No split view or wrong split view");
+    if(!([self navigatorViewVisible] ^ visible))
+        return; /* Nothing to do */
+    
+    if(visible)
+    {
+        if( !navigatorHeight ) navigatorHeight = 100.f;
+        if( ![self videoViewVisible] && ![self navigatorViewVisible] )
+        {
+            NSRect frame = [self frame];
+            frame.origin.y -= navigatorHeight;
+            frame.size.height += navigatorHeight;
+            [[self animator] setFrame:frame display:YES];
+        }
+        else
+            [[mainSplitView animator] setSliderPosition:([mainSplitView bounds].size.height - navigatorHeight - [mainSplitView dividerThickness])];
+        /* Hack, because sliding cause some glitches */
+        [navigatorView moveSubviewsToVisible];
+    }
+    else
+    {
+        navigatorHeight = [navigatorView bounds].size.height;
+        NSRect frame0 = [self frame];
+        NSRect frame1 = [[[mainSplitView subviews] objectAtIndex: 1] frame];
+        frame0.size.height -= frame1.size.height;
+        frame0.origin.y += frame1.size.height;
+        frame1.size.height = 0;
+        [[mainSplitView animator] setSliderPosition:([mainSplitView bounds].size.height)];
+        /* Hack, because sliding cause some glitches */
+        [navigatorView moveSubviewsToVisible];
+    }
+}
+@end
+
+@implementation VLCMainWindow (SplitViewDelegating)
+- (CGFloat)splitView:(NSSplitView *)sender constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)offset
+{
+    CGFloat minHeight = 34.;
+
+    /* Hack, because sliding cause some glitches */
+    [navigatorView moveSubviewsToVisible];
+
+    /* Get the bottom of the navigator view to get stuck at some points */
+    if( [sender bounds].size.height - proposedPosition < minHeight*3./2. &&
+        [sender bounds].size.height - proposedPosition >= minHeight/2 )
+         return [sender bounds].size.height - minHeight;
+    if( [sender bounds].size.height - proposedPosition < minHeight/2 )
+         return [sender bounds].size.height;
+    return proposedPosition;
+}
+
+- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize
+{
+    [sender  adjustSubviews];
+
+    /* Hack, because sliding cause some glitches */
+    [navigatorView setFrame:[[navigatorView superview] bounds]];
+    [navigatorView moveSubviewsToVisible];
+}
+
+- (void)splitViewWillResizeSubviews:(NSNotification *)aNotification
+{
+    /* Hack, because sliding cause some glitches */
+    [navigatorView moveSubviewsToVisible];
+    
+    /* This could be changed from now on, so post a KVO notification */
+    [self willChangeValueForKey:@"navigatorViewVisible"];
+}
+- (void)splitViewDidResizeSubviews:(NSNotification *)aNotification
+{
+    [self didChangeValueForKey:@"navigatorViewVisible"];
+}
+@end
+
+@implementation VLCMainWindow (NSWindowDelegating)
+- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
+{
+    if( proposedFrameSize.height < 120.f)
+        proposedFrameSize.height = [self minSize].height;
+    return proposedFrameSize;
+}
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCMediaArrayController.h b/extras/MacOSX/VLC_app/Sources/VLCMediaArrayController.h
new file mode 100644 (file)
index 0000000..7b426f1
--- /dev/null
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * VLCMediaArrayController.h: NSArrayController subclass specific to media
+ * list.
+ *****************************************************************************
+ * 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 <Cocoa/Cocoa.h>
+#import <VLC/VLC.h>
+
+@interface VLCMediaArrayController : NSArrayController
+{
+    VLCMediaList * contentMediaList;
+}
+
+/* Usually set through a bindings. Contents is provided by the 
+ * super class contentArray bindings. This is useful to
+ * get the media list ability to be read-write. */
+@property (retain) VLCMediaList * contentMediaList;
+
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCMediaArrayController.m b/extras/MacOSX/VLC_app/Sources/VLCMediaArrayController.m
new file mode 100644 (file)
index 0000000..462f559
--- /dev/null
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * VLCMediaArrayController.m: NSArrayController subclass specific to media
+ * list.
+ *****************************************************************************
+ * 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 "VLCMediaArrayController.h"
+
+
+@implementation VLCMediaArrayController
+@synthesize contentMediaList;
+@end
+
+/******************************************************************************
+ * VLCMediaArrayController (NSTableViewDataSource)
+ */
+@implementation VLCMediaArrayController (NSTableViewDataSource)
+
+/* Dummy implementation, because that seems to be needed */
+- (int)numberOfRowsInTableView:(NSTableView *)tableView
+{
+    return 0;
+}
+
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn
+                       row:(int)row
+{
+    return nil;
+}
+
+/* Implement drag and drop */
+- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info 
+                                proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op
+{    
+    return [contentMediaList isReadOnly] ? NSDragOperationNone : NSDragOperationGeneric;
+}
+
+- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
+                         row:(int)row dropOperation:(NSTableViewDropOperation)operation
+{
+    int i;
+    row = 0;
+    NSArray *droppedItems = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
+    
+    for (i = 0; i < [droppedItems count]; i++)
+    {
+        NSString * filename = [droppedItems objectAtIndex:i];
+               VLCMedia *media = [VLCMedia mediaWithPath:filename];
+        [contentMediaList lock];
+               [contentMediaList insertMedia:media atIndex:[contentMediaList count] > 0 ? [contentMediaList count]-1 : 0];
+        [contentMediaList unlock];
+    }
+    return YES;
+}
+@end
diff --git a/extras/MacOSX/VLC_app/Sources/VLCValueTransformer.h b/extras/MacOSX/VLC_app/Sources/VLCValueTransformer.h
new file mode 100644 (file)
index 0000000..dd2063a
--- /dev/null
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * VLCValueTransformer.m: NSValueTransformer subclasses
+ *****************************************************************************
+ * 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 <Cocoa/Cocoa.h>
+
+@interface VLCFloat10000FoldTransformer : NSValueTransformer {
+}
+@end
+
+@interface VLCNonNilAsBoolTransformer : NSValueTransformer {
+}
+@end
+
diff --git a/extras/MacOSX/VLC_app/Sources/VLCValueTransformer.m b/extras/MacOSX/VLC_app/Sources/VLCValueTransformer.m
new file mode 100644 (file)
index 0000000..bc99bda
--- /dev/null
@@ -0,0 +1,73 @@
+//
+//  VLCValueTransformer.m
+//  VLC
+//
+//  Created by Pierre d'Herbemont on 12/29/07.
+//  Copyright 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import "VLCValueTransformer.h"
+
+
+@implementation VLCFloat10000FoldTransformer
+
++ (Class)transformedValueClass
+{
+    return [NSNumber class];
+}
+
++ (BOOL)allowsReverseTransformation
+{
+    return YES;
+}
+
+- (id)transformedValue:(id)value
+{
+    if( !value ) return nil;
+    if(![value respondsToSelector: @selector(floatValue)])
+    {
+        [NSException raise: NSInternalInconsistencyException
+                    format: @"Value (%@) does not respond to -floatValue.",
+        [value class]];
+        return nil;
+    }
+    return [NSNumber numberWithFloat: [value floatValue]*10000.];
+}
+
+- (id)reverseTransformedValue:(id)value
+{
+    if( !value ) return nil;
+    if(![value respondsToSelector: @selector(floatValue)])
+    {
+        [NSException raise: NSInternalInconsistencyException
+                    format: @"Value (%@) does not respond to -floatValue.",
+        [value class]];
+        return nil;
+    }
+    return [NSNumber numberWithFloat: [value floatValue]/10000.];
+}
+@end
+
+@implementation VLCNonNilAsBoolTransformer
+
++ (Class)transformedValueClass
+{
+    return [NSObject class];
+}
+
++ (BOOL)allowsReverseTransformation
+{
+    return NO;
+}
+
+- (NSNumber *)transformedValue:(id)value
+{
+    return [NSNumber numberWithBool: !!value];
+}
+
+@end
+
index 60ca40e..064286f 100644 (file)
@@ -9,7 +9,29 @@
 /* Begin PBXBuildFile section */
                6310515A0CF7604600ACDE1E /* VLC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 631051590CF7604600ACDE1E /* VLC.framework */; };
                6310515D0CF7604900ACDE1E /* VLC.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 631051590CF7604600ACDE1E /* VLC.framework */; };
-               63C5518D0C7F663500B202D3 /* VLCController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63C5518B0C7F663500B202D3 /* VLCController.m */; };
+               633BD4BC0D2A90470012A314 /* VLCValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4AA0D2A90470012A314 /* VLCValueTransformer.m */; };
+               633BD4BD0D2A90470012A314 /* VLCMediaArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4AC0D2A90470012A314 /* VLCMediaArrayController.m */; };
+               633BD4BE0D2A90470012A314 /* VLCMainWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4AD0D2A90470012A314 /* VLCMainWindow.m */; };
+               633BD4BF0D2A90470012A314 /* VLCExceptionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4AF0D2A90470012A314 /* VLCExceptionHandler.m */; };
+               633BD4C00D2A90470012A314 /* VLCController.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4B10D2A90470012A314 /* VLCController.m */; };
+               633BD4C10D2A90470012A314 /* VLCBrowsableVideoView.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4B30D2A90470012A314 /* VLCBrowsableVideoView.m */; };
+               633BD4C20D2A90470012A314 /* VLCAppBindings.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4B50D2A90470012A314 /* VLCAppBindings.m */; };
+               633BD4C30D2A90470012A314 /* VLCAppAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4B90D2A90470012A314 /* VLCAppAdditions.m */; };
+               633BD4C40D2A90470012A314 /* ImageAndTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 633BD4BA0D2A90470012A314 /* ImageAndTextCell.m */; };
+               633BD4DA0D2A90C80012A314 /* dialog-error.png in Resources */ = {isa = PBXBuildFile; fileRef = 633BD4D80D2A90C80012A314 /* dialog-error.png */; };
+               633BD4DB0D2A90C80012A314 /* applications-internet.png in Resources */ = {isa = PBXBuildFile; fileRef = 633BD4D90D2A90C80012A314 /* applications-internet.png */; };
+               63874B190D25960600F738AD /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63874B170D25960600F738AD /* MainWindow.xib */; };
+               638F47110D216C8F008E4912 /* type_playlist.png in Resources */ = {isa = PBXBuildFile; fileRef = 638F47100D216C8F008E4912 /* type_playlist.png */; };
+               63A742B30D2759C1002D41A0 /* ExceptionHandling.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63A742B20D2759C1002D41A0 /* ExceptionHandling.framework */; };
+               63E380AA0D1C65A600FD6958 /* volume_high.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380A80D1C65A600FD6958 /* volume_high.png */; };
+               63E380AB0D1C65A600FD6958 /* volume_low.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380A90D1C65A600FD6958 /* volume_low.png */; };
+               63E380AE0D1C65D100FD6958 /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380AC0D1C65D100FD6958 /* play.png */; };
+               63E380AF0D1C65D100FD6958 /* play_blue.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380AD0D1C65D100FD6958 /* play_blue.png */; };
+               63E380B20D1C65F200FD6958 /* skip_forward_active.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380B00D1C65F200FD6958 /* skip_forward_active.png */; };
+               63E380B30D1C65F200FD6958 /* skip_forward_blue.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380B10D1C65F200FD6958 /* skip_forward_blue.png */; };
+               63E380B60D1C65FC00FD6958 /* skip_previous_active.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380B40D1C65FC00FD6958 /* skip_previous_active.png */; };
+               63E380B70D1C65FC00FD6958 /* skip_previous_blue.png in Resources */ = {isa = PBXBuildFile; fileRef = 63E380B50D1C65FC00FD6958 /* skip_previous_blue.png */; };
+               63E380DF0D1C6FD800FD6958 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63E380DE0D1C6FD800FD6958 /* QuartzCore.framework */; };
                8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
                8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
                8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
                29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
                32CA4F630368D1EE00C91783 /* VLC_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLC_Prefix.pch; sourceTree = "<group>"; };
                631051590CF7604600ACDE1E /* VLC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VLC.framework; path = ../Framework/build/Debug/VLC.framework; sourceTree = SOURCE_ROOT; };
-               63C5518A0C7F663500B202D3 /* VLCController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VLCController.h; sourceTree = "<group>"; };
-               63C5518B0C7F663500B202D3 /* VLCController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VLCController.m; sourceTree = "<group>"; };
+               633BD4AA0D2A90470012A314 /* VLCValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCValueTransformer.m; path = Sources/VLCValueTransformer.m; sourceTree = "<group>"; };
+               633BD4AB0D2A90470012A314 /* VLCValueTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCValueTransformer.h; path = Sources/VLCValueTransformer.h; sourceTree = "<group>"; };
+               633BD4AC0D2A90470012A314 /* VLCMediaArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCMediaArrayController.m; path = Sources/VLCMediaArrayController.m; sourceTree = "<group>"; };
+               633BD4AD0D2A90470012A314 /* VLCMainWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCMainWindow.m; path = Sources/VLCMainWindow.m; sourceTree = "<group>"; };
+               633BD4AE0D2A90470012A314 /* VLCMediaArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCMediaArrayController.h; path = Sources/VLCMediaArrayController.h; sourceTree = "<group>"; };
+               633BD4AF0D2A90470012A314 /* VLCExceptionHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCExceptionHandler.m; path = Sources/VLCExceptionHandler.m; sourceTree = "<group>"; };
+               633BD4B00D2A90470012A314 /* VLCMainWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCMainWindow.h; path = Sources/VLCMainWindow.h; sourceTree = "<group>"; };
+               633BD4B10D2A90470012A314 /* VLCController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCController.m; path = Sources/VLCController.m; sourceTree = "<group>"; };
+               633BD4B20D2A90470012A314 /* VLCExceptionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCExceptionHandler.h; path = Sources/VLCExceptionHandler.h; sourceTree = "<group>"; };
+               633BD4B30D2A90470012A314 /* VLCBrowsableVideoView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCBrowsableVideoView.m; path = Sources/VLCBrowsableVideoView.m; sourceTree = "<group>"; };
+               633BD4B40D2A90470012A314 /* VLCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCController.h; path = Sources/VLCController.h; sourceTree = "<group>"; };
+               633BD4B50D2A90470012A314 /* VLCAppBindings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCAppBindings.m; path = Sources/VLCAppBindings.m; sourceTree = "<group>"; };
+               633BD4B60D2A90470012A314 /* VLCBrowsableVideoView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCBrowsableVideoView.h; path = Sources/VLCBrowsableVideoView.h; sourceTree = "<group>"; };
+               633BD4B70D2A90470012A314 /* VLCAppBindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCAppBindings.h; path = Sources/VLCAppBindings.h; sourceTree = "<group>"; };
+               633BD4B80D2A90470012A314 /* VLCAppAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCAppAdditions.h; path = Sources/VLCAppAdditions.h; sourceTree = "<group>"; };
+               633BD4B90D2A90470012A314 /* VLCAppAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCAppAdditions.m; path = Sources/VLCAppAdditions.m; sourceTree = "<group>"; };
+               633BD4BA0D2A90470012A314 /* ImageAndTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ImageAndTextCell.m; path = Sources/ImageAndTextCell.m; sourceTree = "<group>"; };
+               633BD4BB0D2A90470012A314 /* ImageAndTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageAndTextCell.h; path = Sources/ImageAndTextCell.h; sourceTree = "<group>"; };
+               633BD4D80D2A90C80012A314 /* dialog-error.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dialog-error.png"; path = "Icons/dialog-error.png"; sourceTree = "<group>"; };
+               633BD4D90D2A90C80012A314 /* applications-internet.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "applications-internet.png"; path = "Icons/applications-internet.png"; sourceTree = "<group>"; };
+               63874B180D25960600F738AD /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainWindow.xib; sourceTree = "<group>"; };
+               638F47100D216C8F008E4912 /* type_playlist.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = type_playlist.png; path = ../../../modules/gui/qt4/pixmaps/type_playlist.png; sourceTree = SOURCE_ROOT; };
+               63A742B20D2759C1002D41A0 /* ExceptionHandling.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ExceptionHandling.framework; path = /System/Library/Frameworks/ExceptionHandling.framework; sourceTree = "<absolute>"; };
+               63E380A80D1C65A600FD6958 /* volume_high.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = volume_high.png; path = ../Resources/volume_high.png; sourceTree = SOURCE_ROOT; };
+               63E380A90D1C65A600FD6958 /* volume_low.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = volume_low.png; path = ../Resources/volume_low.png; sourceTree = SOURCE_ROOT; };
+               63E380AC0D1C65D100FD6958 /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = play.png; path = ../Resources/play.png; sourceTree = SOURCE_ROOT; };
+               63E380AD0D1C65D100FD6958 /* play_blue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = play_blue.png; path = ../Resources/play_blue.png; sourceTree = SOURCE_ROOT; };
+               63E380B00D1C65F200FD6958 /* skip_forward_active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = skip_forward_active.png; path = ../Resources/skip_forward_active.png; sourceTree = SOURCE_ROOT; };
+               63E380B10D1C65F200FD6958 /* skip_forward_blue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = skip_forward_blue.png; path = ../Resources/skip_forward_blue.png; sourceTree = SOURCE_ROOT; };
+               63E380B40D1C65FC00FD6958 /* skip_previous_active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = skip_previous_active.png; path = ../Resources/skip_previous_active.png; sourceTree = SOURCE_ROOT; };
+               63E380B50D1C65FC00FD6958 /* skip_previous_blue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = skip_previous_blue.png; path = ../Resources/skip_previous_blue.png; sourceTree = SOURCE_ROOT; };
+               63E380DE0D1C6FD800FD6958 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
                8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
                8D1107320486CEB800E47090 /* VLC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VLC.app; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
                        files = (
                                8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
                                6310515A0CF7604600ACDE1E /* VLC.framework in Frameworks */,
+                               63E380DF0D1C6FD800FD6958 /* QuartzCore.framework in Frameworks */,
+                               63A742B30D2759C1002D41A0 /* ExceptionHandling.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-               080E96DDFE201D6D7F000001 /* Classes */ = {
-                       isa = PBXGroup;
-                       children = (
-                               63C5518A0C7F663500B202D3 /* VLCController.h */,
-                               63C5518B0C7F663500B202D3 /* VLCController.m */,
-                       );
-                       name = Classes;
-                       sourceTree = "<group>";
-               };
                1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               63A742B20D2759C1002D41A0 /* ExceptionHandling.framework */,
+                               63E380DE0D1C6FD800FD6958 /* QuartzCore.framework */,
                                1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
                                631051590CF7604600ACDE1E /* VLC.framework */,
                        );
                29B97314FDCFA39411CA2CEA /* VLC */ = {
                        isa = PBXGroup;
                        children = (
-                               080E96DDFE201D6D7F000001 /* Classes */,
+                               63874AF40D2591CE00F738AD /* Sources */,
                                29B97315FDCFA39411CA2CEA /* Other Sources */,
                                29B97317FDCFA39411CA2CEA /* Resources */,
                                29B97323FDCFA39411CA2CEA /* Frameworks */,
                                63C551960C7F6AD100B202D3 /* Images */,
                                8D1107310486CEB800E47090 /* Info.plist */,
                                089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
+                               63874B170D25960600F738AD /* MainWindow.xib */,
                                29B97318FDCFA39411CA2CEA /* MainMenu.nib */,
                        );
                        name = Resources;
                        name = Frameworks;
                        sourceTree = "<group>";
                };
+               633BD4620D2A8DF30012A314 /* Internals */ = {
+                       isa = PBXGroup;
+                       children = (
+                               633BD4B20D2A90470012A314 /* VLCExceptionHandler.h */,
+                               633BD4AF0D2A90470012A314 /* VLCExceptionHandler.m */,
+                       );
+                       name = Internals;
+                       sourceTree = "<group>";
+               };
+               63874AF40D2591CE00F738AD /* Sources */ = {
+                       isa = PBXGroup;
+                       children = (
+                               633BD4B10D2A90470012A314 /* VLCController.m */,
+                               633BD4B40D2A90470012A314 /* VLCController.h */,
+                               63874AF60D25920800F738AD /* Additions */,
+                               633BD4620D2A8DF30012A314 /* Internals */,
+                               63874AF50D2591EF00F738AD /* Video */,
+                               63874AF70D25922800F738AD /* Media List Management */,
+                               63874B0E0D25928400F738AD /* Window Management */,
+                       );
+                       name = Sources;
+                       sourceTree = "<group>";
+               };
+               63874AF50D2591EF00F738AD /* Video */ = {
+                       isa = PBXGroup;
+                       children = (
+                               633BD4B60D2A90470012A314 /* VLCBrowsableVideoView.h */,
+                               633BD4B30D2A90470012A314 /* VLCBrowsableVideoView.m */,
+                       );
+                       name = Video;
+                       sourceTree = "<group>";
+               };
+               63874AF60D25920800F738AD /* Additions */ = {
+                       isa = PBXGroup;
+                       children = (
+                               633BD4AB0D2A90470012A314 /* VLCValueTransformer.h */,
+                               633BD4AA0D2A90470012A314 /* VLCValueTransformer.m */,
+                               633BD4B70D2A90470012A314 /* VLCAppBindings.h */,
+                               633BD4B50D2A90470012A314 /* VLCAppBindings.m */,
+                               633BD4B80D2A90470012A314 /* VLCAppAdditions.h */,
+                               633BD4B90D2A90470012A314 /* VLCAppAdditions.m */,
+                               633BD4BB0D2A90470012A314 /* ImageAndTextCell.h */,
+                               633BD4BA0D2A90470012A314 /* ImageAndTextCell.m */,
+                       );
+                       name = Additions;
+                       sourceTree = "<group>";
+               };
+               63874AF70D25922800F738AD /* Media List Management */ = {
+                       isa = PBXGroup;
+                       children = (
+                               633BD4AE0D2A90470012A314 /* VLCMediaArrayController.h */,
+                               633BD4AC0D2A90470012A314 /* VLCMediaArrayController.m */,
+                       );
+                       name = "Media List Management";
+                       sourceTree = "<group>";
+               };
+               63874B0E0D25928400F738AD /* Window Management */ = {
+                       isa = PBXGroup;
+                       children = (
+                               633BD4B00D2A90470012A314 /* VLCMainWindow.h */,
+                               633BD4AD0D2A90470012A314 /* VLCMainWindow.m */,
+                       );
+                       name = "Window Management";
+                       sourceTree = "<group>";
+               };
                63C551960C7F6AD100B202D3 /* Images */ = {
                        isa = PBXGroup;
                        children = (
+                               638F47100D216C8F008E4912 /* type_playlist.png */,
+                               633BD4D80D2A90C80012A314 /* dialog-error.png */,
+                               633BD4D90D2A90C80012A314 /* applications-internet.png */,
+                               63E380A80D1C65A600FD6958 /* volume_high.png */,
+                               63E380A90D1C65A600FD6958 /* volume_low.png */,
+                               63E380AC0D1C65D100FD6958 /* play.png */,
+                               63E380AD0D1C65D100FD6958 /* play_blue.png */,
+                               63E380B00D1C65F200FD6958 /* skip_forward_active.png */,
+                               63E380B10D1C65F200FD6958 /* skip_forward_blue.png */,
+                               63E380B40D1C65FC00FD6958 /* skip_previous_active.png */,
+                               63E380B50D1C65FC00FD6958 /* skip_previous_blue.png */,
                        );
                        name = Images;
                        sourceTree = "<group>";
                        files = (
                                8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */,
                                8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
+                               63E380AA0D1C65A600FD6958 /* volume_high.png in Resources */,
+                               63E380AB0D1C65A600FD6958 /* volume_low.png in Resources */,
+                               63E380AE0D1C65D100FD6958 /* play.png in Resources */,
+                               63E380AF0D1C65D100FD6958 /* play_blue.png in Resources */,
+                               63E380B20D1C65F200FD6958 /* skip_forward_active.png in Resources */,
+                               63E380B30D1C65F200FD6958 /* skip_forward_blue.png in Resources */,
+                               63E380B60D1C65FC00FD6958 /* skip_previous_active.png in Resources */,
+                               63E380B70D1C65FC00FD6958 /* skip_previous_blue.png in Resources */,
+                               638F47110D216C8F008E4912 /* type_playlist.png in Resources */,
+                               63874B190D25960600F738AD /* MainWindow.xib in Resources */,
+                               633BD4DA0D2A90C80012A314 /* dialog-error.png in Resources */,
+                               633BD4DB0D2A90C80012A314 /* applications-internet.png in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                8D11072D0486CEB800E47090 /* main.m in Sources */,
-                               63C5518D0C7F663500B202D3 /* VLCController.m in Sources */,
+                               633BD4BC0D2A90470012A314 /* VLCValueTransformer.m in Sources */,
+                               633BD4BD0D2A90470012A314 /* VLCMediaArrayController.m in Sources */,
+                               633BD4BE0D2A90470012A314 /* VLCMainWindow.m in Sources */,
+                               633BD4BF0D2A90470012A314 /* VLCExceptionHandler.m in Sources */,
+                               633BD4C00D2A90470012A314 /* VLCController.m in Sources */,
+                               633BD4C10D2A90470012A314 /* VLCBrowsableVideoView.m in Sources */,
+                               633BD4C20D2A90470012A314 /* VLCAppBindings.m in Sources */,
+                               633BD4C30D2A90470012A314 /* VLCAppAdditions.m in Sources */,
+                               633BD4C40D2A90470012A314 /* ImageAndTextCell.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        name = MainMenu.nib;
                        sourceTree = "<group>";
                };
+               63874B170D25960600F738AD /* MainWindow.xib */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               63874B180D25960600F738AD /* English */,
+                       );
+                       name = MainWindow.xib;
+                       sourceTree = "<group>";
+               };
 /* End PBXVariantGroup section */
 
 /* Begin XCBuildConfiguration section */
                                        "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
                                        "\"$(SRCROOT)/../Framework/build/Debug\"",
                                );
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/../..\"";
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_2 = "\"$(SRCROOT)/../Framework\"";
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(SRCROOT)/../Framework/build/Release\\\"";
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(SRCROOT)/../Framework/build/Release\"";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_ENABLE_OBJC_GC = unsupported;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                INFOPLIST_FILE = Info.plist;
                                        "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
                                        "\"$(SRCROOT)/../Framework/build/Debug\"",
                                );
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/../..\"";
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_2 = "\"$(SRCROOT)/../Framework\"";
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(SRCROOT)/../Framework/build/Release\\\"";
-                               FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(SRCROOT)/../Framework/build/Release\"";
+                               GCC_ENABLE_OBJC_GC = unsupported;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
                                GCC_MODEL_TUNING = G5;
                                INFOPLIST_FILE = Info.plist;