]> git.sesse.net Git - vlc/blob - projects/macosx/vlc_app/Sources/VLCMainWindowController.m
vlc_app: New media layer view. Enabled by default. Set bindings from resources. ...
[vlc] / projects / macosx / vlc_app / Sources / VLCMainWindowController.m
1 /*****************************************************************************
2  * VLCMainWindowController.m: VLCMainWindowController implementation
3  *****************************************************************************
4  * Copyright (C) 2007 Pierre d'Herbemont
5  * Copyright (C) 2007 the VideoLAN team
6  * $Id: VLCMainWindow.h 24209 2008-01-09 22:05:17Z pdherbemont $
7  *
8  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import "VLCMainWindowController.h"
26 #import "VLCAppAdditions.h"
27 #import "ImageAndTextCell.h"
28
29 /******************************************************************************
30  * @implementation VLCMainWindowController
31  */
32
33 @implementation VLCMainWindowController
34
35 @synthesize mediaPlayer;
36 @synthesize videoView;
37 @synthesize mediaArrayController;
38
39 - (void)awakeFromNib
40 {
41     NSTableColumn * tableColumn;
42
43     /***********************************
44      * Init the media player
45      */
46
47     NSAssert( mediaPlayer, @"No mediaPlayer" );
48     
49     categoriesTreeController = [[NSTreeController alloc] init];
50     
51     /***********************************
52      * CategoriesList OutlineView content
53      */
54     /* categoriesTreeController */ 
55     NSAssert( categoriesTreeController, @"No categoriesTreeController" );
56     NSAssert( categoriesListView, @"No categoriesListView" );
57     NSAssert( controller, @"No controller" );
58
59     [categoriesTreeController setContent:controller.categories];
60     //[categoriesTreeController bind:@"content" toObject:controller withKeyPath:@"categories" options:nil];
61   
62     [categoriesTreeController setChildrenKeyPath:@"childrenInCategoriesList"];
63
64     /* Bind the "name" table column */
65     tableColumn = [categoriesListView tableColumnWithIdentifier:@"name"];
66     [tableColumn bind:@"value" toObject:categoriesTreeController withKeyPath:@"arrangedObjects.descriptionInCategoriesList" options:nil];
67
68     /* Use an ImageAndTextCell in the "name" table column */
69     ImageAndTextCell * cell = [[ImageAndTextCell alloc] init];
70     [cell setFont:[[tableColumn dataCell] font]];
71     [cell setImageKeyPath:@"image"];
72     [tableColumn setDataCell: cell];
73
74     /* Other setup */
75     [categoriesListView setIndentationMarkerFollowsCell:YES];
76     [categoriesListView setAutoresizesOutlineColumn:NO];
77     [categoriesListView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
78     [categoriesListView setDelegate:self];
79
80     [categoriesListView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, @"VLCMediaURLType", nil]];
81     [categoriesListView setDataSource: self];
82
83     /***********************************
84      * mediaListView setup
85      */
86
87     /* 1- Drag and drop */
88     NSAssert( mediaArrayController, @"No mediaArrayController" );
89     NSAssert( mediaListView, @"No mediaListView" );
90     [mediaListView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]];
91     [mediaListView setDataSource:mediaArrayController];
92         /* 3- binding for "title" column */
93     tableColumn = [mediaListView tableColumnWithIdentifier:@"title"];
94         [tableColumn bind:@"value" toObject: mediaArrayController withKeyPath:@"arrangedObjects.metaDictionary.title" options:nil];
95
96
97     /* 2- Double click */
98     [mediaListView setTarget:self];
99     [mediaListView setDoubleAction:@selector(mediaListViewItemDoubleClicked:)];
100
101
102         /* 4- binding for "state" column */
103     tableColumn = [mediaListView tableColumnWithIdentifier:@"state"];
104         [tableColumn bind:@"value" toObject: mediaArrayController withKeyPath:@"arrangedObjects.stateAsImage" options:nil];
105
106     /* 6- Bind the @"contentArray" and contentMediaList of the mediaArrayController */
107     [mediaArrayController bind:@"contentArray" toObject:categoriesTreeController withKeyPath:@"selection.childrenInCategoriesListForDetailView.media" options:nil];
108
109     [mediaArrayController bind:@"contentMediaList" toObject:categoriesTreeController withKeyPath:@"selection.childrenInCategoriesListForDetailView.parentMediaList" options:nil];
110     
111     /* 7- Aspect */
112     [mediaListView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
113     [mediaListView setAllowsTypeSelect:YES];
114
115     /***********************************
116      * videoView setup
117      */
118     [videoView setItemsTree:controller.categories];
119     [videoView setNodeKeyPath:@"childrenInVideoView"];
120     [videoView setContentKeyPath:@"descriptionInVideoView"];
121     [videoView setTarget:self];
122     [videoView setAction:@selector(videoViewItemClicked:)];
123     
124     /***********************************
125      * Toolbar setup
126      */
127
128     /***********************************
129      * Other interface element setup
130      */
131 #if 0
132
133     [mediaListItemsCount bind:@"displayPatternValue1" toObject:mediaArrayController withKeyPath:@"arrangedObjects.@count" options:[NSDictionary dictionaryWithObject:@"%{value1}@ items" forKey:NSDisplayPatternBindingOption]];
134     [mediaListItemFetchedStatus bind:@"animate" toObject:categoriesTreeController withKeyPath:@"selection.currentlyFetchingItems" options:[NSDictionary dictionaryWithObject:@"%{value1}@ items" forKey:NSDisplayPatternBindingOption]];
135
136     [fillScreenButton bind:@"value" toObject:videoView withKeyPath:@"fillScreen" options: nil];
137     [fullScreenButton bind:@"value" toObject:videoView withKeyPath:@"fullScreen" options: nil];
138     [fullScreenButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
139     [fillScreenButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
140     [mediaReadingProgressSlider bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
141     [mediaReadingProgressSlider bind:@"enabled2" toObject:mediaPlayer withKeyPath:@"seekable" options: nil];
142
143     [mediaReadingProgressSlider bind:@"value" toObject:mediaPlayer withKeyPath:@"position" options:
144         [NSDictionary dictionaryWithObjectsAndKeys:@"Float10000FoldTransformer", NSValueTransformerNameBindingOption,
145                                                   [NSNumber numberWithBool:NO], NSConditionallySetsEnabledBindingOption, nil ]];
146     [mediaReadingProgressText bind:@"value" toObject:mediaPlayer withKeyPath:@"time.stringValue" options: nil];
147     [mediaDescriptionText bind:@"value" toObject:mediaPlayer withKeyPath:@"description" options: nil];
148     [self bind:@"representedFilename" toObject:mediaPlayer withKeyPath:@"media.url" options: [NSDictionary dictionaryWithObject:@"URLToRepresentedFileNameTransformer" forKey:NSValueTransformerNameBindingOption]];
149     [self bind:@"title" toObject:mediaPlayer withKeyPath:@"description" options: nil];
150
151     [navigatorViewToggleButton bind:@"value" toObject:self withKeyPath:@"navigatorViewVisible" options: nil];
152 #endif
153
154     /* Playlist buttons */
155 #if 0
156     [removePlaylistButton bind:@"enabled" toObject:categoriesTreeController withKeyPath:@"selection.editableInCategoriesList" options: nil];
157 #endif
158     [removePlaylistButton setTarget:categoriesTreeController];
159     [removePlaylistButton setAction:@selector(remove:)];
160     [addPlaylistButton setTarget:controller];
161     [addPlaylistButton setAction:@selector(addPlaylist:)];
162
163     /* mediaPlayer */
164 #if 0
165     [mediaPlayerPlayPauseStopButton bind:@"enabled" toObject:mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
166     [mediaPlayerPlayPauseStopButton bind:@"state"   toObject:mediaPlayer withKeyPath:@"playing" options: nil];
167     [mediaPlayerPlayPauseStopButton bind:@"alternateImage" toObject:mediaPlayer withKeyPath:@"stateAsButtonAlternateImage" options: nil];
168     [mediaPlayerPlayPauseStopButton bind:@"image"   toObject:mediaPlayer withKeyPath:@"stateAsButtonImage" options: nil];
169     [mediaPlayerBackwardPrevButton  bind:@"enabled" toObject:mediaPlayer withKeyPath:@"playing" options: nil];
170     [mediaPlayerForwardNextButton   bind:@"enabled" toObject:mediaPlayer withKeyPath:@"playing" options: nil];
171 #endif
172
173     [mediaPlayerForwardNextButton   setTarget:mediaPlayer];
174     [mediaPlayerForwardNextButton   setAction:@selector(fastForward)];
175     [mediaPlayerBackwardPrevButton  setTarget:mediaPlayer];
176     [mediaPlayerBackwardPrevButton  setAction:@selector(rewind)];
177     [mediaPlayerPlayPauseStopButton setTarget:mediaPlayer];
178     [mediaPlayerPlayPauseStopButton setAction:@selector(pause)];
179
180     /* Last minute setup */
181     [categoriesListView expandItem:nil expandChildren:YES];
182     [categoriesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:[categoriesListView numberOfRows] > 0 ? [categoriesListView numberOfRows]-1 : 0] byExtendingSelection:NO];
183     [self setNavigatorViewVisible:NO animate:NO];
184     [self showWindow:self];
185     [mainSplitView setDelegate:self];
186 }
187
188 - (BOOL)navigatorViewVisible
189 {
190     return [mainSplitView sliderPosition] <= [mainSplitView bounds].size.width - [mainSplitView dividerThickness] - 30.f /* To be tolerant */;
191 }
192
193 - (void)setNavigatorViewVisible:(BOOL)wantsVisible animate:(BOOL)animate
194 {
195     if( [self navigatorViewVisible] == wantsVisible )
196         return;
197
198     if( !animate ) [self willChangeValueForKey:@"navigatorViewVisible"];
199
200     VLCOneSplitView * splitView = animate ? [mainSplitView animator] : mainSplitView;
201         
202     if( wantsVisible )
203     {
204         if( navigatorViewWidth >= [mainSplitView bounds].size.width - 200.f )
205             navigatorViewWidth = [mainSplitView bounds].size.width - 200.f;
206         [splitView setSliderPosition:navigatorViewWidth];
207     }
208     else
209     {
210         navigatorViewWidth = [videoView frame].size.width;
211         [splitView setSliderPosition:[mainSplitView bounds].size.width - [mainSplitView dividerThickness]];
212     }
213     if( !animate ) [self didChangeValueForKey:@"navigatorViewVisible"];
214 }
215
216 - (void)setNavigatorViewVisible:(BOOL)wantsVisible
217 {
218     [self setNavigatorViewVisible:wantsVisible animate:YES];
219 }
220
221 - (IBAction)mediaListViewItemDoubleClicked:(id)sender
222 {
223     if([[mediaArrayController selectedObjects] count] <= 0 )
224         return;
225     [mediaPlayer setMedia:[[mediaArrayController selectedObjects] objectAtIndex:0]];
226     [mediaPlayer play];
227 }
228
229 - (void)videoViewItemClicked:(id)sender
230 {
231     id object = [sender selectedObject];
232     NSAssert( [object isKindOfClass:[VLCMedia class]], @"Object is not a VLCMedia" );
233
234     [mediaPlayer setMedia:object];
235     [mediaPlayer play];
236 }
237
238 @end
239
240 /******************************************************************************
241  * @implementation VLCMainWindowController (NSToolbarDelegating)
242  */
243
244 @implementation VLCMainWindowController (NSToolbarDelegating)
245 /* Our item identifiers */
246 static NSString * VLCToolbarMediaControl     = @"VLCToolbarMediaControl";
247 static NSString * VLCToolbarMediaAudioVolume = @"VLCToolbarMediaAudioVolume";
248 static NSString * VLCToolbarMediaDescription = @"VLCToolbarMediaDescription";
249
250 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
251 {
252     return [NSArray arrayWithObjects:
253                         NSToolbarCustomizeToolbarItemIdentifier,
254                         NSToolbarFlexibleSpaceItemIdentifier,
255                         NSToolbarSpaceItemIdentifier,
256                         NSToolbarSeparatorItemIdentifier,
257                         VLCToolbarMediaControl,
258                         VLCToolbarMediaAudioVolume,
259                         VLCToolbarMediaDescription,
260                         nil ];
261 }
262
263 - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
264 {
265     return [NSArray arrayWithObjects:
266                         VLCToolbarMediaControl,
267                         VLCToolbarMediaAudioVolume,
268                         VLCToolbarMediaDescription,
269                         nil ];
270 }
271
272 - (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
273 {
274     NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
275  
276     if( [itemIdentifier isEqual: VLCToolbarMediaControl] )
277     {
278         [toolbarItem setLabel:@"Media Controls"];
279         [toolbarItem setPaletteLabel:@"Media Controls"];
280      
281         [toolbarItem setView:toolbarMediaControl];
282         [toolbarItem setMinSize:[[toolbarItem view] frame].size];
283         [toolbarItem setMaxSize:[[toolbarItem view] frame].size];
284
285         /* TODO: setup a menu */
286     }
287     else if( [itemIdentifier isEqual: VLCToolbarMediaAudioVolume] )
288     {
289         [toolbarItem setLabel:@"Audio Volume"];
290         [toolbarItem setPaletteLabel:@"Audio Volume"];
291      
292         [toolbarItem setView:toolbarMediaAudioVolume];
293         [toolbarItem setMinSize:[[toolbarItem view] frame].size];
294         [toolbarItem setMaxSize:[[toolbarItem view] frame].size];
295
296         /* TODO: setup a menu */
297     }
298     else  if( [itemIdentifier isEqual: VLCToolbarMediaDescription] )
299     {
300         [toolbarItem setLabel:@"Media Description"];
301         [toolbarItem setPaletteLabel:@"Media Description"];
302      
303         [toolbarItem setView:toolbarMediaDescription];
304         [toolbarItem setMinSize:[[toolbarItem view] frame].size];
305         [toolbarItem setMaxSize:NSMakeSize(10000 /* Can be really big */, NSHeight([[toolbarItem view] frame]))];
306
307         /* TODO: setup a menu */
308     }
309     else
310     {
311         /* itemIdentifier referred to a toolbar item that is not
312          * provided or supported by us or Cocoa
313          * Returning nil will inform the toolbar
314          * that this kind of item is not supported */
315         toolbarItem = nil;
316     }
317     return toolbarItem;
318 }
319 @end
320
321 /******************************************************************************
322  * VLCMainWindowController (CategoriesListDelegate)
323  */
324 @implementation VLCMainWindowController (CategoriesListDelegate)
325 - (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
326 {
327     return [[item representedObject] isKindOfClass:[NSDictionary class]];
328 }
329 - (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
330 {
331     return !([[item representedObject] isKindOfClass:[NSDictionary class]]);
332 }
333 - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
334 {
335     [cell setRepresentedObject:[item representedObject]];
336 }
337 @end
338
339 /******************************************************************************
340  * VLCMainWindowController (CategoriesListDataSource)
341  */
342 @implementation VLCMainWindowController (CategoriesListDataSource)
343 /* Drag and drop */
344 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index
345 {
346     int i;
347
348     if(![item respondsToSelector:@selector(representedObject)])
349         return NO;
350     
351     NSArray *droppedItems = [[info draggingPasteboard] propertyListForType:@"VLCMediaURLType"];
352     if( !droppedItems )
353         droppedItems = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
354     if( !droppedItems )
355         droppedItems = [[info draggingPasteboard] propertyListForType:NSURLPboardType];
356
357     NSAssert( droppedItems, @"Dropped an unsupported object type on the outline View" );
358
359     VLCMediaList * mediaList = [(VLCMedia *)[item representedObject] subitems];
360
361     for (i = 0; i < [droppedItems count]; i++)
362     {
363         NSString * filename = [droppedItems objectAtIndex:i];
364                 VLCMedia *media = [VLCMedia mediaWithPath:filename];
365         [mediaList lock];
366                 [mediaList insertMedia:media atIndex:index+1];
367         [mediaList unlock];
368     }
369     return YES;
370 }
371
372 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
373 {
374     NSArray *droppedItems = [[info draggingPasteboard] propertyListForType:@"VLCMediaURLType"];
375     if( !droppedItems )
376         droppedItems = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
377     if( !droppedItems )
378         droppedItems = [[info draggingPasteboard] propertyListForType:NSURLPboardType];
379
380     if(! droppedItems ||
381        ![item respondsToSelector:@selector(representedObject)] ||
382        ![[item representedObject] isKindOfClass:[VLCMedia class]] )
383     {
384         return NSDragOperationNone;
385     }
386
387     return NSDragOperationMove;
388 }
389 @end
390
391 /******************************************************************************
392  * VLCMainWindowController (SplitViewDelegate)
393  */
394 @implementation VLCMainWindowController (SplitViewDelegate)
395
396 - (void)splitViewWillResizeSubviews:(NSNotification *)aNotification
397 {
398     [self willChangeValueForKey:@"navigatorViewVisible"];
399 }
400 - (void)splitViewDidResizeSubviews:(NSNotification *)aNotification
401 {
402     [self didChangeValueForKey:@"navigatorViewVisible"];
403 }
404
405 @end