]> git.sesse.net Git - vlc/blob - modules/gui/macosx/open.m
ALL: New output dialog that uses the new --sout syntax.
[vlc] / modules / gui / macosx / open.m
1 /*****************************************************************************
2  * open.m: MacOS X plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id: open.m,v 1.30 2003/04/30 23:58:56 hartman Exp $
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  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <sys/param.h>                                    /* for MAXPATHLEN */
31 #include <string.h>
32
33 #include <paths.h>
34 #include <IOKit/IOKitLib.h>
35 #include <IOKit/IOBSD.h>
36 #include <IOKit/storage/IOMedia.h>
37 #include <IOKit/storage/IOCDMedia.h>
38 #include <IOKit/storage/IODVDMedia.h>
39
40 #include "intf.h"
41 #include "playlist.h"
42 #include "open.h"
43
44 #include "netutils.h"
45
46 /*****************************************************************************
47  * GetEjectableMediaOfClass 
48  *****************************************************************************/
49 NSArray *GetEjectableMediaOfClass( const char *psz_class )
50 {
51     io_object_t next_media;
52     mach_port_t master_port;
53     kern_return_t kern_result;
54     NSArray *o_devices = nil;
55     NSMutableArray *p_list = nil;
56     io_iterator_t media_iterator;
57     CFMutableDictionaryRef classes_to_match;
58
59     kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
60     if( kern_result != KERN_SUCCESS )
61     {
62         return( nil );
63     }
64     
65     classes_to_match = IOServiceMatching( psz_class );
66     if( classes_to_match == NULL )
67     {
68         return( nil );
69     }
70     
71     CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectable ), 
72                           kCFBooleanTrue );
73     
74     kern_result = IOServiceGetMatchingServices( master_port, classes_to_match, 
75                                                 &media_iterator );
76     if( kern_result != KERN_SUCCESS )
77     {
78         return( nil );
79     }
80
81     p_list = [NSMutableArray arrayWithCapacity: 1];
82     
83     next_media = IOIteratorNext( media_iterator );
84     if( next_media != NULL )
85     {
86         char psz_buf[0x32];
87         size_t dev_path_length;
88         CFTypeRef str_bsd_path;
89     
90         do
91         {
92             str_bsd_path = IORegistryEntryCreateCFProperty( next_media,
93                                                             CFSTR( kIOBSDName ),
94                                                             kCFAllocatorDefault,
95                                                             0 );
96             if( str_bsd_path == NULL )
97             {
98                 IOObjectRelease( next_media );
99                 continue;
100             }
101             
102             snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
103             dev_path_length = strlen( psz_buf );
104             
105             if( CFStringGetCString( str_bsd_path,
106                                     (char*)&psz_buf + dev_path_length,
107                                     sizeof(psz_buf) - dev_path_length,
108                                     kCFStringEncodingASCII ) )
109             {
110                 [p_list addObject: [NSString stringWithCString: psz_buf]];
111             }
112             
113             CFRelease( str_bsd_path );
114             
115             IOObjectRelease( next_media );
116         
117         } while( ( next_media = IOIteratorNext( media_iterator ) ) != NULL );
118     }
119     
120     IOObjectRelease( media_iterator );
121
122     o_devices = [NSArray arrayWithArray: p_list];
123
124     return( o_devices );
125 }
126
127 /*****************************************************************************
128  * VLCOpen implementation 
129  *****************************************************************************/
130 @implementation VLCOpen
131
132 - (void)awakeFromNib
133 {
134     intf_thread_t * p_intf = [NSApp getIntf];
135
136     [o_panel setTitle: _NS("Open Source")];
137     [o_mrl_lbl setTitle: _NS("Media Resource Locator (MRL)")];
138     [o_ckbox_enqueue setTitle: _NS("Only enqueue in playlist, do not play")];
139
140     [o_btn_ok setTitle: _NS("OK")];
141     [o_btn_cancel setTitle: _NS("Cancel")];
142
143     [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
144     [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
145     [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
146
147     [o_file_btn_browse setTitle: _NS("Browse...")];
148     [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
149
150     [o_disc_device_lbl setStringValue: _NS("Device name")];
151     [o_disc_title_lbl setStringValue: _NS("Title")];
152     [o_disc_chapter_lbl setStringValue: _NS("Chapter")];
153     [o_disc_videots_btn_browse setTitle: _NS("Browse...")];
154     [o_disc_dvd_menus setTitle: _NS("Use DVD menus (EXPERIMENTAL)")];
155
156     [[o_disc_type cellAtRow:0 column:0] setTitle: _NS("VIDEO_TS folder")];
157     [[o_disc_type cellAtRow:1 column:0] setTitle: _NS("DVD")];
158     [[o_disc_type cellAtRow:2 column:0] setTitle: _NS("VCD")];
159
160     [o_net_udp_port_lbl setStringValue: _NS("Port")];
161     [o_net_udpm_addr_lbl setStringValue: _NS("Address")];
162     [o_net_udpm_port_lbl setStringValue: _NS("Port")];
163     [o_net_http_url_lbl setStringValue: _NS("URL")];
164
165     [[o_net_mode cellAtRow:0 column:0] setTitle: _NS("UDP/RTP")];
166     [[o_net_mode cellAtRow:1 column:0] setTitle: _NS("UDP/RTP Multicast")];
167     [[o_net_mode cellAtRow:2 column:0] setTitle: _NS("HTTP/FTP/MMS")];
168
169     [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
170     [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
171
172     [o_file_sub_ckbox setTitle: _NS("Load subtitles file:")];
173     [o_file_sub_btn_settings setTitle: _NS("Settings...")];
174     [o_file_sub_btn_browse setTitle: _NS("Browse...")];
175     [o_file_sub_override setTitle: _NS("Override")];
176     [o_file_sub_delay_lbl setStringValue: _NS("delay")];
177     [o_file_sub_delay_stp setEnabled: NO];
178     [o_file_sub_fps_lbl setStringValue: _NS("fps")];
179     [o_file_sub_fps_stp setEnabled: NO];
180     [o_file_sub_ok_btn setStringValue: _NS("OK")];
181     
182     [[NSNotificationCenter defaultCenter] addObserver: self
183         selector: @selector(openFilePathChanged:)
184         name: NSControlTextDidChangeNotification
185         object: o_file_path];
186
187     [[NSNotificationCenter defaultCenter] addObserver: self
188         selector: @selector(openDiscInfoChanged:)
189         name: NSControlTextDidChangeNotification
190         object: o_disc_device];
191     [[NSNotificationCenter defaultCenter] addObserver: self
192         selector: @selector(openDiscInfoChanged:)
193         name: NSControlTextDidChangeNotification
194         object: o_disc_title];
195     [[NSNotificationCenter defaultCenter] addObserver: self
196         selector: @selector(openDiscInfoChanged:)
197         name: NSControlTextDidChangeNotification
198         object: o_disc_chapter];
199     [[NSNotificationCenter defaultCenter] addObserver: self
200         selector: @selector(openDiscInfoChanged:)
201         name: NSControlTextDidChangeNotification
202         object: o_disc_videots_folder];
203
204     [[NSNotificationCenter defaultCenter] addObserver: self
205         selector: @selector(openNetInfoChanged:)
206         name: NSControlTextDidChangeNotification
207         object: o_net_udp_port];
208     [[NSNotificationCenter defaultCenter] addObserver: self
209         selector: @selector(openNetInfoChanged:)
210         name: NSControlTextDidChangeNotification
211         object: o_net_udpm_addr];
212     [[NSNotificationCenter defaultCenter] addObserver: self
213         selector: @selector(openNetInfoChanged:)
214         name: NSControlTextDidChangeNotification
215         object: o_net_udpm_port];
216     [[NSNotificationCenter defaultCenter] addObserver: self
217         selector: @selector(openNetInfoChanged:)
218         name: NSControlTextDidChangeNotification
219         object: o_net_http_url];
220 }
221
222 - (void)openTarget:(int)i_type
223 {
224     int i_result;
225
226     [o_tabview selectTabViewItemAtIndex: i_type];
227     [o_file_sub_ckbox setState: NSOffState];
228     
229     i_result = [NSApp runModalForWindow: o_panel];
230     [o_panel close];
231
232     if( i_result )
233     {
234         intf_thread_t * p_intf = [NSApp getIntf];
235
236         NSString *o_source = [o_mrl stringValue];
237         BOOL b_enq = [o_ckbox_enqueue state] == NSOnState ? YES : NO;
238         NSString *subPath = [o_file_sub_path stringValue];
239         
240         [o_playlist appendArray: 
241             [NSArray arrayWithObject: o_source] atPos: -1 enqueue:b_enq];
242         
243         if (([o_file_sub_ckbox state] == NSOnState) && !([subPath isEqualTo: @""]))
244         {
245             config_PutPsz( p_intf, "sub-file", strdup( [subPath cString] ) );
246             if ( [o_file_sub_override state] )
247             {
248                 config_PutInt( p_intf, "sub-delay", (int)( [o_file_sub_delay intValue] * 10 ) );
249                 config_PutFloat( p_intf, "sub-fps", [o_file_sub_fps floatValue] );
250             }
251         }
252         else
253         {
254             config_PutPsz( p_intf, "sub-file", "" );
255             config_PutInt( p_intf, "sub-delay", 0 );
256             config_PutFloat( p_intf, "sub-fps", 0.0 );
257         }
258     }
259 }
260
261 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
262 {
263     NSString *o_label = [o_tvi label];
264
265     if( [o_label isEqualToString: _NS("File")] )
266     {
267         [self openFilePathChanged: nil];
268     }
269     else if( [o_label isEqualToString: _NS("Disc")] )
270     {
271         [self openDiscTypeChanged: nil];
272     }
273     else if( [o_label isEqualToString: _NS("Network")] )
274     {
275         [self openNetModeChanged: nil];
276     }  
277 }
278
279 - (IBAction)openFileGeneric:(id)sender
280 {
281     [self openFilePathChanged: nil];
282     [self openTarget: 0];
283 }
284
285 - (IBAction)openDisc:(id)sender
286 {
287     [self openDiscTypeChanged: nil];
288     [self openTarget: 1];
289 }
290
291 - (IBAction)openNet:(id)sender
292 {
293     [self openNetModeChanged: nil];
294     [self openTarget: 2];
295 }
296
297 - (void)openFilePathChanged:(NSNotification *)o_notification
298 {
299     NSString *o_mrl_string;
300     NSString *o_filename = [o_file_path stringValue];
301     NSString *o_ext = [o_filename pathExtension];
302     vlc_bool_t b_stream = [o_file_stream state];
303     BOOL b_dir = NO;
304     
305     [[NSFileManager defaultManager] fileExistsAtPath:o_filename isDirectory:&b_dir];
306
307     if( b_dir )
308     {
309         o_mrl_string = [NSString stringWithFormat: @"dir:%@", o_filename];
310     }
311     else if( [o_ext isEqualToString: @"bin"] ||
312         [o_ext isEqualToString: @"cue"] ||
313         [o_ext isEqualToString: @"vob"] ||
314         [o_ext isEqualToString: @"iso"] )
315     {
316         o_mrl_string = o_filename;
317     }
318     else
319     {
320         o_mrl_string = [NSString stringWithFormat: @"%s://%@",
321                         b_stream ? "stream" : "file",
322                         o_filename];
323     }
324     [o_mrl setStringValue: o_mrl_string]; 
325 }
326
327 - (IBAction)openFileBrowse:(id)sender
328 {
329     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
330     
331     [o_open_panel setAllowsMultipleSelection: NO];
332     [o_open_panel setCanChooseDirectories: YES];
333     [o_open_panel setTitle: _NS("Open File")];
334     [o_open_panel setPrompt: _NS("Open")];
335
336     [o_open_panel beginSheetForDirectory:nil
337         file:nil
338         types:nil
339         modalForWindow:[sender window]
340         modalDelegate: self
341         didEndSelector: @selector(pathChosenInPanel: 
342                         withReturn:
343                         contextInfo:)
344         contextInfo: nil];
345 }
346
347 - (void)pathChosenInPanel: (NSOpenPanel *) sheet withReturn:(int)returnCode contextInfo:(void  *)contextInfo
348 {
349     if (returnCode == NSFileHandlingPanelOKButton)
350     {
351         NSString *o_filename = [[sheet filenames] objectAtIndex: 0];
352         [o_file_path setStringValue: o_filename];
353         [self openFilePathChanged: nil];
354     }
355 }
356
357 - (IBAction)openFileStreamChanged:(id)sender
358 {
359     [self openFilePathChanged: nil];
360 }
361
362 - (IBAction)openDiscTypeChanged:(id)sender
363 {
364     NSString *o_type;
365     vlc_bool_t b_device, b_menus, b_title_chapter;
366     
367     [o_disc_device removeAllItems];
368     b_title_chapter = ![o_disc_dvd_menus state];
369     
370     o_type = [[o_disc_type selectedCell] title];
371
372     if ( [o_type isEqualToString: _NS("VIDEO_TS folder")] )
373     {
374         b_device = 0; b_menus = 1;
375     }
376     else
377     {
378         NSArray *o_devices;
379         NSString *o_disc;
380         const char *psz_class = NULL;
381         b_device = 1;
382
383         if ( [o_type isEqualToString: _NS("VCD")] )
384         {
385             psz_class = kIOCDMediaClass;
386             o_disc = o_type;
387             b_menus = 0; b_title_chapter = 1;
388             [o_disc_dvd_menus setState: FALSE];
389         }
390         else
391         {
392             psz_class = kIODVDMediaClass;
393             o_disc = o_type;
394             b_menus = 1;
395         }
396     
397         o_devices = GetEjectableMediaOfClass( psz_class );
398         if ( o_devices != nil )
399         {
400             int i_devices = [o_devices count];
401         
402             if ( i_devices )
403             {
404                 int i;
405         
406                 for( i = 0; i < i_devices; i++ )
407                 {
408                     [o_disc_device 
409                         addItemWithObjectValue: [o_devices objectAtIndex: i]];
410                 }
411
412                 [o_disc_device selectItemAtIndex: 0];
413             }
414             else
415             {
416                 [o_disc_device setStringValue: 
417                     [NSString stringWithFormat: _NS("No %@s found"), o_disc]];
418             }
419         }
420     }
421
422     [o_disc_device setEnabled: b_device];
423     [o_disc_title setEnabled: b_title_chapter];
424     [o_disc_title_stp setEnabled: b_title_chapter];
425     [o_disc_chapter setEnabled: b_title_chapter];
426     [o_disc_chapter_stp setEnabled: b_title_chapter];
427     [o_disc_videots_folder setEnabled: !b_device];
428     [o_disc_videots_btn_browse setEnabled: !b_device];
429     [o_disc_dvd_menus setEnabled: b_menus];
430
431     [self openDiscInfoChanged: nil];
432 }
433
434 - (IBAction)openDiscStepperChanged:(id)sender
435 {
436     int i_tag = [sender tag];
437
438     if( i_tag == 0 )
439     {
440         [o_disc_title setIntValue: [o_disc_title_stp intValue]];
441     }
442     else if( i_tag == 1 )
443     {
444         [o_disc_chapter setIntValue: [o_disc_chapter_stp intValue]];
445     }
446
447     [self openDiscInfoChanged: nil];
448 }
449
450 - (void)openDiscInfoChanged:(NSNotification *)o_notification
451 {
452     NSString *o_type;
453     NSString *o_device;
454     NSString *o_videots;
455     NSString *o_mrl_string;
456     int i_title, i_chapter;
457     vlc_bool_t b_menus;
458
459     o_type = [[o_disc_type selectedCell] title];
460     o_device = [o_disc_device stringValue];
461     i_title = [o_disc_title intValue];
462     i_chapter = [o_disc_chapter intValue];
463     o_videots = [o_disc_videots_folder stringValue];
464     b_menus = [o_disc_dvd_menus state];
465
466     if ( [o_type isEqualToString: _NS("VCD")] )
467     {
468         if ( [o_device isEqualToString:
469                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
470             o_device = @"";
471         o_mrl_string = [NSString stringWithFormat: @"vcd://%@@%i,%i",
472                         o_device, i_title, i_chapter]; 
473     }
474     else if ( [o_type isEqualToString: _NS("DVD")] )
475     {
476         if ( [o_device isEqualToString:
477                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
478             o_device = @"";
479         if ( b_menus )
480             o_mrl_string = [NSString stringWithFormat: @"dvdplay://%@",
481                             o_device]; 
482         else
483             o_mrl_string = [NSString stringWithFormat: @"dvdold://%@@%i,%i",
484                             o_device, i_title, i_chapter]; 
485     }
486     else /* VIDEO_TS folder */
487     {
488         if ( b_menus )
489             o_mrl_string = [NSString stringWithFormat: @"dvdplay://%@",
490                             o_videots]; 
491         else
492             o_mrl_string = [NSString stringWithFormat: @"dvdread://%@@%i,%i",
493                             o_videots, i_title, i_chapter]; 
494     }
495
496     [o_mrl setStringValue: o_mrl_string]; 
497 }
498
499 - (IBAction)openDiscMenusChanged:(id)sender
500 {
501     [self openDiscInfoChanged: nil];
502     [self openDiscTypeChanged: nil];
503 }
504
505 - (IBAction)openVTSBrowse:(id)sender
506 {
507     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
508
509     [o_open_panel setAllowsMultipleSelection: NO];
510     [o_open_panel setCanChooseFiles: NO];
511     [o_open_panel setCanChooseDirectories: YES];
512     [o_open_panel setTitle: _NS("Open VIDEO_TS Directory")];
513     [o_open_panel setPrompt: _NS("Open")];
514
515     if( [o_open_panel runModalForDirectory: nil
516             file: nil types: nil] == NSOKButton )
517     {
518         NSString *o_dirname = [[o_open_panel filenames] objectAtIndex: 0];
519         [o_disc_videots_folder setStringValue: o_dirname];
520         [self openDiscInfoChanged: nil];
521     }
522 }
523
524 - (IBAction)openNetModeChanged:(id)sender
525 {
526     NSString *o_mode;
527     BOOL b_udp = FALSE;
528     BOOL b_udpm = FALSE;
529     BOOL b_http = FALSE;
530
531     o_mode = [[o_net_mode selectedCell] title];
532
533     if( [o_mode isEqualToString: _NS("UDP/RTP")] ) b_udp = TRUE;   
534     else if( [o_mode isEqualToString: _NS("UDP/RTP Multicast")] ) b_udpm = TRUE;
535     else if( [o_mode isEqualToString: _NS("HTTP/FTP/MMS")] ) b_http = TRUE;
536
537     [o_net_udp_port setEnabled: b_udp];
538     [o_net_udp_port_stp setEnabled: b_udp];
539     [o_net_udpm_addr setEnabled: b_udpm];
540     [o_net_udpm_port setEnabled: b_udpm];
541     [o_net_udpm_port_stp setEnabled: b_udpm];
542     [o_net_http_url setEnabled: b_http];
543
544     [self openNetInfoChanged: nil];
545 }
546
547 - (IBAction)openNetStepperChanged:(id)sender
548 {
549     int i_tag = [sender tag];
550
551     if( i_tag == 0 )
552     {
553         [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
554     }
555     else if( i_tag == 1 )
556     {
557         [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
558     }
559
560     [self openNetInfoChanged: nil];
561 }
562
563 - (void)openNetInfoChanged:(NSNotification *)o_notification
564 {
565     NSString *o_mode;
566     NSString *o_mrl_string = [NSString string];
567     intf_thread_t * p_intf = [NSApp getIntf];
568
569     o_mode = [[o_net_mode selectedCell] title];
570
571     if( [o_mode isEqualToString: _NS("UDP/RTP")] )
572     {
573         int i_port = [o_net_udp_port intValue];
574
575         o_mrl_string = [NSString stringWithString: @"udp://"]; 
576
577         if( i_port != config_GetInt( p_intf, "server-port" ) )
578         {
579             o_mrl_string = 
580                 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port]; 
581         } 
582     }
583     else if( [o_mode isEqualToString: _NS("UDP/RTP Multicast")] ) 
584     {
585         NSString *o_addr = [o_net_udpm_addr stringValue];
586         int i_port = [o_net_udpm_port intValue];
587
588         o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr]; 
589
590         if( i_port != config_GetInt( p_intf, "server-port" ) )
591         {
592             o_mrl_string = 
593                 [o_mrl_string stringByAppendingFormat: @":%i", i_port]; 
594         } 
595     }
596     else if( [o_mode isEqualToString: _NS("HTTP/FTP/MMS")] )
597     {
598         NSString *o_url = [o_net_http_url stringValue];
599
600         if ( ![o_url hasPrefix:@"http:"] && ![o_url hasPrefix:@"ftp:"]
601               && ![o_url hasPrefix:@"mms"] )
602             o_mrl_string = [NSString stringWithFormat: @"http://%@", o_url];
603         else
604             o_mrl_string = o_url;
605     }
606
607     [o_mrl setStringValue: o_mrl_string];
608 }
609
610 - (IBAction)openFile:(id)sender
611 {
612     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
613     
614     [o_open_panel setAllowsMultipleSelection: YES];
615     [o_open_panel setCanChooseDirectories: YES];
616     [o_open_panel setTitle: _NS("Open File")];
617     [o_open_panel setPrompt: _NS("Open")];
618     
619     if( [o_open_panel runModalForDirectory: nil
620             file: nil types: nil] == NSOKButton )
621     {
622         intf_thread_t * p_intf = [NSApp getIntf];
623         config_PutPsz( p_intf, "sout", NULL );
624         
625         NSArray *o_values = [[o_open_panel filenames]
626                 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
627         
628         [o_playlist appendArray: o_values atPos: -1 enqueue:NO];
629         config_PutPsz( p_intf, "sub-file", "" );
630         config_PutInt( p_intf, "sub-delay", 0 );
631         config_PutFloat( p_intf, "sub-fps", 0.0 );
632         config_PutPsz( p_intf, "sout", "" );
633     }
634 }
635
636 - (IBAction)subsChanged:(id)sender
637 {
638     if ([o_file_sub_ckbox state] == NSOnState)
639     {
640         [o_file_sub_btn_settings setEnabled:YES];
641     }
642     else
643     {
644         [o_file_sub_btn_settings setEnabled:NO];
645     }
646 }
647
648 - (IBAction)subSettings:(id)sender
649 {
650     [NSApp beginSheet: o_file_sub_sheet
651         modalForWindow: [sender window]
652         modalDelegate: self
653         didEndSelector: NULL
654         contextInfo: nil];
655 }
656
657 - (IBAction)subFileBrowse:(id)sender
658 {
659     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
660     
661     [o_open_panel setAllowsMultipleSelection: NO];
662     [o_open_panel setTitle: _NS("Open File")];
663     [o_open_panel setPrompt: _NS("Open")];
664
665     if( [o_open_panel runModalForDirectory: nil 
666             file: nil types: nil] == NSOKButton )
667     {
668         NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
669         [o_file_sub_path setStringValue: o_filename];
670     }
671 }
672
673 - (IBAction)subOverride:(id)sender
674 {
675     BOOL b_state = [o_file_sub_override state];
676     [o_file_sub_delay setEnabled: b_state];
677     [o_file_sub_delay_stp setEnabled: b_state];
678     [o_file_sub_fps setEnabled: b_state];
679     [o_file_sub_fps_stp setEnabled: b_state];
680 }
681
682 - (IBAction)subDelayStepperChanged:(id)sender
683 {
684     [o_file_sub_delay setIntValue: [o_file_sub_delay_stp intValue]];
685 }
686
687 - (IBAction)subFpsStepperChanged:(id)sender;
688 {
689     [o_file_sub_fps setFloatValue: [o_file_sub_fps_stp floatValue]];
690 }
691
692 - (IBAction)subCloseSheet:(id)sender
693 {
694     [o_file_sub_sheet orderOut:sender];
695     [NSApp endSheet: o_file_sub_sheet];
696 }
697
698 - (IBAction)panelCancel:(id)sender
699 {
700     [NSApp stopModalWithCode: 0];
701 }
702
703 - (IBAction)panelOk:(id)sender
704 {
705     if( [[o_mrl stringValue] length] )
706     {
707         [NSApp stopModalWithCode: 1];
708     }
709     else
710     {
711         NSBeep();
712     }
713 }
714
715 @end