You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

407 lines
17 KiB

/*****************************************************************************
* VLCMainWindowController.m: VLCMainWindowController implementation
*****************************************************************************
* Copyright (C) 2007 Pierre d'Herbemont
* Copyright (C) 2007 the VideoLAN team
* $Id$
*
* Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#import "VLCMainWindowController.h"
#import "VLCAppAdditions.h"
#import "ImageAndTextCell.h"
/******************************************************************************
* @implementation VLCMainWindowController
*/
@implementation VLCMainWindowController
@synthesize mediaPlayer;
@synthesize videoView;
@synthesize mediaArrayController;
@synthesize categoriesTreeController;
- (void)awakeFromNib
{
NSTableColumn * tableColumn;
/***********************************
* Init the media player
*/
NSAssert( mediaPlayer, @"No mediaPlayer" );
[self willChangeValueForKey:@"categoriesTreeController"];
categoriesTreeController = [[NSTreeController alloc] init];
[self didChangeValueForKey:@"categoriesTreeController"];
/***********************************
* CategoriesList OutlineView content
*/
/* categoriesTreeController */
NSAssert( categoriesTreeController, @"No categoriesTreeController" );
NSAssert( categoriesListView, @"No categoriesListView" );
NSAssert( controller, @"No controller" );
[categoriesTreeController setContent:controller.categories];
//[categoriesTreeController bind:@"content" toObject:controller withKeyPath:@"categories" options:nil];
[categoriesTreeController setChildrenKeyPath:@"childrenInCategoriesList"];
/* Bind the "name" table column */
tableColumn = [categoriesListView tableColumnWithIdentifier:@"name"];
[tableColumn bind:@"value" toObject:categoriesTreeController withKeyPath:@"arrangedObjects.descriptionInCategoriesList" 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 */
[categoriesListView setIndentationMarkerFollowsCell:YES];
[categoriesListView setAutoresizesOutlineColumn:NO];
[categoriesListView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
[categoriesListView setDelegate:self];
[categoriesListView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, @"VLCMediaURLType", nil]];
[categoriesListView setDataSource: self];
/***********************************
* mediaListView setup
*/
/* 1- Drag and drop */
NSAssert( mediaArrayController, @"No mediaArrayController" );
NSAssert( mediaListView, @"No mediaListView" );
[mediaListView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]];
[mediaListView setDataSource:mediaArrayController];
/* 3- binding for "title" column */
tableColumn = [mediaListView tableColumnWithIdentifier:@"title"];
[tableColumn bind:@"value" toObject: mediaArrayController withKeyPath:@"arrangedObjects.metaDictionary.title" options:nil];
/* 2- Double click */
[mediaListView setTarget:self];
[mediaListView setDoubleAction:@selector(mediaListViewItemDoubleClicked:)];
/* 4- binding for "state" column */
tableColumn = [mediaListView tableColumnWithIdentifier:@"state"];
[tableColumn bind:@"value" toObject: mediaArrayController withKeyPath:@"arrangedObjects.stateAsImage" options:nil];
/* 6- Bind the @"contentArray" and contentMediaList of the mediaArrayController */
[mediaArrayController bind:@"contentArray" toObject:categoriesTreeController withKeyPath:@"selection.childrenInCategoriesListForDetailView.media" options:nil];
[mediaArrayController bind:@"contentMediaList" toObject:categoriesTreeController withKeyPath:@"selection.childrenInCategoriesListForDetailView.parentMediaList" options:nil];
/* 7- Aspect */
[mediaListView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
[mediaListView setAllowsTypeSelect:YES];
/***********************************
* videoView setup
*/
[videoView setItemsTree:controller.categories];
[videoView setNodeKeyPath:@"childrenInVideoView"];
[videoView setContentKeyPath:@"descriptionInVideoView"];
[videoView setTarget:self];
[videoView setAction:@selector(videoViewItemClicked:)];
/***********************************
* Toolbar setup
*/
/***********************************
* Other interface element setup
*/
#if 0
[mediaListItemsCount bind:@"displayPatternValue1" toObject:mediaArrayController withKeyPath:@"arrangedObjects.@count" options:[NSDictionary dictionaryWithObject:@"%{value1}@ items" forKey:NSDisplayPatternBindingOption]];
[mediaListItemFetchedStatus bind:@"animate" toObject:categoriesTreeController withKeyPath:@"selection.currentlyFetchingItems" options:[NSDictionary dictionaryWithObject:@"%{value1}@ items" forKey:NSDisplayPatternBindingOption]];
[fillScreenButton bind:@"value" toObject:videoView withKeyPath:@"fillScreen" options: nil];
[fullScreenButton bind:@"value" toObject:videoView withKeyPath:@"fullScreen" options: nil];
[fullScreenButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
[fillScreenButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
[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];
[self bind:@"representedFilename" toObject:mediaPlayer withKeyPath:@"media.url" options: [NSDictionary dictionaryWithObject:@"URLToRepresentedFileNameTransformer" forKey:NSValueTransformerNameBindingOption]];
[self bind:@"title" toObject:mediaPlayer withKeyPath:@"description" options: nil];
[navigatorViewToggleButton bind:@"value" toObject:self withKeyPath:@"navigatorViewVisible" options: nil];
#endif
/* Playlist buttons */
#if 0
[removePlaylistButton bind:@"enabled" toObject:categoriesTreeController withKeyPath:@"selection.editableInCategoriesList" options: nil];
#endif
[removePlaylistButton setTarget:categoriesTreeController];
[removePlaylistButton setAction:@selector(remove:)];
[addPlaylistButton setTarget:controller];
[addPlaylistButton setAction:@selector(addPlaylist:)];
/* mediaPlayer */
#if 0
[mediaPlayerPlayPauseStopButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
[mediaPlayerPlayPauseStopButton bind:@"state" toObject:mediaPlayer withKeyPath:@"playing" options: nil];
[mediaPlayerPlayPauseStopButton bind:@"alternateImage" toObject:mediaPlayer withKeyPath:@"stateAsButtonAlternateImage" options: nil];
[mediaPlayerPlayPauseStopButton bind:@"image" toObject:mediaPlayer withKeyPath:@"stateAsButtonImage" options: nil];
[mediaPlayerBackwardPrevButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"playing" options: nil];
[mediaPlayerForwardNextButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"playing" options: nil];
#endif
[mediaPlayerForwardNextButton setTarget:mediaPlayer];
[mediaPlayerForwardNextButton setAction:@selector(fastForward)];
[mediaPlayerBackwardPrevButton setTarget:mediaPlayer];
[mediaPlayerBackwardPrevButton setAction:@selector(rewind)];
[mediaPlayerPlayPauseStopButton setTarget:mediaPlayer];
[mediaPlayerPlayPauseStopButton setAction:@selector(pause)];
/* Last minute setup */
[categoriesListView expandItem:nil expandChildren:YES];
[categoriesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:[categoriesListView numberOfRows] > 0 ? [categoriesListView numberOfRows]-1 : 0] byExtendingSelection:NO];
[self setNavigatorViewVisible:NO animate:NO];
[self showWindow:self];
[mainSplitView setDelegate:self];
}
- (BOOL)navigatorViewVisible
{
return [mainSplitView sliderPosition] <= [mainSplitView bounds].size.width - [mainSplitView dividerThickness] - 30.f /* To be tolerant */;
}
- (void)setNavigatorViewVisible:(BOOL)wantsVisible animate:(BOOL)animate
{
if( [self navigatorViewVisible] == wantsVisible )
return;
if( !animate ) [self willChangeValueForKey:@"navigatorViewVisible"];
VLCOneSplitView * splitView = animate ? [mainSplitView animator] : mainSplitView;
if( wantsVisible )
{
if( navigatorViewWidth >= [mainSplitView bounds].size.width - 200.f )
navigatorViewWidth = [mainSplitView bounds].size.width - 200.f;
[splitView setSliderPosition:navigatorViewWidth];
}
else
{
navigatorViewWidth = [videoView frame].size.width;
[splitView setSliderPosition:[mainSplitView bounds].size.width - [mainSplitView dividerThickness]];
}
if( !animate ) [self didChangeValueForKey:@"navigatorViewVisible"];
}
- (void)setNavigatorViewVisible:(BOOL)wantsVisible
{
[self setNavigatorViewVisible:wantsVisible animate:YES];
}
- (IBAction)mediaListViewItemDoubleClicked:(id)sender
{
if([[mediaArrayController selectedObjects] count] <= 0 )
return;
[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];
}
@end
/******************************************************************************
* @implementation VLCMainWindowController (NSToolbarDelegating)
*/
@implementation VLCMainWindowController (NSToolbarDelegating)
/* Our item identifiers */
static NSString * VLCToolbarMediaControl = @"VLCToolbarMediaControl";
static NSString * VLCToolbarMediaAudioVolume = @"VLCToolbarMediaAudioVolume";
static NSString * VLCToolbarMediaDescription = @"VLCToolbarMediaDescription";
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
return [NSArray arrayWithObjects:
NSToolbarCustomizeToolbarItemIdentifier,
NSToolbarFlexibleSpaceItemIdentifier,
NSToolbarSpaceItemIdentifier,
NSToolbarSeparatorItemIdentifier,
VLCToolbarMediaControl,
VLCToolbarMediaAudioVolume,
VLCToolbarMediaDescription,
nil ];
}
- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
{
return [NSArray arrayWithObjects:
VLCToolbarMediaControl,
VLCToolbarMediaAudioVolume,
VLCToolbarMediaDescription,
nil ];
}
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
{
NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
if( [itemIdentifier isEqual: VLCToolbarMediaControl] )
{
[toolbarItem setLabel:@"Media Controls"];
[toolbarItem setPaletteLabel:@"Media Controls"];
[toolbarItem setView:toolbarMediaControl];
[toolbarItem setMinSize:[[toolbarItem view] frame].size];
[toolbarItem setMaxSize:[[toolbarItem view] frame].size];
/* TODO: setup a menu */
}
else if( [itemIdentifier isEqual: VLCToolbarMediaAudioVolume] )
{
[toolbarItem setLabel:@"Audio Volume"];
[toolbarItem setPaletteLabel:@"Audio Volume"];
[toolbarItem setView:toolbarMediaAudioVolume];
[toolbarItem setMinSize:[[toolbarItem view] frame].size];
[toolbarItem setMaxSize:[[toolbarItem view] frame].size];
/* TODO: setup a menu */
}
else if( [itemIdentifier isEqual: VLCToolbarMediaDescription] )
{
[toolbarItem setLabel:@"Media Description"];
[toolbarItem setPaletteLabel:@"Media Description"];
[toolbarItem setView:toolbarMediaDescription];
[toolbarItem setMinSize:[[toolbarItem view] frame].size];
[toolbarItem setMaxSize:NSMakeSize(10000 /* Can be really big */, NSHeight([[toolbarItem view] frame]))];
/* TODO: setup a menu */
}
else
{
/* itemIdentifier referred to a toolbar item that is not
* provided or supported by us or Cocoa
* Returning nil will inform the toolbar
* that this kind of item is not supported */
toolbarItem = nil;
}
return toolbarItem;
}
@end
/******************************************************************************
* VLCMainWindowController (CategoriesListDelegate)
*/
@implementation VLCMainWindowController (CategoriesListDelegate)
- (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
/******************************************************************************
* VLCMainWindowController (CategoriesListDataSource)
*/
@implementation VLCMainWindowController (CategoriesListDataSource)
/* Drag and drop */
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index
{
int i;
if(![item respondsToSelector:@selector(representedObject)])
return NO;
NSArray *droppedItems = [[info draggingPasteboard] propertyListForType:@"VLCMediaURLType"];
if( !droppedItems )
droppedItems = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
if( !droppedItems )
droppedItems = [[info draggingPasteboard] propertyListForType:NSURLPboardType];
NSAssert( droppedItems, @"Dropped an unsupported object type on the outline View" );
VLCMediaList * mediaList = [(VLCMedia *)[item representedObject] subitems];
for (i = 0; i < [droppedItems count]; i++)
{
NSString * filename = [droppedItems objectAtIndex:i];
VLCMedia *media = [VLCMedia mediaWithPath:filename];
[mediaList lock];
[mediaList insertMedia:media atIndex:index+1];
[mediaList unlock];
}
return YES;
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
NSArray *droppedItems = [[info draggingPasteboard] propertyListForType:@"VLCMediaURLType"];
if( !droppedItems )
droppedItems = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
if( !droppedItems )
droppedItems = [[info draggingPasteboard] propertyListForType:NSURLPboardType];
if(! droppedItems ||
![item respondsToSelector:@selector(representedObject)] ||
![[item representedObject] isKindOfClass:[VLCMedia class]] )
{
return NSDragOperationNone;
}
return NSDragOperationMove;
}
@end
/******************************************************************************
* VLCMainWindowController (SplitViewDelegate)
*/
@implementation VLCMainWindowController (SplitViewDelegate)
- (void)splitViewWillResizeSubviews:(NSNotification *)aNotification
{
[self willChangeValueForKey:@"navigatorViewVisible"];
}
- (void)splitViewDidResizeSubviews:(NSNotification *)aNotification
{
[self didChangeValueForKey:@"navigatorViewVisible"];
}
@end