]> git.sesse.net Git - vlc/blob - modules/gui/macosx/open.m
02d3b66a30692f34c925bc13c360d858e1037292
[vlc] / modules / gui / macosx / open.m
1 /*****************************************************************************
2  * open.m: Open dialogues for VLC's MacOS X port
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <thedj@users.sourceforge.net>
10  *          Benjamin Pracht <bigben at videolan dot org>
11  *          Felix Paul Kühne <fkuehne at videolan dot org>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <stdlib.h>                                      /* malloc(), free() */
32 #include <sys/param.h>                                    /* for MAXPATHLEN */
33 #include <string.h>
34
35 #include <paths.h>
36 #include <IOKit/IOKitLib.h>
37 #include <IOKit/IOBSD.h>
38 #include <IOKit/storage/IOMedia.h>
39 #include <IOKit/storage/IOCDMedia.h>
40 #include <IOKit/storage/IODVDMedia.h>
41
42 #import "intf.h"
43 #import "playlist.h"
44 #import "open.h"
45 #import "output.h"
46 #import "eyetv.h"
47
48 #include <vlc_url.h>
49
50 #define setEyeTVUnconnected \
51 [o_capture_lbl setStringValue: _NS("No device connected")]; \
52 [o_capture_long_lbl setStringValue: _NS("VLC could not detect any EyeTV compatible device.\n\nCheck the device's connection, make sure that the latest EyeTV software is installed and try again.")]; \
53 [o_capture_lbl displayIfNeeded]; \
54 [o_capture_long_lbl displayIfNeeded]; \
55 [self showCaptureView: o_capture_label_view]
56
57
58 /*****************************************************************************
59  * GetEjectableMediaOfClass
60  *****************************************************************************/
61 NSArray *GetEjectableMediaOfClass( const char *psz_class )
62 {
63     io_object_t next_media;
64     mach_port_t master_port;
65     kern_return_t kern_result;
66     NSArray *o_devices = nil;
67     NSMutableArray *p_list = nil;
68     io_iterator_t media_iterator;
69     CFMutableDictionaryRef classes_to_match;
70
71     kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
72     if( kern_result != KERN_SUCCESS )
73     {
74         return( nil );
75     }
76  
77     classes_to_match = IOServiceMatching( psz_class );
78     if( classes_to_match == NULL )
79     {
80         return( nil );
81     }
82  
83     CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectableKey ),
84                           kCFBooleanTrue );
85  
86     kern_result = IOServiceGetMatchingServices( master_port, classes_to_match,
87                                                 &media_iterator );
88     if( kern_result != KERN_SUCCESS )
89     {
90         return( nil );
91     }
92
93     p_list = [NSMutableArray arrayWithCapacity: 1];
94  
95     next_media = IOIteratorNext( media_iterator );
96     if( next_media )
97     {
98         char psz_buf[0x32];
99         size_t dev_path_length;
100         CFTypeRef str_bsd_path;
101  
102         do
103         {
104             str_bsd_path = IORegistryEntryCreateCFProperty( next_media,
105                                                             CFSTR( kIOBSDNameKey ),
106                                                             kCFAllocatorDefault,
107                                                             0 );
108             if( str_bsd_path == NULL )
109             {
110                 IOObjectRelease( next_media );
111                 continue;
112             }
113  
114             snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
115             dev_path_length = strlen( psz_buf );
116  
117             if( CFStringGetCString( str_bsd_path,
118                                     (char*)&psz_buf + dev_path_length,
119                                     sizeof(psz_buf) - dev_path_length,
120                                     kCFStringEncodingASCII ) )
121             {
122                 [p_list addObject: [NSString stringWithUTF8String: psz_buf]];
123             }
124  
125             CFRelease( str_bsd_path );
126  
127             IOObjectRelease( next_media );
128  
129         } while( ( next_media = IOIteratorNext( media_iterator ) ) );
130     }
131  
132     IOObjectRelease( media_iterator );
133
134     o_devices = [NSArray arrayWithArray: p_list];
135
136     return( o_devices );
137 }
138
139 /*****************************************************************************
140  * VLCOpen implementation
141  *****************************************************************************/
142 @implementation VLCOpen
143
144 static VLCOpen *_o_sharedMainInstance = nil;
145
146 + (VLCOpen *)sharedInstance
147 {
148     return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
149 }
150
151 - (id)init
152 {
153     if( _o_sharedMainInstance) {
154         [self dealloc];
155     } else {
156         _o_sharedMainInstance = [super init];
157         p_intf = VLCIntf;
158     }
159  
160     return _o_sharedMainInstance;
161 }
162
163 - (void)dealloc
164 {
165     if( o_file_slave_path )
166         [o_file_slave_path release];
167     [super dealloc];
168 }
169
170 - (void)awakeFromNib
171 {
172     [o_panel setTitle: _NS("Open Source")];
173     [o_mrl_lbl setStringValue: _NS("Media Resource Locator (MRL)")];
174
175     [o_btn_ok setTitle: _NS("Open")];
176     [o_btn_cancel setTitle: _NS("Cancel")];
177
178     [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
179     [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
180     [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
181     [[o_tabview tabViewItemAtIndex: 3] setLabel: _NS("Capture")];
182
183     [o_file_btn_browse setTitle: _NS("Browse...")];
184     [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
185     [o_file_slave_ckbox setTitle: _NS("Play another media synchronously")];
186     [o_file_slave_select_btn setTitle: _NS("Choose...")];
187     [o_file_slave_filename_txt setStringValue: @""];
188
189     [o_disc_device_lbl setStringValue: _NS("Device name")];
190     [o_disc_title_lbl setStringValue: _NS("Title")];
191     [o_disc_chapter_lbl setStringValue: _NS("Chapter")];
192     [o_disc_videots_btn_browse setTitle: _NS("Browse...")];
193     [o_disc_dvd_menus setTitle: _NS("No DVD menus")];
194
195     [[o_disc_type cellAtRow:0 column:0] setTitle: _NS("VIDEO_TS folder")];
196     [[o_disc_type cellAtRow:1 column:0] setTitle: _NS("DVD")];
197     [[o_disc_type cellAtRow:2 column:0] setTitle: _NS("VCD")];
198     [[o_disc_type cellAtRow:3 column:0] setTitle: _NS("Audio CD")];
199
200     [o_net_udp_port_lbl setStringValue: _NS("Port")];
201     [o_net_udpm_addr_lbl setStringValue: _NS("IP Address")];
202     [o_net_udpm_port_lbl setStringValue: _NS("Port")];
203     [o_net_http_url_lbl setStringValue: _NS("URL")];
204     [o_net_help_lbl setStringValue: _NS("To Open a usual network stream (HTTP, RTSP, MMS, FTP, etc.), just enter the URL in the field above. If you want to open a RTP or UDP stream, press the button below.")];
205     [o_net_help_udp_lbl setStringValue: _NS("If you want to open a multicast stream, enter the respective IP address given by the stream provider. In unicast mode, VLC will use your machine's IP automatically.\n\nTo open a stream using a different protocol, just press Cancel to close this sheet.")];
206     [o_net_udp_cancel_btn setTitle: _NS("Cancel")];
207     [o_net_udp_ok_btn setTitle: _NS("Open")];
208     [o_net_openUDP_btn setTitle: _NS("Open RTP/UDP Stream")];
209     [o_net_udp_mode_lbl setStringValue: _NS("Mode")];
210     [o_net_udp_protocol_lbl setStringValue: _NS("Protocol")];
211     [o_net_udp_address_lbl setStringValue: _NS("Address")];
212
213     [[o_net_mode cellAtRow:0 column:0] setTitle: _NS("Unicast")];
214     [[o_net_mode cellAtRow:1 column:0] setTitle: _NS("Multicast")];
215
216     [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
217     [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
218
219     [o_eyetv_chn_bgbar setUsesThreadedAnimation: YES];
220
221     [o_capture_mode_pop removeAllItems];
222     [o_capture_mode_pop addItemWithTitle: @"iSight"];
223     [o_capture_mode_pop addItemWithTitle: _NS("Screen")];
224     [o_capture_mode_pop addItemWithTitle: @"EyeTV"];
225     [o_screen_lbl setStringValue: _NS("Screen Capture Input")];
226     [o_screen_long_lbl setStringValue: _NS("This facility allows you to process your screen's output.")];
227     [o_screen_fps_lbl setStringValue: _NS("Frames per Second:")];
228     [o_screen_left_lbl setStringValue: _NS("Subscreen left:")];
229     [o_screen_top_lbl setStringValue: _NS("Subscreen top:")];
230     [o_screen_width_lbl setStringValue: _NS("Subscreen width:")];
231     [o_screen_height_lbl setStringValue: _NS("Subscreen height:")];
232     [o_screen_follow_mouse_ckb setTitle: _NS("Follow the mouse")];
233     [o_eyetv_currentChannel_lbl setStringValue: _NS("Current channel:")];
234     [o_eyetv_previousProgram_btn setTitle: _NS("Previous Channel")];
235     [o_eyetv_nextProgram_btn setTitle: _NS("Next Channel")];
236     [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
237     [o_eyetv_noInstance_lbl setStringValue: _NS("EyeTV is not launched")];
238     [o_eyetv_noInstanceLong_lbl setStringValue: _NS("VLC could not connect to EyeTV.\nMake sure that you installed VLC's EyeTV plugin.")];
239     [o_eyetv_launchEyeTV_btn setTitle: _NS("Launch EyeTV now")];
240     [o_eyetv_getPlugin_btn setTitle: _NS("Download Plugin")];
241
242     [self setSubPanel];
243
244     [[NSNotificationCenter defaultCenter] addObserver: self
245         selector: @selector(openFilePathChanged:)
246         name: NSControlTextDidChangeNotification
247         object: o_file_path];
248
249     [[NSNotificationCenter defaultCenter] addObserver: self
250         selector: @selector(openDiscInfoChanged:)
251         name: NSControlTextDidChangeNotification
252         object: o_disc_device];
253     [[NSNotificationCenter defaultCenter] addObserver: self
254         selector: @selector(openDiscInfoChanged:)
255         name: NSControlTextDidChangeNotification
256         object: o_disc_title];
257     [[NSNotificationCenter defaultCenter] addObserver: self
258         selector: @selector(openDiscInfoChanged:)
259         name: NSControlTextDidChangeNotification
260         object: o_disc_chapter];
261     [[NSNotificationCenter defaultCenter] addObserver: self
262         selector: @selector(openDiscInfoChanged:)
263         name: NSControlTextDidChangeNotification
264         object: o_disc_videots_folder];
265
266     [[NSNotificationCenter defaultCenter] addObserver: self
267         selector: @selector(openNetInfoChanged:)
268         name: NSControlTextDidChangeNotification
269         object: o_net_udp_port];
270     [[NSNotificationCenter defaultCenter] addObserver: self
271         selector: @selector(openNetInfoChanged:)
272         name: NSControlTextDidChangeNotification
273         object: o_net_udpm_addr];
274     [[NSNotificationCenter defaultCenter] addObserver: self
275         selector: @selector(openNetInfoChanged:)
276         name: NSControlTextDidChangeNotification
277         object: o_net_udpm_port];
278     [[NSNotificationCenter defaultCenter] addObserver: self
279         selector: @selector(openNetInfoChanged:)
280         name: NSControlTextDidChangeNotification
281         object: o_net_http_url];
282
283     [[NSDistributedNotificationCenter defaultCenter] addObserver: self
284                                                         selector: @selector(eyetvChanged:)
285                                                             name: NULL
286                                                           object: @"VLCEyeTVSupport"
287                                               suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
288
289     [[NSNotificationCenter defaultCenter] addObserver: self
290                                              selector: @selector(screenFPSfieldChanged:)
291                                                  name: NSControlTextDidChangeNotification
292                                                object: o_screen_fps_fld];
293
294     /* register clicks on text fields */
295     [[NSNotificationCenter defaultCenter] addObserver: self
296                                              selector: @selector(textFieldWasClicked:)
297                                                  name: @"VLCOpenTextFieldWasClicked"
298                                                object: nil];
299 }
300
301 - (void)setSubPanel
302 {
303     int i_index;
304     module_config_t * p_item;
305
306     [o_file_sub_ckbox setTitle: _NS("Load subtitles file:")];
307     [o_file_sub_btn_settings setTitle: _NS("Settings...")];
308     [o_file_sub_btn_browse setTitle: _NS("Browse...")];
309     [o_file_sub_override setTitle: _NS("Override parametters")];
310     [o_file_sub_delay_lbl setStringValue: _NS("Delay")];
311     [o_file_sub_delay_stp setEnabled: NO];
312     [o_file_sub_fps_lbl setStringValue: _NS("FPS")];
313     [o_file_sub_fps_stp setEnabled: NO];
314     [o_file_sub_encoding_lbl setStringValue: _NS("Subtitles encoding")];
315     [o_file_sub_encoding_pop removeAllItems];
316     [o_file_sub_size_lbl setStringValue: _NS("Font size")];
317     [o_file_sub_size_pop removeAllItems];
318     [o_file_sub_align_lbl setStringValue: _NS("Subtitles alignment")];
319     [o_file_sub_align_pop removeAllItems];
320     [o_file_sub_ok_btn setStringValue: _NS("OK")];
321     [o_file_sub_font_box setTitle: _NS("Font Properties")];
322     [o_file_sub_file_box setTitle: _NS("Subtitle File")];
323
324     p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-encoding" );
325
326     if( p_item )
327     {
328         for( i_index = 0; p_item->ppsz_list && p_item->ppsz_list[i_index];
329              i_index++ )
330         {
331             [o_file_sub_encoding_pop addItemWithTitle:
332                 [NSString stringWithUTF8String: p_item->ppsz_list[i_index]]];
333         }
334         [o_file_sub_encoding_pop selectItemWithTitle:
335                 [NSString stringWithUTF8String: p_item->value.psz]];
336     }
337
338     p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-align" );
339
340     if ( p_item )
341     {
342         for ( i_index = 0; i_index < p_item->i_list; i_index++ )
343         {
344             [o_file_sub_align_pop addItemWithTitle:
345                 [NSString stringWithUTF8String:
346                 p_item->ppsz_list_text[i_index]]];
347         }
348         [o_file_sub_align_pop selectItemAtIndex: p_item->value.i];
349     }
350
351     p_item = config_FindConfig( VLC_OBJECT(p_intf), "freetype-rel-fontsize" );
352
353     if ( p_item )
354     {
355         for ( i_index = 0; i_index < p_item->i_list; i_index++ )
356         {
357             [o_file_sub_size_pop addItemWithTitle:
358                 [NSString stringWithUTF8String:
359                 p_item->ppsz_list_text[i_index]]];
360             if ( p_item->value.i == p_item->pi_list[i_index] )
361             {
362                 [o_file_sub_size_pop selectItemAtIndex: i_index];
363             }
364         }
365     }
366 }
367
368 - (void)openTarget:(int)i_type
369 {
370     int i_result;
371
372     b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
373
374     [o_tabview selectTabViewItemAtIndex: i_type];
375     [o_file_sub_ckbox setState: NSOffState];
376  
377     i_result = [NSApp runModalForWindow: o_panel];
378     [o_panel close];
379
380     if( i_result )
381     {
382         NSMutableDictionary *o_dic;
383         NSMutableArray *o_options = [NSMutableArray array];
384         unsigned int i;
385
386         o_dic = [NSMutableDictionary dictionaryWithObject: [o_mrl stringValue] forKey: @"ITEM_URL"];
387         if( [o_file_sub_ckbox state] == NSOnState )
388         {
389             module_config_t * p_item;
390
391             [o_options addObject: [NSString stringWithFormat: @"sub-file=%@", [o_file_sub_path stringValue]]];
392             if( [o_file_sub_override state] == NSOnState )
393             {
394                 [o_options addObject: [NSString stringWithFormat: @"sub-delay=%i", (int)( [o_file_sub_delay intValue] * 10 )]];
395                 [o_options addObject: [NSString stringWithFormat: @"sub-fps=%f", [o_file_sub_fps floatValue]]];
396             }
397             [o_options addObject: [NSString stringWithFormat:
398                     @"subsdec-encoding=%@",
399                     [o_file_sub_encoding_pop titleOfSelectedItem]]];
400             [o_options addObject: [NSString stringWithFormat:
401                     @"subsdec-align=%i",
402                     [o_file_sub_align_pop indexOfSelectedItem]]];
403
404             p_item = config_FindConfig( VLC_OBJECT(p_intf),
405                                             "freetype-rel-fontsize" );
406
407             if ( p_item )
408             {
409                 [o_options addObject: [NSString stringWithFormat:
410                     @"freetype-rel-fontsize=%i",
411                     p_item->pi_list[[o_file_sub_size_pop indexOfSelectedItem]]]];
412             }
413         }
414         if( [o_output_ckbox state] == NSOnState )
415         {
416             for (i = 0 ; i < [[o_sout_options mrl] count] ; i++)
417             {
418                 [o_options addObject: [NSString stringWithString:
419                       [[(VLCOutput *)o_sout_options mrl] objectAtIndex: i]]];
420             }
421         }
422         if( [o_file_slave_ckbox state] && o_file_slave_path )
423            [o_options addObject: [NSString stringWithFormat: @"input-slave=%@", o_file_slave_path]];
424         if( [[[o_tabview selectedTabViewItem] label] isEqualToString: _NS("Capture")] )
425         {
426             if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
427                 [o_options addObject: [NSString stringWithFormat: @"screen-fps=%f", [o_screen_fps_fld floatValue]]];
428                 [o_options addObject: [NSString stringWithFormat: @"screen-left=%i", [o_screen_left_fld intValue]]];
429                 [o_options addObject: [NSString stringWithFormat: @"screen-top=%i", [o_screen_top_fld intValue]]];
430                 [o_options addObject: [NSString stringWithFormat: @"screen-width=%i", [o_screen_width_fld intValue]]];
431                 [o_options addObject: [NSString stringWithFormat: @"screen-height=%i", [o_screen_height_fld intValue]]];
432                 if( [o_screen_follow_mouse_ckb intValue] == YES )
433                     [o_options addObject: @"screen-follow-mouse"];
434                 else
435                     [o_options addObject: @"no-screen-follow-mouse"];
436         }
437
438         /* apply the options to our item(s) */
439         [o_dic setObject: (NSArray *)[o_options copy] forKey: @"ITEM_OPTIONS"];
440         if( b_autoplay )
441             [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:NO];
442         else
443             [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:YES];
444     }
445 }
446
447 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
448 {
449     NSString *o_label = [o_tvi label];
450
451     if( [o_label isEqualToString: _NS("File")] )
452     {
453         [self openFilePathChanged: nil];
454     }
455     else if( [o_label isEqualToString: _NS("Disc")] )
456     {
457         [self openDiscTypeChanged: nil];
458     }
459     else if( [o_label isEqualToString: _NS("Network")] )
460     {
461         [self openNetInfoChanged: nil];
462     }
463     else if( [o_label isEqualToString: _NS("Capture")] )
464     {
465         [self openCaptureModeChanged: nil];
466     }
467 }
468
469 - (IBAction)expandMRLfieldAction:(id)sender
470 {
471     NSRect o_win_rect, o_view_rect;
472     o_win_rect = [o_panel frame];
473     o_view_rect = [o_mrl_view frame];
474
475     if( [o_mrl_btn state] == NSOffState )
476     {
477         /* we need to collaps, restore the panel size */
478         o_win_rect.size.height = o_win_rect.size.height - o_view_rect.size.height;
479         o_win_rect.origin.y = ( o_win_rect.origin.y + o_view_rect.size.height ) - o_view_rect.size.height;
480
481         /* remove the MRL view */
482         [o_mrl_view removeFromSuperviewWithoutNeedingDisplay];
483     } else {
484         /* we need to expand */
485         [o_mrl_view setFrame: NSMakeRect( 0,
486                                          [o_mrl_btn frame].origin.y,
487                                          o_view_rect.size.width,
488                                          o_view_rect.size.height )];
489         [o_mrl_view setNeedsDisplay: YES];
490         [o_mrl_view setAutoresizesSubviews: YES];
491
492         /* add the MRL view */
493         [[o_panel contentView] addSubview: o_mrl_view];
494         o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
495     }
496
497     [o_panel setFrame: o_win_rect display:YES animate: YES];
498     [o_panel displayIfNeeded];
499 }
500
501 - (IBAction)inputSlaveAction:(id)sender
502 {
503     if( sender == o_file_slave_ckbox )
504     {
505         [o_file_slave_select_btn setEnabled: [o_file_slave_ckbox state]];
506         [o_file_slave_filename_txt setStringValue: @""];
507     }
508     else
509     {
510         NSOpenPanel *o_open_panel;
511         o_open_panel = [NSOpenPanel openPanel];
512         [o_open_panel setCanChooseFiles: YES];
513         [o_open_panel setCanChooseDirectories: NO];
514         if( [o_open_panel runModalForDirectory: nil file: nil types: nil] == NSOKButton )
515         {
516             if( o_file_slave_path )
517                 [o_file_slave_path release];
518             o_file_slave_path = [[o_open_panel filenames] objectAtIndex: 0];
519             [o_file_slave_path retain];
520             NSFileWrapper *o_file_wrapper;
521             o_file_wrapper = [[NSFileWrapper alloc] initWithPath: [[o_open_panel filenames] objectAtIndex: 0]];
522             [o_file_slave_filename_txt setStringValue: [NSString stringWithFormat: @"\"%@\"", [o_file_wrapper preferredFilename]]];
523         }
524         else
525             [o_file_slave_filename_txt setStringValue: @""];
526     }
527 }
528
529 - (void)openFileGeneric
530 {
531     [self openFilePathChanged: nil];
532     [self openTarget: 0];
533 }
534
535 - (void)openDisc
536 {
537     [self openDiscTypeChanged: nil];
538     [self openTarget: 1];
539 }
540
541 - (void)openNet
542 {
543     [self openNetInfoChanged: nil];
544     [self openTarget: 2];
545 }
546
547 - (void)openCapture
548 {
549     [self openCaptureModeChanged: nil];
550     [self showCaptureView: o_capture_label_view];
551     [self openTarget: 3];
552 }
553
554 - (void)openFilePathChanged:(NSNotification *)o_notification
555 {
556     NSString *o_filename = [o_file_path stringValue];
557     bool b_stream = [o_file_stream state];
558     BOOL b_dir = NO;
559
560     [[NSFileManager defaultManager] fileExistsAtPath:o_filename isDirectory:&b_dir];
561
562     char *psz_uri = make_URI([o_filename UTF8String]);
563     if( !psz_uri ) return;
564
565     NSMutableString *o_mrl_string = [NSMutableString stringWithUTF8String: psz_uri ];
566     NSRange offile = [o_mrl_string rangeOfString:@"file"];
567     free( psz_uri );
568
569     if( b_dir )
570     {
571         [o_mrl_string replaceCharactersInRange:offile withString: @"directory"];
572     }
573     else if( b_stream )
574     {
575         [o_mrl_string replaceCharactersInRange:offile withString: @"stream"];
576     }
577     [o_mrl setStringValue: o_mrl_string];
578 }
579
580 - (IBAction)openFileBrowse:(id)sender
581 {
582     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
583  
584     [o_open_panel setAllowsMultipleSelection: NO];
585     [o_open_panel setCanChooseDirectories: YES];
586     [o_open_panel setTitle: _NS("Open File")];
587     [o_open_panel setPrompt: _NS("Open")];
588
589     [o_open_panel beginSheetForDirectory:nil
590         file:nil
591         types:nil
592         modalForWindow:[sender window]
593         modalDelegate: self
594         didEndSelector: @selector(pathChosenInPanel:
595                         withReturn:
596                         contextInfo:)
597         contextInfo: nil];
598 }
599
600 - (void)pathChosenInPanel: (NSOpenPanel *) sheet withReturn:(int)returnCode contextInfo:(void  *)contextInfo
601 {
602     if (returnCode == NSFileHandlingPanelOKButton)
603     {
604         NSString *o_filename = [[sheet filenames] objectAtIndex: 0];
605         [o_file_path setStringValue: o_filename];
606         [self openFilePathChanged: nil];
607     }
608 }
609
610 - (IBAction)openFileStreamChanged:(id)sender
611 {
612     [self openFilePathChanged: nil];
613 }
614
615 - (IBAction)openDiscTypeChanged:(id)sender
616 {
617     NSString *o_type;
618     BOOL b_device, b_no_menus, b_title_chapter;
619  
620     [o_disc_device removeAllItems];
621     b_title_chapter = ![o_disc_dvd_menus state];
622  
623     o_type = [[o_disc_type selectedCell] title];
624
625     if ( [o_type isEqualToString: _NS("VIDEO_TS folder")] )
626     {
627         b_device = NO; b_no_menus = YES;
628     }
629     else
630     {
631         NSArray *o_devices;
632         NSString *o_disc;
633         const char *psz_class = NULL;
634         b_device = YES;
635
636         if ( [o_type isEqualToString: _NS("VCD")] )
637         {
638             psz_class = kIOCDMediaClass;
639             o_disc = o_type;
640             b_no_menus = NO; b_title_chapter = YES;
641                 }
642         else if ( [o_type isEqualToString: _NS("Audio CD")])
643         {
644             psz_class = kIOCDMediaClass;
645             o_disc = o_type;
646             b_no_menus = NO; b_title_chapter = NO;
647         }
648         else
649         {
650             psz_class = kIODVDMediaClass;
651             o_disc = o_type;
652             b_no_menus = YES;
653         }
654  
655         o_devices = GetEjectableMediaOfClass( psz_class );
656         if ( o_devices != nil )
657         {
658             int i_devices = [o_devices count];
659  
660             if ( i_devices )
661             {
662                                 for( int i = 0; i < i_devices; i++ )
663                 {
664                     [o_disc_device
665                         addItemWithObjectValue: [o_devices objectAtIndex: i]];
666                 }
667
668                 [o_disc_device selectItemAtIndex: 0];
669             }
670             else
671             {
672                 [o_disc_device setStringValue:
673                     [NSString stringWithFormat: _NS("No %@s found"), o_disc]];
674             }
675         }
676     }
677
678     [o_disc_device setEnabled: b_device];
679     [o_disc_title setEnabled: b_title_chapter];
680     [o_disc_title_stp setEnabled: b_title_chapter];
681     [o_disc_chapter setEnabled: b_title_chapter];
682     [o_disc_chapter_stp setEnabled: b_title_chapter];
683     [o_disc_videots_folder setEnabled: !b_device];
684     [o_disc_videots_btn_browse setEnabled: !b_device];
685     [o_disc_dvd_menus setEnabled: b_no_menus];
686
687     [self openDiscInfoChanged: nil];
688 }
689
690 - (IBAction)openDiscStepperChanged:(id)sender
691 {
692     int i_tag = [sender tag];
693
694     if( i_tag == 0 )
695     {
696         [o_disc_title setIntValue: [o_disc_title_stp intValue]];
697     }
698     else if( i_tag == 1 )
699     {
700         [o_disc_chapter setIntValue: [o_disc_chapter_stp intValue]];
701     }
702
703     [self openDiscInfoChanged: nil];
704 }
705
706 - (void)openDiscInfoChanged:(NSNotification *)o_notification
707 {
708     NSString *o_type;
709     NSString *o_device;
710     NSString *o_videots;
711     NSString *o_mrl_string;
712     int i_title, i_chapter;
713     BOOL b_no_menus;
714
715     o_type = [[o_disc_type selectedCell] title];
716     o_device = [o_disc_device stringValue];
717     i_title = [o_disc_title intValue];
718     i_chapter = [o_disc_chapter intValue];
719     o_videots = [o_disc_videots_folder stringValue];
720     b_no_menus = [o_disc_dvd_menus state];
721
722     if ( [o_type isEqualToString: _NS("VCD")] )
723     {
724         if ( [o_device isEqualToString:
725                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
726             o_device = @"";
727         o_mrl_string = [NSString stringWithFormat: @"vcd://%@@%i:%i",
728                         o_device, i_title, i_chapter];
729     }
730     else if ( [o_type isEqualToString: _NS("Audio CD")] )
731     {
732         if ( [o_device isEqualToString:
733                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
734             o_device = @"";
735         o_mrl_string = [NSString stringWithFormat: @"cdda://%@",
736                         o_device];
737     }
738     else if ( [o_type isEqualToString: _NS("DVD")] )
739     {
740         if ( [o_device isEqualToString:
741                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
742             o_device = @"";
743         if ( b_no_menus )
744             o_mrl_string = [NSString stringWithFormat: @"dvdread://%@@%i:%i-",
745                             o_device, i_title, i_chapter];
746         else
747                         o_mrl_string = [NSString stringWithFormat: @"dvdnav://%@",
748                             o_device];
749             
750     }
751     else /* VIDEO_TS folder */
752     {
753         if ( b_no_menus )
754             o_mrl_string = [NSString stringWithFormat: @"dvdread://%@@%i:%i",
755                             o_videots, i_title, i_chapter];
756         else
757                         o_mrl_string = [NSString stringWithFormat: @"dvdnav://%@",
758                             o_videots];            
759     }
760
761     [o_mrl setStringValue: o_mrl_string];
762 }
763
764 - (IBAction)openDiscMenusChanged:(id)sender
765 {
766     [self openDiscInfoChanged: nil];
767     [self openDiscTypeChanged: nil];
768 }
769
770 - (IBAction)openVTSBrowse:(id)sender
771 {
772     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
773
774     [o_open_panel setAllowsMultipleSelection: NO];
775     [o_open_panel setCanChooseFiles: NO];
776     [o_open_panel setCanChooseDirectories: YES];
777     [o_open_panel setTitle: _NS("Open VIDEO_TS Directory")];
778     [o_open_panel setPrompt: _NS("Open")];
779
780     if( [o_open_panel runModalForDirectory: nil
781             file: nil types: nil] == NSOKButton )
782     {
783         NSString *o_dirname = [[o_open_panel filenames] objectAtIndex: 0];
784         [o_disc_videots_folder setStringValue: o_dirname];
785         [self openDiscInfoChanged: nil];
786     }
787 }
788
789 - (void)textFieldWasClicked:(NSNotification *)o_notification
790 {
791     if( [o_notification object] == o_net_udp_port )
792         [o_net_mode selectCellAtRow: 0 column: 0];
793     else if( [o_notification object] == o_net_udpm_addr ||
794              [o_notification object] == o_net_udpm_port )
795         [o_net_mode selectCellAtRow: 1 column: 0];
796     else
797         [o_net_mode selectCellAtRow: 2 column: 0];
798
799     [self openNetInfoChanged: nil];
800 }
801
802 - (IBAction)openNetModeChanged:(id)sender
803 {
804     if( sender == o_net_mode )
805     {
806         if( [[sender selectedCell] tag] == 0 )
807             [o_panel makeFirstResponder: o_net_udp_port];
808         else if ( [[sender selectedCell] tag] == 1 )
809             [o_panel makeFirstResponder: o_net_udpm_addr];
810         else
811             msg_Warn( p_intf, "Unknown sender tried to change UDP/RTP mode" );
812     }
813
814     [self openNetInfoChanged: nil];
815 }
816
817 - (IBAction)openNetStepperChanged:(id)sender
818 {
819     int i_tag = [sender tag];
820
821     if( i_tag == 0 )
822     {
823         [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
824         [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
825                                                             object: o_net_udp_port];
826         [o_panel makeFirstResponder: o_net_udp_port];
827     }
828     else if( i_tag == 1 )
829     {
830         [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
831         [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
832                                                             object: o_net_udpm_port];
833         [o_panel makeFirstResponder: o_net_udpm_port];
834     }
835
836     [self openNetInfoChanged: nil];
837 }
838
839 - (void)openNetInfoChanged:(NSNotification *)o_notification
840 {
841     NSString *o_mrl_string = [NSString string];
842
843     if( [o_net_udp_panel isVisible] )
844     {
845         NSString *o_mode;
846         o_mode = [[o_net_mode selectedCell] title];
847
848         if( [o_mode isEqualToString: _NS("Unicast")] )
849         {
850             int i_port = [o_net_udp_port intValue];
851
852             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
853                 o_mrl_string = [NSString stringWithString: @"udp://"];
854             else
855                 o_mrl_string = [NSString stringWithString: @"rtp://"];
856
857             if( i_port != config_GetInt( p_intf, "server-port" ) )
858             {
859                 o_mrl_string =
860                     [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
861             }
862         }
863         else if( [o_mode isEqualToString: _NS("Multicast")] )
864         {
865             NSString *o_addr = [o_net_udpm_addr stringValue];
866             int i_port = [o_net_udpm_port intValue];
867
868             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
869                 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
870             else
871                 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
872
873             if( i_port != config_GetInt( p_intf, "server-port" ) )
874             {
875                 o_mrl_string =
876                     [o_mrl_string stringByAppendingFormat: @":%i", i_port];
877             }
878         }
879     }
880     else
881     {
882         NSString *o_url = [o_net_http_url stringValue];
883
884         if ( ![o_url hasPrefix:@"http:"] && ![o_url hasPrefix:@"ftp:"]
885               && ![o_url hasPrefix:@"mms"] && ![o_url hasPrefix:@"rtsp"] )
886             o_mrl_string = [NSString stringWithFormat: @"http://%@", o_url];
887         else
888             o_mrl_string = o_url;
889     }
890     [o_mrl setStringValue: o_mrl_string];
891 }
892
893 - (IBAction)openNetUDPButtonAction:(id)sender
894 {
895     if( sender == o_net_openUDP_btn )
896     {
897         [NSApp beginSheet: o_net_udp_panel
898            modalForWindow: o_panel
899             modalDelegate: self
900            didEndSelector: NULL
901               contextInfo: nil];
902         [self openNetInfoChanged: nil];
903     }
904     else if( sender == o_net_udp_cancel_btn )
905     {
906         [o_net_udp_panel orderOut: sender];
907         [NSApp endSheet: o_net_udp_panel];
908     }
909     else if( sender == o_net_udp_ok_btn )
910     {
911         NSString *o_mrl_string = [NSString string];
912         if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Unicast")] )
913         {
914             int i_port = [o_net_udp_port intValue];
915             
916             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
917                 o_mrl_string = [NSString stringWithString: @"udp://"];
918             else
919                 o_mrl_string = [NSString stringWithString: @"rtp://"];
920
921             if( i_port != config_GetInt( p_intf, "server-port" ) )
922             {
923                 o_mrl_string =
924                 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
925             }
926         }
927         else if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Multicast")] )
928         {
929             NSString *o_addr = [o_net_udpm_addr stringValue];
930             int i_port = [o_net_udpm_port intValue];
931             
932             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
933                 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
934             else
935                 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
936
937             if( i_port != config_GetInt( p_intf, "server-port" ) )
938             {
939                 o_mrl_string =
940                 [o_mrl_string stringByAppendingFormat: @":%i", i_port];
941             }
942         }
943         [o_mrl setStringValue: o_mrl_string];
944         [o_net_http_url setStringValue: o_mrl_string];
945         [o_net_udp_panel orderOut: sender];
946         [NSApp endSheet: o_net_udp_panel];
947     }
948 }
949     
950 - (void)openFile
951 {
952     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
953     int i;
954     b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
955  
956     [o_open_panel setAllowsMultipleSelection: YES];
957     [o_open_panel setCanChooseDirectories: YES];
958     [o_open_panel setTitle: _NS("Open File")];
959     [o_open_panel setPrompt: _NS("Open")];
960  
961     if( [o_open_panel runModalForDirectory: nil
962             file: nil types: nil] == NSOKButton )
963     {
964         NSArray *o_array = [NSArray array];
965         NSArray *o_values = [[o_open_panel filenames]
966                 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
967
968         for( i = 0; i < (int)[o_values count]; i++)
969         {
970             NSDictionary *o_dic;
971             o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
972             o_array = [o_array arrayByAddingObject: o_dic];
973         }
974         if( b_autoplay )
975             [o_playlist appendArray: o_array atPos: -1 enqueue:NO];
976         else
977             [o_playlist appendArray: o_array atPos: -1 enqueue:YES];
978     }
979 }
980
981 - (void)showCaptureView: theView
982 {
983     NSRect o_view_rect;
984     o_view_rect = [theView frame];
985     if( o_currentCaptureView )
986     {
987         [o_currentCaptureView removeFromSuperviewWithoutNeedingDisplay];
988         [o_currentCaptureView release];
989     }
990     [theView setFrame: NSMakeRect( 0, -10, o_view_rect.size.width, o_view_rect.size.height)];
991     [theView setNeedsDisplay: YES];
992     [theView setAutoresizesSubviews: YES];
993     [[[o_tabview tabViewItemAtIndex: 3] view] addSubview: theView];
994     [theView displayIfNeeded];
995     o_currentCaptureView = theView;
996     [o_currentCaptureView retain];
997 }
998
999 - (IBAction)openCaptureModeChanged:(id)sender
1000 {
1001     if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: @"EyeTV"] )
1002     {
1003         if( [[[VLCMain sharedInstance] eyeTVController] isEyeTVrunning] == YES )
1004         {
1005             if( [[[VLCMain sharedInstance] eyeTVController] isDeviceConnected] == YES )
1006             {
1007                 [self showCaptureView: o_eyetv_running_view];
1008                 [self setupChannelInfo];
1009             }
1010             else
1011             {
1012                 setEyeTVUnconnected;
1013             }
1014         }
1015         else
1016             [self showCaptureView: o_eyetv_notLaunched_view];
1017         [o_mrl setStringValue: @""];
1018     } 
1019     else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
1020     {
1021         [self showCaptureView: o_screen_view];
1022         [o_mrl setStringValue: @"screen://"];
1023         [o_screen_height_fld setIntValue: config_GetInt( p_intf, "screen-height" )];
1024         [o_screen_width_fld setIntValue: config_GetInt( p_intf, "screen-width" )];
1025         [o_screen_fps_fld setFloatValue: config_GetFloat( p_intf, "screen-fps" )];
1026         [o_screen_left_fld setIntValue: config_GetInt( p_intf, "screen-left" )];
1027         [o_screen_top_fld setIntValue: config_GetInt( p_intf, "screen-top" )];
1028         [o_screen_follow_mouse_ckb setIntValue: config_GetInt( p_intf, "screen-follow-mouse" )];
1029     }
1030     else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: @"iSight"] )
1031     {
1032         [o_capture_lbl setStringValue: _NS("iSight Capture Input")];
1033         [o_capture_long_lbl setStringValue: _NS("This facility allows you to process your iSight's input signal.\n\nNo settings are available in this version, so you will be provided a 640px*480px raw video stream.\n\nLive Audio input is not supported.")];
1034         [o_capture_lbl displayIfNeeded];
1035         [o_capture_long_lbl displayIfNeeded];
1036         
1037         [self showCaptureView: o_capture_label_view];
1038         [o_mrl setStringValue: @"qtcapture://"];
1039     }
1040 }
1041
1042 - (IBAction)screenStepperChanged:(id)sender
1043 {
1044     [o_screen_fps_fld setFloatValue: [o_screen_fps_stp floatValue]];
1045     [o_panel makeFirstResponder: o_screen_fps_fld];
1046     [o_mrl setStringValue: @"screen://"];
1047 }
1048
1049 - (void)screenFPSfieldChanged:(NSNotification *)o_notification
1050 {
1051     [o_screen_fps_stp setFloatValue: [o_screen_fps_fld floatValue]];
1052     if( [[o_screen_fps_fld stringValue] isEqualToString: @""] )
1053         [o_screen_fps_fld setFloatValue: 1.0];
1054     [o_mrl setStringValue: @"screen://"];
1055 }
1056
1057 - (IBAction)eyetvSwitchChannel:(id)sender
1058 {
1059     if( sender == o_eyetv_nextProgram_btn )
1060     {
1061         int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: YES];
1062         [o_eyetv_channels_pop selectItemWithTag:chanNum];
1063         [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1064     }
1065     else if( sender == o_eyetv_previousProgram_btn )
1066     {
1067         int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: NO];
1068         [o_eyetv_channels_pop selectItemWithTag:chanNum];
1069         [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1070     }
1071     else if( sender == o_eyetv_channels_pop )
1072     {
1073         int chanNum = [[sender selectedItem] tag];
1074         [[[VLCMain sharedInstance] eyeTVController] selectChannel:chanNum];
1075         [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1076     }
1077     else
1078         msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
1079 }
1080
1081 - (IBAction)eyetvLaunch:(id)sender
1082 {
1083     [[[VLCMain sharedInstance] eyeTVController] launchEyeTV];
1084 }
1085
1086 - (IBAction)eyetvGetPlugin:(id)sender
1087 {
1088     [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"http://www.videolan.org/vlc/eyetv"]];
1089 }
1090
1091 - (void)eyetvChanged:(NSNotification *)o_notification
1092 {
1093     if( [[o_notification name] isEqualToString: @"DeviceAdded"] )
1094     {
1095         msg_Dbg( VLCIntf, "eyetv device was added" );
1096         [self showCaptureView: o_eyetv_running_view];
1097         [self setupChannelInfo];
1098     }
1099     else if( [[o_notification name] isEqualToString: @"DeviceRemoved"] )
1100     {
1101         /* leave the channel selection like that,
1102          * switch to our "no device" tab */
1103         msg_Dbg( VLCIntf, "eyetv device was removed" );
1104         setEyeTVUnconnected;
1105     }
1106     else if( [[o_notification name] isEqualToString: @"PluginQuit"] )
1107     {
1108         /* switch to the "launch eyetv" tab */
1109         msg_Dbg( VLCIntf, "eyetv was terminated" );
1110         [self showCaptureView: o_eyetv_notLaunched_view];
1111     }
1112     else if( [[o_notification name] isEqualToString: @"PluginInit"] )
1113     {
1114         /* we got no device yet */
1115         msg_Dbg( VLCIntf, "eyetv was launched, no device yet" );
1116         setEyeTVUnconnected;
1117     }
1118     else
1119         msg_Warn( VLCIntf, "unknown external notify '%s' received", [[o_notification name] UTF8String] );
1120 }    
1121
1122 /* little helper method, since this code needs to be run by multiple objects */
1123 - (void)setupChannelInfo
1124 {
1125     /* set up channel selection */
1126     [o_eyetv_channels_pop removeAllItems];
1127     [o_eyetv_chn_bgbar setHidden: NO];
1128     [o_eyetv_chn_bgbar animate: self];
1129     [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
1130     [o_eyetv_chn_status_txt setHidden: NO];
1131  
1132     /* retrieve info */
1133     NSEnumerator *channels = [[[VLCMain sharedInstance] eyeTVController] allChannels];
1134     int x = -2;
1135     [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("Composite input")
1136                                                action: nil
1137                                         keyEquivalent: @""] setTag:x++];
1138     [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("S-Video input")
1139                                                action: nil
1140                                         keyEquivalent: @""] setTag:x++];
1141     if( channels ) 
1142     {
1143         NSString *channel;
1144         [[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]];
1145         while( channel = [channels nextObject] )
1146         {
1147             /* we have to add items this way, because we accept duplicates
1148              * additionally, we save a bit of time */
1149             [[[o_eyetv_channels_pop menu] addItemWithTitle: channel
1150                                                    action: nil
1151                                             keyEquivalent: @""] setTag:++x];
1152         }
1153         /* make Tuner the default */
1154         [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] eyeTVController] currentChannel]];
1155     }
1156  
1157     /* clean up GUI */
1158     [o_eyetv_chn_bgbar setHidden: YES];
1159     [o_eyetv_chn_status_txt setHidden: YES];
1160 }
1161
1162 - (IBAction)subsChanged:(id)sender
1163 {
1164     if ([o_file_sub_ckbox state] == NSOnState)
1165     {
1166         [o_file_sub_btn_settings setEnabled:YES];
1167     }
1168     else
1169     {
1170         [o_file_sub_btn_settings setEnabled:NO];
1171     }
1172 }
1173
1174 - (IBAction)subSettings:(id)sender
1175 {
1176     [NSApp beginSheet: o_file_sub_sheet
1177         modalForWindow: [sender window]
1178         modalDelegate: self
1179         didEndSelector: NULL
1180         contextInfo: nil];
1181 }
1182
1183 - (IBAction)subCloseSheet:(id)sender
1184 {
1185     [o_file_sub_sheet orderOut:sender];
1186     [NSApp endSheet: o_file_sub_sheet];
1187 }
1188     
1189 - (IBAction)subFileBrowse:(id)sender
1190 {
1191     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
1192  
1193     [o_open_panel setAllowsMultipleSelection: NO];
1194     [o_open_panel setTitle: _NS("Open File")];
1195     [o_open_panel setPrompt: _NS("Open")];
1196
1197     if( [o_open_panel runModalForDirectory: nil
1198             file: nil types: nil] == NSOKButton )
1199     {
1200         NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
1201         [o_file_sub_path setStringValue: o_filename];
1202     }
1203 }
1204
1205 - (IBAction)subOverride:(id)sender
1206 {
1207     BOOL b_state = [o_file_sub_override state];
1208     [o_file_sub_delay setEnabled: b_state];
1209     [o_file_sub_delay_stp setEnabled: b_state];
1210     [o_file_sub_fps setEnabled: b_state];
1211     [o_file_sub_fps_stp setEnabled: b_state];
1212 }
1213
1214 - (IBAction)subDelayStepperChanged:(id)sender
1215 {
1216     [o_file_sub_delay setIntValue: [o_file_sub_delay_stp intValue]];
1217 }
1218
1219 - (IBAction)subFpsStepperChanged:(id)sender;
1220 {
1221     [o_file_sub_fps setFloatValue: [o_file_sub_fps_stp floatValue]];
1222 }
1223
1224 - (IBAction)panelCancel:(id)sender
1225 {
1226     [NSApp stopModalWithCode: 0];
1227 }
1228
1229 - (IBAction)panelOk:(id)sender
1230 {
1231     if( [[o_mrl stringValue] length] )
1232     {
1233         [NSApp stopModalWithCode: 1];
1234     }
1235     else
1236     {
1237         NSBeep();
1238     }
1239 }
1240
1241 @end
1242
1243 @implementation VLCOpenTextField
1244
1245 - (void)mouseDown:(NSEvent *)theEvent
1246 {
1247     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
1248                                                         object: self];
1249     [super mouseDown: theEvent];
1250 }
1251
1252 @end