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