]> git.sesse.net Git - vlc/blob - modules/gui/macosx/open.m
macosx: fix auto play when adding a new file with file dialogs
[vlc] / modules / gui / macosx / open.m
1 /*****************************************************************************
2  * open.m: Open dialogues for VLC's MacOS X port
3  *****************************************************************************
4  * Copyright (C) 2002-2012 VLC authors and VideoLAN
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 #import <stdlib.h>                                      /* malloc(), free() */
32 #import <sys/param.h>                                    /* for MAXPATHLEN */
33
34 #import "CompatibilityFixes.h"
35
36 #import <paths.h>
37 #import <IOKit/IOBSD.h>
38 #import <IOKit/storage/IOMedia.h>
39 #import <IOKit/storage/IOCDMedia.h>
40 #import <IOKit/storage/IODVDMedia.h>
41 #import <IOKit/storage/IOBDMedia.h>
42 #import <Cocoa/Cocoa.h>
43 #import <QTKit/QTKit.h>
44
45 #import "intf.h"
46 #import "playlist.h"
47 #import "open.h"
48 #import "output.h"
49 #import "eyetv.h"
50
51 #import <vlc_url.h>
52
53 NSArray               *qtkvideoDevices;
54 #define setEyeTVUnconnected \
55 [o_capture_lbl setStringValue: _NS("No device is selected")]; \
56 [o_capture_long_lbl setStringValue: _NS("No device is selected.\n\nChoose available device in above pull-down menu\n.")]; \
57 [o_capture_lbl displayIfNeeded]; \
58 [o_capture_long_lbl displayIfNeeded]; \
59 [self showCaptureView: o_capture_label_view]
60
61 #define kVLCMediaAudioCD "AudioCD"
62 #define kVLCMediaDVD "DVD"
63 #define kVLCMediaVCD "VCD"
64 #define kVLCMediaSVCD "SVCD"
65 #define kVLCMediaBD "Bluray"
66 #define kVLCMediaVideoTSFolder "VIDEO_TS"
67 #define kVLCMediaBDMVFolder "BDMV"
68 #define kVLCMediaUnknown "Unknown"
69
70
71 /*****************************************************************************
72  * VLCOpen implementation
73  *****************************************************************************/
74 @implementation VLCOpen
75
76 static VLCOpen *_o_sharedMainInstance = nil;
77
78 + (VLCOpen *)sharedInstance
79 {
80     return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
81 }
82
83 - (id)init
84 {
85     if( _o_sharedMainInstance) {
86         [self dealloc];
87     } else {
88         _o_sharedMainInstance = [super init];
89         p_intf = VLCIntf;
90     }
91  
92     return _o_sharedMainInstance;
93 }
94
95 - (void)dealloc
96 {
97     [o_specialMediaFolders release];
98     [o_opticalDevices release];
99     if( o_file_slave_path )
100         [o_file_slave_path release];
101     [o_mrl release];
102     if (o_sub_path)
103         [o_sub_path release];
104     [o_currentOpticalMediaIconView release];
105     [o_currentOpticalMediaView release];
106     [super dealloc];
107 }
108
109 - (void)awakeFromNib
110 {
111     if (OSX_LION)
112         [o_panel setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
113
114     [o_panel setTitle: _NS("Open Source")];
115     [o_mrl_lbl setStringValue: _NS("Media Resource Locator (MRL)")];
116
117     [o_btn_ok setTitle: _NS("Open")];
118     [o_btn_cancel setTitle: _NS("Cancel")];
119
120     [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
121     [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
122     [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
123     [[o_tabview tabViewItemAtIndex: 3] setLabel: _NS("Capture")];
124
125     [o_file_name setStringValue: @""];
126     [o_file_name_stub setStringValue: _NS("Choose a file")];
127     [o_file_icon_well setImage: [NSImage imageNamed:@"generic"]];
128     [o_file_btn_browse setTitle: _NS("Browse...")];
129     [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
130     [o_file_stream setHidden: NO];
131     [o_file_slave_ckbox setTitle: _NS("Play another media synchronously")];
132     [o_file_slave_select_btn setTitle: _NS("Choose...")];
133     [o_file_slave_filename_lbl setStringValue: @""];
134     [o_file_slave_icon_well setImage: NULL];
135     [o_file_subtitles_filename_lbl setStringValue: @""];
136     [o_file_subtitles_icon_well setImage: NULL];
137
138     [o_disc_selector_pop removeAllItems];
139     [o_disc_selector_pop setHidden: NO];
140     NSString *o_videots = _NS("Open VIDEO_TS folder");
141     NSString *o_bdmv = _NS("Open BDMV folder");
142     [o_disc_nodisc_lbl setStringValue: _NS("Insert Disc")];
143     [o_disc_nodisc_videots_btn setTitle: o_videots];
144     [o_disc_nodisc_bdmv_btn setTitle: o_bdmv];
145     [o_disc_audiocd_lbl setStringValue: _NS("Audio CD")];
146     [o_disc_audiocd_trackcount_lbl setStringValue: @""];
147     [o_disc_audiocd_videots_btn setTitle: o_videots];
148     [o_disc_audiocd_bdmv_btn setTitle: o_bdmv];
149     [o_disc_dvd_lbl setStringValue: @""];
150     [o_disc_dvd_disablemenus_btn setTitle: _NS("Disable DVD menus")];
151     [o_disc_dvd_videots_btn setTitle: o_videots];
152     [o_disc_dvd_bdmv_btn setTitle: o_bdmv];
153     [o_disc_dvdwomenus_lbl setStringValue: @""];
154     [o_disc_dvdwomenus_enablemenus_btn setTitle: _NS("Enable DVD menus")];
155     [o_disc_dvdwomenus_videots_btn setTitle: o_videots];
156     [o_disc_dvdwomenus_bdmv_btn setTitle: o_bdmv];
157     [o_disc_dvdwomenus_title_lbl setStringValue: _NS("Title")];
158     [o_disc_dvdwomenus_chapter_lbl setStringValue: _NS("Chapter")];
159     [o_disc_vcd_title_lbl setStringValue: _NS("Title")];
160     [o_disc_vcd_chapter_lbl setStringValue: _NS("Chapter")];
161     [o_disc_vcd_videots_btn setTitle: o_videots];
162     [o_disc_vcd_bdmv_btn setTitle: o_bdmv];
163     [o_disc_bd_videots_btn setTitle: o_videots];
164     [o_disc_bd_bdmv_btn setTitle: o_bdmv];
165
166     [o_net_udp_port_lbl setStringValue: _NS("Port")];
167     [o_net_udpm_addr_lbl setStringValue: _NS("IP Address")];
168     [o_net_udpm_port_lbl setStringValue: _NS("Port")];
169     [o_net_http_url_lbl setStringValue: _NS("URL")];
170     [o_net_help_lbl setStringValue: _NS("To Open a usual network stream (HTTP, RTSP, RTMP, 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.")];
171     [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.")];
172     [o_net_udp_cancel_btn setTitle: _NS("Cancel")];
173     [o_net_udp_ok_btn setTitle: _NS("Open")];
174     [o_net_openUDP_btn setTitle: _NS("Open RTP/UDP Stream")];
175     [o_net_udp_mode_lbl setStringValue: _NS("Mode")];
176     [o_net_udp_protocol_lbl setStringValue: _NS("Protocol")];
177     [o_net_udp_address_lbl setStringValue: _NS("Address")];
178
179     [[o_net_mode cellAtRow:0 column:0] setTitle: _NS("Unicast")];
180     [[o_net_mode cellAtRow:1 column:0] setTitle: _NS("Multicast")];
181
182     [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
183     [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
184
185     [o_eyetv_chn_bgbar setUsesThreadedAnimation: YES];
186
187     [o_capture_mode_pop removeAllItems];
188     [o_capture_mode_pop addItemWithTitle: _NS("Capture Device")];
189         // our screen capture module isn't Lion-compatible, so let's hide it from the user if needed (trac #4799)
190         if( NSAppKitVersionNumber < 1115.2 )
191                 [o_capture_mode_pop addItemWithTitle: _NS("Screen")];
192     [o_capture_mode_pop addItemWithTitle: @"EyeTV"];
193     [o_screen_long_lbl setStringValue: _NS("This input allows you to save, stream or display your current screen contents.")];
194     [o_screen_fps_lbl setStringValue: _NS("Frames per Second:")];
195     [o_screen_left_lbl setStringValue: _NS("Subscreen left:")];
196     [o_screen_top_lbl setStringValue: _NS("Subscreen top:")];
197     [o_screen_width_lbl setStringValue: _NS("Subscreen width:")];
198     [o_screen_height_lbl setStringValue: _NS("Subscreen height:")];
199     [o_screen_follow_mouse_ckb setTitle: _NS("Follow the mouse")];
200     [o_eyetv_currentChannel_lbl setStringValue: _NS("Current channel:")];
201     [o_eyetv_previousProgram_btn setTitle: _NS("Previous Channel")];
202     [o_eyetv_nextProgram_btn setTitle: _NS("Next Channel")];
203     [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
204     [o_eyetv_noInstance_lbl setStringValue: _NS("EyeTV is not launched")];
205     [o_eyetv_noInstanceLong_lbl setStringValue: _NS("VLC could not connect to EyeTV.\nMake sure that you installed VLC's EyeTV plugin.")];
206     [o_eyetv_launchEyeTV_btn setTitle: _NS("Launch EyeTV now")];
207     [o_eyetv_getPlugin_btn setTitle: _NS("Download Plugin")];
208     [o_qtk_long_lbl setStringValue: _NS("This input allows you to process input signals from QuickTime-compatible video devices.\nLive Audio input is not supported.")];
209     [o_capture_width_lbl setStringValue: _NS("Image width:")];
210     [o_capture_height_lbl setStringValue: _NS("Image height:")];
211
212     [self qtkvideoDevices];
213     [o_qtk_device_pop removeAllItems];
214     msg_Dbg( VLCIntf, "Found %lu capture devices", [qtkvideoDevices count] );
215         if([qtkvideoDevices count] >= 1)
216                 {
217         if (!qtk_currdevice_uid) {
218             qtk_currdevice_uid = [[[QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeVideo] uniqueID]
219                                                                 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
220         }
221         NSUInteger deviceCount = [qtkvideoDevices count];
222         for(int ivideo = 0; ivideo < deviceCount; ivideo++){
223             QTCaptureDevice *qtk_device;
224             qtk_device = [qtkvideoDevices objectAtIndex:ivideo];
225             [o_qtk_device_pop addItemWithTitle: [qtk_device localizedDisplayName]];
226             if([[[qtk_device uniqueID]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:qtk_currdevice_uid]){
227                 [o_qtk_device_pop selectItemAtIndex:ivideo];
228             }
229         }
230     }
231         else
232         {
233                 [o_qtk_device_pop addItemWithTitle: _NS("None")];
234         [qtk_currdevice_uid release];
235         }
236
237
238     [self setSubPanel];
239
240     [[NSNotificationCenter defaultCenter] addObserver: self
241         selector: @selector(openNetInfoChanged:)
242         name: NSControlTextDidChangeNotification
243         object: o_net_udp_port];
244     [[NSNotificationCenter defaultCenter] addObserver: self
245         selector: @selector(openNetInfoChanged:)
246         name: NSControlTextDidChangeNotification
247         object: o_net_udpm_addr];
248     [[NSNotificationCenter defaultCenter] addObserver: self
249         selector: @selector(openNetInfoChanged:)
250         name: NSControlTextDidChangeNotification
251         object: o_net_udpm_port];
252     [[NSNotificationCenter defaultCenter] addObserver: self
253         selector: @selector(openNetInfoChanged:)
254         name: NSControlTextDidChangeNotification
255         object: o_net_http_url];
256
257     [[NSDistributedNotificationCenter defaultCenter] addObserver: self
258                                                         selector: @selector(eyetvChanged:)
259                                                             name: NULL
260                                                           object: @"VLCEyeTVSupport"
261                                               suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
262
263     [[NSNotificationCenter defaultCenter] addObserver: self
264                                              selector: @selector(screenFPSfieldChanged:)
265                                                  name: NSControlTextDidChangeNotification
266                                                object: o_screen_fps_fld];
267
268     /* register clicks on text fields */
269     [[NSNotificationCenter defaultCenter] addObserver: self
270                                              selector: @selector(textFieldWasClicked:)
271                                                  name: @"VLCOpenTextFieldWasClicked"
272                                                object: nil];
273
274     /* we want to be notified about removed or added media */
275     o_specialMediaFolders = [[NSMutableArray alloc] init];
276     o_opticalDevices = [[NSMutableArray alloc] init];
277     NSWorkspace *sharedWorkspace = [NSWorkspace sharedWorkspace];
278         [[sharedWorkspace notificationCenter] addObserver:self selector:@selector(scanOpticalMedia:) name:NSWorkspaceDidMountNotification object:nil];
279         [[sharedWorkspace notificationCenter] addObserver:self selector:@selector(scanOpticalMedia:) name:NSWorkspaceDidUnmountNotification object:nil];
280     [self scanOpticalMedia:nil];
281
282     [self setMRL: @""];
283 }
284
285 - (void)setMRL:(NSString *)newMRL
286 {
287     [o_mrl release];
288     o_mrl = newMRL;
289     [o_mrl retain];
290     [o_mrl_fld setStringValue: newMRL];
291     if ([o_mrl length] > 0)
292         [o_btn_ok setEnabled: YES];
293     else
294         [o_btn_ok setEnabled: NO];
295 }
296
297 - (NSString *)MRL
298 {
299     return o_mrl;
300 }
301
302 - (void)setSubPanel
303 {
304     int i_index;
305     module_config_t * p_item;
306
307     [o_file_sub_ckbox setTitle: _NS("Load subtitles file:")];
308     [o_file_sub_path_lbl setStringValue: _NS("Choose a file")];
309     [o_file_sub_path_lbl setHidden: NO];
310     [o_file_sub_path_fld setStringValue: @""];
311     [o_file_sub_btn_settings setTitle: _NS("Choose...")];
312     [o_file_sub_btn_browse setTitle: _NS("Browse...")];
313     [o_file_sub_override setTitle: _NS("Override parameters")];
314     [o_file_sub_delay_lbl setStringValue: _NS("Delay")];
315     [o_file_sub_delay_stp setEnabled: NO];
316     [o_file_sub_fps_lbl setStringValue: _NS("FPS")];
317     [o_file_sub_fps_stp setEnabled: NO];
318     [o_file_sub_encoding_lbl setStringValue: _NS("Subtitles encoding")];
319     [o_file_sub_encoding_pop removeAllItems];
320     [o_file_sub_size_lbl setStringValue: _NS("Font size")];
321     [o_file_sub_size_pop removeAllItems];
322     [o_file_sub_align_lbl setStringValue: _NS("Subtitles alignment")];
323     [o_file_sub_align_pop removeAllItems];
324     [o_file_sub_ok_btn setStringValue: _NS("OK")];
325     [o_file_sub_font_box setTitle: _NS("Font Properties")];
326     [o_file_sub_file_box setTitle: _NS("Subtitle File")];
327
328     p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-encoding" );
329
330     if( p_item )
331     {
332         for( i_index = 0; p_item->ppsz_list && p_item->ppsz_list[i_index];
333              i_index++ )
334         {
335             [o_file_sub_encoding_pop addItemWithTitle:
336                 [NSString stringWithUTF8String: p_item->ppsz_list[i_index]]];
337         }
338         [o_file_sub_encoding_pop selectItemWithTitle:
339                 [NSString stringWithUTF8String: p_item->value.psz]];
340     }
341
342     p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-align" );
343
344     if ( p_item )
345     {
346         for ( i_index = 0; i_index < p_item->i_list; i_index++ )
347         {
348             [o_file_sub_align_pop addItemWithTitle:
349                 [NSString stringWithUTF8String:
350                 p_item->ppsz_list_text[i_index]]];
351         }
352         [o_file_sub_align_pop selectItemAtIndex: p_item->value.i];
353     }
354
355     p_item = config_FindConfig( VLC_OBJECT(p_intf), "freetype-rel-fontsize" );
356
357     if ( p_item )
358     {
359         for ( i_index = 0; i_index < p_item->i_list; i_index++ )
360         {
361             [o_file_sub_size_pop addItemWithTitle:
362                 [NSString stringWithUTF8String:
363                 p_item->ppsz_list_text[i_index]]];
364             if ( p_item->value.i == p_item->pi_list[i_index] )
365             {
366                 [o_file_sub_size_pop selectItemAtIndex: i_index];
367             }
368         }
369     }
370 }
371
372 - (void)openTarget:(int)i_type
373 {
374     int i_result;
375
376     b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
377
378     [o_tabview selectTabViewItemAtIndex: i_type];
379     [o_file_sub_ckbox setState: NSOffState];
380  
381     i_result = [NSApp runModalForWindow: o_panel];
382     [o_panel close];
383
384     if( i_result )
385     {
386         NSMutableDictionary *o_dic;
387         NSMutableArray *o_options = [NSMutableArray array];
388
389         o_dic = [NSMutableDictionary dictionaryWithObject: [self MRL] forKey: @"ITEM_URL"];
390         if( [o_file_sub_ckbox state] == NSOnState )
391         {
392             module_config_t * p_item;
393
394             [o_options addObject: [NSString stringWithFormat: @"sub-file=%@", o_sub_path]];
395             if( [o_file_sub_override state] == NSOnState )
396             {
397                 [o_options addObject: [NSString stringWithFormat: @"sub-delay=%i", (int)( [o_file_sub_delay intValue] * 10 )]];
398                 [o_options addObject: [NSString stringWithFormat: @"sub-fps=%f", [o_file_sub_fps floatValue]]];
399             }
400             [o_options addObject: [NSString stringWithFormat:
401                     @"subsdec-encoding=%@",
402                     [o_file_sub_encoding_pop titleOfSelectedItem]]];
403             [o_options addObject: [NSString stringWithFormat:
404                     @"subsdec-align=%i",
405                     [o_file_sub_align_pop indexOfSelectedItem]]];
406
407             p_item = config_FindConfig( VLC_OBJECT(p_intf),
408                                             "freetype-rel-fontsize" );
409
410             if ( p_item )
411             {
412                 [o_options addObject: [NSString stringWithFormat:
413                     @"freetype-rel-fontsize=%i",
414                     p_item->pi_list[[o_file_sub_size_pop indexOfSelectedItem]]]];
415             }
416         }
417         if( [o_output_ckbox state] == NSOnState )
418         {
419             NSUInteger count = [[o_sout_options mrl] count];
420             for (NSUInteger i = 0 ; i < count ; i++)
421             {
422                 [o_options addObject: [NSString stringWithString: [[(VLCOutput *)o_sout_options mrl] objectAtIndex: i]]];
423             }
424         }
425         if( [o_file_slave_ckbox state] && o_file_slave_path )
426            [o_options addObject: [NSString stringWithFormat: @"input-slave=%@", o_file_slave_path]];
427         if( [[[o_tabview selectedTabViewItem] label] isEqualToString: _NS("Capture")] )
428         {
429             if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
430             {
431                 [o_options addObject: [NSString stringWithFormat: @"screen-fps=%f", [o_screen_fps_fld floatValue]]];
432                 [o_options addObject: [NSString stringWithFormat: @"screen-left=%i", [o_screen_left_fld intValue]]];
433                 [o_options addObject: [NSString stringWithFormat: @"screen-top=%i", [o_screen_top_fld intValue]]];
434                 [o_options addObject: [NSString stringWithFormat: @"screen-width=%i", [o_screen_width_fld intValue]]];
435                 [o_options addObject: [NSString stringWithFormat: @"screen-height=%i", [o_screen_height_fld intValue]]];
436                 if( [o_screen_follow_mouse_ckb intValue] == YES )
437                     [o_options addObject: @"screen-follow-mouse"];
438                 else
439                     [o_options addObject: @"no-screen-follow-mouse"];
440             }
441             else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Capture Device")] )
442             {
443                 [o_options addObject: [NSString stringWithFormat: @"qtcapture-width=%i", [o_capture_width_fld intValue]]];
444                 [o_options addObject: [NSString stringWithFormat: @"qtcapture-height=%i", [o_capture_height_fld intValue]]];
445             }
446         }
447
448         /* apply the options to our item(s) */
449         [o_dic setObject: (NSArray *)[o_options copy] forKey: @"ITEM_OPTIONS"];
450         if( b_autoplay )
451             [[[VLCMain sharedInstance] playlist] appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:NO];
452         else
453             [[[VLCMain sharedInstance] playlist] appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:YES];
454     }
455 }
456
457 - (IBAction)qtkChanged:(id)sender
458 {
459         NSInteger i_selectedDevice = [o_qtk_device_pop indexOfSelectedItem];
460         if (i_selectedDevice > ([qtkvideoDevices count] - 1))
461         {
462                 NSValue *sizes = [[[[qtkvideoDevices objectAtIndex:i_selectedDevice] formatDescriptions] objectAtIndex: 0] attributeForKey: QTFormatDescriptionVideoEncodedPixelsSizeAttribute];
463
464                 [o_capture_width_fld setIntValue: [sizes sizeValue].width];
465                 [o_capture_height_fld setIntValue: [sizes sizeValue].height];
466                 [o_capture_width_stp setIntValue: [o_capture_width_fld intValue]];
467                 [o_capture_height_stp setIntValue: [o_capture_height_fld intValue]];
468                 qtk_currdevice_uid = [[(QTCaptureDevice *)[qtkvideoDevices objectAtIndex:i_selectedDevice] uniqueID]
469                                                           stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
470                 [self setMRL:[NSString stringWithFormat:@"qtcapture://%@", qtk_currdevice_uid]];
471         }
472 }
473
474 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
475 {
476     NSString *o_label = [o_tvi label];
477
478     if( [o_label isEqualToString: _NS("File")] )
479     {
480         [self openFilePathChanged: nil];
481     }
482     else if( [o_label isEqualToString: _NS("Disc")] )
483     {
484         [self scanOpticalMedia: nil];
485     }
486     else if( [o_label isEqualToString: _NS("Network")] )
487     {
488         [self openNetInfoChanged: nil];
489     }
490     else if( [o_label isEqualToString: _NS("Capture")] )
491     {
492         [self openCaptureModeChanged: nil];
493     }
494 }
495
496 - (IBAction)expandMRLfieldAction:(id)sender
497 {
498     NSRect o_win_rect, o_view_rect;
499     o_win_rect = [o_panel frame];
500     o_view_rect = [o_mrl_view frame];
501
502     if( [o_mrl_btn state] == NSOffState )
503     {
504         /* we need to collaps, restore the panel size */
505         o_win_rect.size.height = o_win_rect.size.height - o_view_rect.size.height;
506         o_win_rect.origin.y = ( o_win_rect.origin.y + o_view_rect.size.height ) - o_view_rect.size.height;
507
508         /* remove the MRL view */
509         [o_mrl_view removeFromSuperview];
510     } else {
511         /* we need to expand */
512         [o_mrl_view setFrame: NSMakeRect( 0,
513                                          [o_mrl_btn frame].origin.y,
514                                          o_view_rect.size.width,
515                                          o_view_rect.size.height )];
516         [o_mrl_view setNeedsDisplay: NO];
517         [o_mrl_view setAutoresizesSubviews: YES];
518
519         /* enlarge panel size for MRL view */
520         o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
521     }
522
523     [[o_panel animator] setFrame: o_win_rect display:YES];
524 //    [o_panel displayIfNeeded];
525     if( [o_mrl_btn state] == NSOnState )
526         [[o_panel contentView] addSubview: o_mrl_view];
527 }
528
529 - (IBAction)inputSlaveAction:(id)sender
530 {
531     if( sender == o_file_slave_ckbox )
532         [o_file_slave_select_btn setEnabled: [o_file_slave_ckbox state]];
533     else
534     {
535         NSOpenPanel *o_open_panel;
536         o_open_panel = [NSOpenPanel openPanel];
537         [o_open_panel setCanChooseFiles: YES];
538         [o_open_panel setCanChooseDirectories: NO];
539         if( [o_open_panel runModal] == NSOKButton )
540         {
541             if( o_file_slave_path )
542                 [o_file_slave_path release];
543             o_file_slave_path = [[[o_open_panel URLs] objectAtIndex: 0] path];
544             [o_file_slave_path retain];
545         }
546     }
547     if( o_file_slave_path && [o_file_slave_ckbox state] == NSOnState)
548     {
549         [o_file_slave_filename_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_file_slave_path]];
550         [o_file_slave_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: o_file_slave_path]];
551     }
552     else
553     {
554         [o_file_slave_filename_lbl setStringValue: @""];
555         [o_file_slave_icon_well setImage: NULL];
556     }
557 }
558
559 - (void)openFileGeneric
560 {
561     [self openFilePathChanged: nil];
562     [self openTarget: 0];
563 }
564
565 - (void)openDisc
566 {
567     [o_specialMediaFolders removeAllObjects];
568     [o_opticalDevices removeAllObjects];
569     [self scanOpticalMedia: nil];
570     [self openTarget: 1];
571 }
572
573 - (void)openNet
574 {
575     [self openNetInfoChanged: nil];
576     [self openTarget: 2];
577 }
578
579 - (void)openCapture
580 {
581     [self openCaptureModeChanged: nil];
582     [self openTarget: 3];
583 }
584
585 - (void)openFilePathChanged:(NSNotification *)o_notification
586 {
587     if ( o_file_path && [o_file_path length] > 0 )
588     {
589         bool b_stream = [o_file_stream state];
590         BOOL b_dir = NO;
591
592         [[NSFileManager defaultManager] fileExistsAtPath:o_file_path isDirectory:&b_dir];
593
594         char *psz_uri = make_URI([o_file_path UTF8String], "file");
595         if( !psz_uri ) return;
596
597         NSMutableString *o_mrl_string = [NSMutableString stringWithUTF8String: psz_uri ];
598         NSRange offile = [o_mrl_string rangeOfString:@"file"];
599         free( psz_uri );
600
601         if( b_dir )
602             [o_mrl_string replaceCharactersInRange:offile withString: @"directory"];
603         else if( b_stream )
604             [o_mrl_string replaceCharactersInRange:offile withString: @"stream"];
605
606         [o_file_name setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_file_path]];
607         [o_file_name_stub setHidden: YES];
608         [o_file_stream setHidden: NO];
609         [o_file_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: o_file_path]];
610         [o_file_icon_well setHidden: NO];
611         [self setMRL: o_mrl_string];
612     }
613     else
614     {
615         [o_file_name setStringValue: @""];
616         [o_file_name_stub setHidden: NO];
617         [o_file_stream setHidden: YES];
618         [o_file_icon_well setImage: [NSImage imageNamed:@"generic"]];
619         [self setMRL: @""];
620     }
621 }
622
623 - (IBAction)openFileBrowse:(id)sender
624 {
625     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
626  
627     [o_open_panel setAllowsMultipleSelection: NO];
628     [o_open_panel setCanChooseDirectories: YES];
629     [o_open_panel setTitle: _NS("Open File")];
630     [o_open_panel setPrompt: _NS("Open")];
631
632     [o_open_panel beginSheetForDirectory:nil
633         file:nil
634         types:nil
635         modalForWindow:[sender window]
636         modalDelegate: self
637         didEndSelector: @selector(pathChosenInPanel:
638                         withReturn:
639                         contextInfo:)
640         contextInfo: nil];
641 }
642
643 - (void)pathChosenInPanel: (NSOpenPanel *) sheet withReturn:(int)returnCode contextInfo:(void  *)contextInfo
644 {
645     if (returnCode == NSFileHandlingPanelOKButton)
646     {
647         if( o_file_path )
648             [o_file_path release];
649         o_file_path = [[[sheet URLs] objectAtIndex: 0] path];
650         [o_file_path retain];
651         [self openFilePathChanged: nil];
652     }
653 }
654
655 - (IBAction)openFileStreamChanged:(id)sender
656 {
657     [self openFilePathChanged: nil];
658 }
659
660 - (void)showOpticalMediaView: theView withIcon:(NSImage *)icon
661 {
662     NSRect o_view_rect;
663     o_view_rect = [theView frame];
664     [theView setFrame: NSMakeRect( 233, 0, o_view_rect.size.width, o_view_rect.size.height)];
665     [theView setAutoresizesSubviews: YES];
666     if (o_currentOpticalMediaView)
667     {
668         [[[[o_tabview tabViewItemAtIndex: [o_tabview indexOfTabViewItemWithIdentifier:@"optical"]] view] animator] replaceSubview: o_currentOpticalMediaView with: theView];
669         [o_currentOpticalMediaView release];
670     }
671     else
672         [[[[o_tabview tabViewItemAtIndex: [o_tabview indexOfTabViewItemWithIdentifier:@"optical"]] view] animator] addSubview: theView];
673     o_currentOpticalMediaView = theView;
674     [o_currentOpticalMediaView retain];
675
676     NSImageView *imageView;
677     imageView = [[NSImageView alloc] init];
678     [imageView setFrame: NSMakeRect( 53, 61, 128, 128 )];
679     [icon setSize: NSMakeSize(128,128)];
680     [imageView setImage: icon];
681     if (o_currentOpticalMediaIconView)
682     {
683         [[[[o_tabview tabViewItemAtIndex: [o_tabview indexOfTabViewItemWithIdentifier:@"optical"]] view] animator] replaceSubview: o_currentOpticalMediaIconView with: imageView];
684         [o_currentOpticalMediaIconView release];
685     }
686     else
687          [[[[o_tabview tabViewItemAtIndex: [o_tabview indexOfTabViewItemWithIdentifier:@"optical"]] view] animator] addSubview: imageView];
688     o_currentOpticalMediaIconView = imageView;
689     [o_currentOpticalMediaIconView retain];
690     [o_currentOpticalMediaView setNeedsDisplay: YES];
691     [o_currentOpticalMediaIconView setNeedsDisplay: YES];
692     [[[o_tabview tabViewItemAtIndex: [o_tabview indexOfTabViewItemWithIdentifier:@"optical"]] view] setNeedsDisplay: YES];
693     [[[o_tabview tabViewItemAtIndex: [o_tabview indexOfTabViewItemWithIdentifier:@"optical"]] view] displayIfNeeded];
694 }
695
696 - (NSString *) getBSDNodeFromMountPath:(NSString *)mountPath
697 {
698     OSStatus err;
699     FSRef ref;
700     FSVolumeRefNum actualVolume;
701     err = FSPathMakeRef ( (const UInt8 *) [mountPath fileSystemRepresentation], &ref, NULL );
702
703     // get a FSVolumeRefNum from mountPath
704     if ( noErr == err ) {
705         FSCatalogInfo   catalogInfo;
706         err = FSGetCatalogInfo ( &ref,
707                                 kFSCatInfoVolume,
708                                 &catalogInfo,
709                                 NULL,
710                                 NULL,
711                                 NULL
712                                 );
713         if ( noErr == err ) {
714             actualVolume = catalogInfo.volume;
715         }
716     }
717
718     GetVolParmsInfoBuffer volumeParms;
719     err = FSGetVolumeParms( actualVolume, &volumeParms, sizeof(volumeParms) );
720     if ( noErr != err ) {
721         msg_Err( p_intf, "error retrieving volume params, bailing out" );
722         return @"";
723     }
724
725     NSString *bsdName = [NSString stringWithUTF8String:(char *)volumeParms.vMDeviceID];
726     return [NSString stringWithFormat:@"/dev/r%@", bsdName];
727 }
728
729 - (char *)getVolumeTypeFromMountPath:(NSString *)mountPath
730 {
731     OSStatus err;
732     FSRef ref;
733     FSVolumeRefNum actualVolume;
734     err = FSPathMakeRef ( (const UInt8 *) [mountPath fileSystemRepresentation], &ref, NULL );
735
736     // get a FSVolumeRefNum from mountPath
737     if ( noErr == err ) {
738         FSCatalogInfo   catalogInfo;
739         err = FSGetCatalogInfo ( &ref,
740                                 kFSCatInfoVolume,
741                                 &catalogInfo,
742                                 NULL,
743                                 NULL,
744                                 NULL
745                                 );
746         if ( noErr == err ) {
747             actualVolume = catalogInfo.volume;
748         }
749     }
750
751     GetVolParmsInfoBuffer volumeParms;
752     err = FSGetVolumeParms( actualVolume, &volumeParms, sizeof(volumeParms) );
753
754     CFMutableDictionaryRef      matchingDict;
755     io_service_t                        service;
756
757     matchingDict = IOBSDNameMatching(kIOMasterPortDefault, 0, volumeParms.vMDeviceID);
758     service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
759
760     char *returnValue;
761     if (IO_OBJECT_NULL != service) {
762         if (IOObjectConformsTo(service, kIOCDMediaClass)) {
763             returnValue = kVLCMediaAudioCD;
764         }
765         else if(IOObjectConformsTo(service, kIODVDMediaClass))
766             returnValue = kVLCMediaDVD;
767         else if(IOObjectConformsTo(service, kIOBDMediaClass))
768             returnValue = kVLCMediaBD;
769         else
770         {
771             if ([mountPath rangeOfString:@"VIDEO_TS"].location != NSNotFound)
772                 returnValue = kVLCMediaVideoTSFolder;
773             else if ([mountPath rangeOfString:@"BDMV"].location != NSNotFound)
774                 returnValue = kVLCMediaBDMVFolder;
775             else
776             {
777                 NSArray * topLevelItems;
778                 topLevelItems = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath: mountPath error: NULL];
779                 NSUInteger itemCount = [topLevelItems count];
780                 for (int i = 0; i < itemCount; i++) {
781                     if([[topLevelItems objectAtIndex:i] rangeOfString:@"SVCD"].location != NSNotFound) {
782                         returnValue = kVLCMediaSVCD;
783                         break;
784                     }
785                     if([[topLevelItems objectAtIndex:i] rangeOfString:@"VCD"].location != NSNotFound) {
786                         returnValue = kVLCMediaVCD;
787                         break;
788                     }
789                 }
790                 if(!returnValue)
791                     returnValue = kVLCMediaUnknown;
792             }
793         }
794
795         IOObjectRelease(service);
796     }
797     return returnValue;
798 }
799
800 - (void)showOpticalAtIndex: (NSNumber *)n_index
801 {
802     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
803
804     if (!o_opticalDevices)
805         return;
806
807     if ([o_opticalDevices count] == 0)
808         return;
809
810     unsigned int index = [n_index intValue];
811         id o_currentOpticalDevice = [o_opticalDevices objectAtIndex: index];
812     char *diskType = [self getVolumeTypeFromMountPath:o_currentOpticalDevice];
813
814     if (diskType == kVLCMediaDVD || diskType == kVLCMediaVideoTSFolder)
815     {
816         [o_disc_dvd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_currentOpticalDevice]];
817         [o_disc_dvdwomenus_lbl setStringValue: [o_disc_dvd_lbl stringValue]];
818         NSString *pathToOpen;
819         if (diskType == kVLCMediaVideoTSFolder)
820             pathToOpen = o_currentOpticalDevice;
821         else
822             pathToOpen = [self getBSDNodeFromMountPath: o_currentOpticalDevice];
823         if (!b_nodvdmenus) {
824             [self setMRL: [NSString stringWithFormat: @"dvdnav://%@", pathToOpen]];
825             [self showOpticalMediaView: o_disc_dvd_view withIcon: [[NSWorkspace sharedWorkspace] iconForFile: o_currentOpticalDevice]];
826         } else {
827             [self setMRL: [NSString stringWithFormat: @"dvdread://%@@%i:%i-", pathToOpen, [o_disc_dvdwomenus_title intValue], [o_disc_dvdwomenus_chapter intValue]]];
828             [self showOpticalMediaView: o_disc_dvdwomenus_view withIcon: [[NSWorkspace sharedWorkspace] iconForFile: o_currentOpticalDevice]];
829         }
830     }
831     else if (diskType == kVLCMediaAudioCD)
832     {
833         [o_disc_audiocd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath: o_currentOpticalDevice]];
834         [o_disc_audiocd_trackcount_lbl setStringValue: [NSString stringWithFormat:_NS("%i tracks"), [[[NSFileManager defaultManager] subpathsOfDirectoryAtPath: o_currentOpticalDevice error:NULL] count] - 1]]; // minus .TOC.plist
835         [self showOpticalMediaView: o_disc_audiocd_view withIcon: [[NSWorkspace sharedWorkspace] iconForFile: o_currentOpticalDevice]];
836         [self setMRL: [NSString stringWithFormat: @"cdda://%@", [self getBSDNodeFromMountPath: o_currentOpticalDevice]]];
837     }
838     else if (diskType == kVLCMediaVCD)
839     {
840         [o_disc_vcd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath: o_currentOpticalDevice]];
841         [self showOpticalMediaView: o_disc_vcd_view withIcon: [[NSWorkspace sharedWorkspace] iconForFile: o_currentOpticalDevice]];
842         [self setMRL: [NSString stringWithFormat: @"vcd://%@#%i:%i", [self getBSDNodeFromMountPath: o_currentOpticalDevice], [o_disc_vcd_title intValue], [o_disc_vcd_chapter intValue]]];
843     }
844     else if (diskType == kVLCMediaSVCD)
845     {
846         [o_disc_vcd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath: o_currentOpticalDevice]];
847         [self showOpticalMediaView: o_disc_vcd_view withIcon: [[NSWorkspace sharedWorkspace] iconForFile: o_currentOpticalDevice]];
848         [self setMRL: [NSString stringWithFormat: @"vcd://%@@%i:%i", [self getBSDNodeFromMountPath: o_currentOpticalDevice], [o_disc_vcd_title intValue], [o_disc_vcd_chapter intValue]]];
849     }
850     else if (diskType == kVLCMediaBD || diskType == kVLCMediaBDMVFolder)
851     {
852         [o_disc_bd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath: o_currentOpticalDevice]];
853         [self showOpticalMediaView: o_disc_bd_view withIcon: [[NSWorkspace sharedWorkspace] iconForFile: o_currentOpticalDevice]];
854         if (diskType == kVLCMediaBD)
855             [self setMRL: [NSString stringWithFormat: @"bluray://%@", [self getBSDNodeFromMountPath: o_currentOpticalDevice]]];
856         else
857             [self setMRL: [NSString stringWithFormat: @"bluray://%@", o_currentOpticalDevice]];
858     }
859     else
860     {
861         msg_Warn( VLCIntf, "unknown disk type, no idea what to display" );
862         [self showOpticalMediaView: o_disc_nodisc_view withIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
863     }
864
865     [o_pool release];
866 }
867
868 - (void)scanOpticalMedia:(NSNotification *)o_notification
869 {
870     [o_opticalDevices removeAllObjects];
871     [o_disc_selector_pop removeAllItems];
872     [o_opticalDevices addObjectsFromArray: [[NSWorkspace sharedWorkspace] mountedRemovableMedia]];
873     if ([o_specialMediaFolders count] > 0)
874         [o_opticalDevices addObjectsFromArray: o_specialMediaFolders];
875     if ([o_opticalDevices count] > 0) {
876         NSUInteger deviceCount = [o_opticalDevices count];
877         for (NSUInteger i = 0; i < deviceCount ; i++)
878             [o_disc_selector_pop addItemWithTitle: [[NSFileManager defaultManager] displayNameAtPath:[o_opticalDevices objectAtIndex: i]]];
879
880         if ([o_disc_selector_pop numberOfItems] <= 1)
881             [o_disc_selector_pop setHidden: YES];
882         else
883             [o_disc_selector_pop setHidden: NO];
884
885         [NSThread detachNewThreadSelector:@selector(showOpticalAtIndex:) toTarget:self withObject:[NSNumber numberWithInt:[o_disc_selector_pop indexOfSelectedItem]]];
886     }
887     else
888     {
889         msg_Dbg( VLCIntf, "no optical media found" );
890         [o_disc_selector_pop setHidden: YES];
891         [self showOpticalMediaView: o_disc_nodisc_view withIcon: [NSImage imageNamed: @"NSApplicationIcon"]];
892     }
893 }
894
895 - (IBAction)discSelectorChanged:(id)sender
896 {
897     [NSThread detachNewThreadSelector:@selector(showOpticalAtIndex:) toTarget:self withObject:[NSNumber numberWithInt:[o_disc_selector_pop indexOfSelectedItem]]];
898 }
899
900 - (IBAction)openSpecialMediaFolder:(id)sender
901 {
902     /* this is currently for VIDEO_TS and BDMV folders */
903     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
904
905     [o_open_panel setAllowsMultipleSelection: NO];
906     [o_open_panel setCanChooseFiles: NO];
907     [o_open_panel setCanChooseDirectories: YES];
908     [o_open_panel setTitle: [sender title]];
909     [o_open_panel setPrompt: _NS("Open")];
910
911     if ([o_open_panel runModal] == NSOKButton)
912     {
913         NSString *o_path = [[[o_open_panel URLs] objectAtIndex: 0] path];
914         if ([o_path length] > 0 )
915         {
916             if ([o_path rangeOfString:@"VIDEO_TS"].location != NSNotFound || [o_path rangeOfString:@"BDMV"].location != NSNotFound)
917             {
918                 [o_specialMediaFolders addObject: o_path];
919                 [self scanOpticalMedia: nil];
920             }
921             else
922                 msg_Dbg( VLCIntf, "chosen directory is no suitable special media folder" );
923         }
924     }
925 }
926
927 - (IBAction)dvdreadOptionChanged:(id)sender
928 {
929     if (sender == o_disc_dvdwomenus_enablemenus_btn) {
930         b_nodvdmenus = NO;
931         [self setMRL: [NSString stringWithFormat: @"dvdnav://%@", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: [o_disc_selector_pop indexOfSelectedItem]]]]];
932         [self showOpticalMediaView: o_disc_dvd_view withIcon: [o_currentOpticalMediaIconView image]];
933         return;
934     }
935     if (sender == o_disc_dvd_disablemenus_btn) {
936         b_nodvdmenus = YES;
937         [self showOpticalMediaView: o_disc_dvdwomenus_view withIcon: [o_currentOpticalMediaIconView image]];
938     }
939
940     if (sender == o_disc_dvdwomenus_title)
941         [o_disc_dvdwomenus_title_stp setIntValue: [o_disc_dvdwomenus_title intValue]];
942     if (sender == o_disc_dvdwomenus_title_stp)
943         [o_disc_dvdwomenus_title setIntValue: [o_disc_dvdwomenus_title_stp intValue]];
944     if (sender == o_disc_dvdwomenus_chapter)
945         [o_disc_dvdwomenus_chapter_stp setIntValue: [o_disc_dvdwomenus_chapter intValue]];
946     if (sender == o_disc_dvdwomenus_chapter_stp)
947         [o_disc_dvdwomenus_chapter setIntValue: [o_disc_dvdwomenus_chapter_stp intValue]];
948
949     [self setMRL: [NSString stringWithFormat: @"dvdread://%@@%i:%i-", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: [o_disc_selector_pop indexOfSelectedItem]]], [o_disc_dvdwomenus_title intValue], [o_disc_dvdwomenus_chapter intValue]]];
950 }
951
952 - (IBAction)vcdOptionChanged:(id)sender
953 {
954     if (sender == o_disc_vcd_title)
955         [o_disc_vcd_title_stp setIntValue: [o_disc_vcd_title intValue]];
956     if (sender == o_disc_vcd_title_stp)
957         [o_disc_vcd_title setIntValue: [o_disc_vcd_title_stp intValue]];
958     if (sender == o_disc_vcd_chapter)
959         [o_disc_vcd_chapter_stp setIntValue: [o_disc_vcd_chapter intValue]];
960     if (sender == o_disc_vcd_chapter_stp)
961         [o_disc_vcd_chapter setIntValue: [o_disc_vcd_chapter_stp intValue]];
962
963     [self setMRL: [NSString stringWithFormat: @"vcd://%@@%i:%i", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: [o_disc_selector_pop indexOfSelectedItem]]], [o_disc_vcd_title intValue], [o_disc_vcd_chapter intValue]]];
964 }
965
966 - (void)textFieldWasClicked:(NSNotification *)o_notification
967 {
968     if( [o_notification object] == o_net_udp_port )
969         [o_net_mode selectCellAtRow: 0 column: 0];
970     else if( [o_notification object] == o_net_udpm_addr ||
971              [o_notification object] == o_net_udpm_port )
972         [o_net_mode selectCellAtRow: 1 column: 0];
973     else
974         [o_net_mode selectCellAtRow: 2 column: 0];
975
976     [self openNetInfoChanged: nil];
977 }
978
979 - (IBAction)openNetModeChanged:(id)sender
980 {
981     if( sender == o_net_mode )
982     {
983         if( [[sender selectedCell] tag] == 0 )
984             [o_panel makeFirstResponder: o_net_udp_port];
985         else if ( [[sender selectedCell] tag] == 1 )
986             [o_panel makeFirstResponder: o_net_udpm_addr];
987         else
988             msg_Warn( p_intf, "Unknown sender tried to change UDP/RTP mode" );
989     }
990
991     [self openNetInfoChanged: nil];
992 }
993
994 - (IBAction)openNetStepperChanged:(id)sender
995 {
996     int i_tag = [sender tag];
997
998     if( i_tag == 0 )
999     {
1000         [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
1001         [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
1002                                                             object: o_net_udp_port];
1003         [o_panel makeFirstResponder: o_net_udp_port];
1004     }
1005     else if( i_tag == 1 )
1006     {
1007         [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
1008         [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
1009                                                             object: o_net_udpm_port];
1010         [o_panel makeFirstResponder: o_net_udpm_port];
1011     }
1012
1013     [self openNetInfoChanged: nil];
1014 }
1015
1016 - (void)openNetInfoChanged:(NSNotification *)o_notification
1017 {
1018     NSString *o_mrl_string = [NSString string];
1019
1020     if( [o_net_udp_panel isVisible] )
1021     {
1022         NSString *o_mode;
1023         o_mode = [[o_net_mode selectedCell] title];
1024
1025         if( [o_mode isEqualToString: _NS("Unicast")] )
1026         {
1027             int i_port = [o_net_udp_port intValue];
1028
1029             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
1030                 o_mrl_string = [NSString stringWithString: @"udp://"];
1031             else
1032                 o_mrl_string = [NSString stringWithString: @"rtp://"];
1033
1034             if( i_port != config_GetInt( p_intf, "server-port" ) )
1035             {
1036                 o_mrl_string =
1037                     [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
1038             }
1039         }
1040         else if( [o_mode isEqualToString: _NS("Multicast")] )
1041         {
1042             NSString *o_addr = [o_net_udpm_addr stringValue];
1043             int i_port = [o_net_udpm_port intValue];
1044
1045             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
1046                 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
1047             else
1048                 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
1049
1050             if( i_port != config_GetInt( p_intf, "server-port" ) )
1051             {
1052                 o_mrl_string =
1053                     [o_mrl_string stringByAppendingFormat: @":%i", i_port];
1054             }
1055         }
1056     }
1057     else
1058     {
1059         o_mrl_string = [o_net_http_url stringValue];
1060     }
1061     [self setMRL: o_mrl_string];
1062 }
1063
1064 - (IBAction)openNetUDPButtonAction:(id)sender
1065 {
1066     if( sender == o_net_openUDP_btn )
1067     {
1068         [NSApp beginSheet: o_net_udp_panel
1069            modalForWindow: o_panel
1070             modalDelegate: self
1071            didEndSelector: NULL
1072               contextInfo: nil];
1073         [self openNetInfoChanged: nil];
1074     }
1075     else if( sender == o_net_udp_cancel_btn )
1076     {
1077         [o_net_udp_panel orderOut: sender];
1078         [NSApp endSheet: o_net_udp_panel];
1079     }
1080     else if( sender == o_net_udp_ok_btn )
1081     {
1082         NSString *o_mrl_string = [NSString string];
1083         if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Unicast")] )
1084         {
1085             int i_port = [o_net_udp_port intValue];
1086             
1087             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
1088                 o_mrl_string = [NSString stringWithString: @"udp://"];
1089             else
1090                 o_mrl_string = [NSString stringWithString: @"rtp://"];
1091
1092             if( i_port != config_GetInt( p_intf, "server-port" ) )
1093             {
1094                 o_mrl_string =
1095                 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
1096             }
1097         }
1098         else if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Multicast")] )
1099         {
1100             NSString *o_addr = [o_net_udpm_addr stringValue];
1101             int i_port = [o_net_udpm_port intValue];
1102             
1103             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
1104                 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
1105             else
1106                 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
1107
1108             if( i_port != config_GetInt( p_intf, "server-port" ) )
1109             {
1110                 o_mrl_string =
1111                 [o_mrl_string stringByAppendingFormat: @":%i", i_port];
1112             }
1113         }
1114         [self setMRL: o_mrl_string];
1115         [o_net_http_url setStringValue: o_mrl_string];
1116         [o_net_udp_panel orderOut: sender];
1117         [NSApp endSheet: o_net_udp_panel];
1118     }
1119 }
1120     
1121 - (void)openFile
1122 {
1123     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
1124     b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
1125
1126     [o_open_panel setAllowsMultipleSelection: YES];
1127     [o_open_panel setCanChooseDirectories: YES];
1128     [o_open_panel setTitle: _NS("Open File")];
1129     [o_open_panel setPrompt: _NS("Open")];
1130  
1131     if( [o_open_panel runModal] == NSOKButton )
1132     {
1133         NSArray * o_urls = [o_open_panel URLs];
1134         NSUInteger count = [o_urls count];
1135         NSMutableArray *o_values = [NSMutableArray arrayWithCapacity:count];
1136         NSMutableArray *o_array = [NSMutableArray arrayWithCapacity:count];
1137         for( NSUInteger i = 0; i < count; i++ )
1138         {
1139             [o_values addObject: [[o_urls objectAtIndex: i] path]];
1140         }
1141         [o_values sortUsingSelector:@selector(caseInsensitiveCompare:)];
1142
1143         for( NSUInteger i = 0; i < count; i++ )
1144         {
1145             NSDictionary *o_dic;
1146             char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], "file");
1147             if( !psz_uri )
1148                 continue;
1149
1150             o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
1151
1152             free( psz_uri );
1153
1154             [o_array addObject: o_dic];
1155         }
1156         if( b_autoplay )
1157             [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
1158         else
1159             [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
1160     }
1161 }
1162
1163 - (void)showCaptureView: theView
1164 {
1165     NSRect o_view_rect;
1166     o_view_rect = [theView frame];
1167     [theView setFrame: NSMakeRect( 0, -10, o_view_rect.size.width, o_view_rect.size.height)];
1168     [theView setAutoresizesSubviews: YES];
1169     if (o_currentCaptureView)
1170     {
1171         [[[[o_tabview tabViewItemAtIndex: 3] view] animator] replaceSubview: o_currentCaptureView with: theView];
1172         [o_currentCaptureView release];
1173     }
1174     else
1175          [[[[o_tabview tabViewItemAtIndex: 3] view] animator] addSubview: theView];
1176     o_currentCaptureView = theView;
1177     [o_currentCaptureView retain];
1178 }
1179
1180 - (IBAction)openCaptureModeChanged:(id)sender
1181 {
1182     if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: @"EyeTV"] )
1183     {
1184         if( [[[VLCMain sharedInstance] eyeTVController] isEyeTVrunning] == YES )
1185         {
1186             if( [[[VLCMain sharedInstance] eyeTVController] isDeviceConnected] == YES )
1187             {
1188                 [self showCaptureView: o_eyetv_running_view];
1189                 [self setupChannelInfo];
1190             }
1191             else
1192             {
1193                 setEyeTVUnconnected;
1194             }
1195         }
1196         else
1197             [self showCaptureView: o_eyetv_notLaunched_view];
1198         [self setMRL: @""];
1199     } 
1200     else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
1201     {
1202         [self showCaptureView: o_screen_view];
1203         [self setMRL: @"screen://"];
1204         [o_screen_height_fld setIntValue: config_GetInt( p_intf, "screen-height" )];
1205         [o_screen_width_fld setIntValue: config_GetInt( p_intf, "screen-width" )];
1206         [o_screen_fps_fld setFloatValue: config_GetFloat( p_intf, "screen-fps" )];
1207         [o_screen_left_fld setIntValue: config_GetInt( p_intf, "screen-left" )];
1208         [o_screen_top_fld setIntValue: config_GetInt( p_intf, "screen-top" )];
1209         [o_screen_follow_mouse_ckb setIntValue: config_GetInt( p_intf, "screen-follow-mouse" )];
1210     }
1211     else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Capture Device")] )
1212     {
1213         [self showCaptureView: o_qtk_view];
1214         if ([o_capture_width_fld intValue] <= 0)
1215             [self qtkChanged:nil];
1216
1217         if(!qtk_currdevice_uid)
1218             [self setMRL: @""];
1219         else
1220             [self setMRL:[NSString stringWithFormat:@"qtcapture://%@", qtk_currdevice_uid]];
1221     }
1222 }
1223
1224 - (IBAction)screenStepperChanged:(id)sender
1225 {
1226     [o_screen_fps_fld setFloatValue: [o_screen_fps_stp floatValue]];
1227     [o_panel makeFirstResponder: o_screen_fps_fld];
1228     [self setMRL: @"screen://"];
1229 }
1230
1231 - (void)screenFPSfieldChanged:(NSNotification *)o_notification
1232 {
1233     [o_screen_fps_stp setFloatValue: [o_screen_fps_fld floatValue]];
1234     if( [[o_screen_fps_fld stringValue] isEqualToString: @""] )
1235         [o_screen_fps_fld setFloatValue: 1.0];
1236     [self setMRL: @"screen://"];
1237 }
1238
1239 - (IBAction)eyetvSwitchChannel:(id)sender
1240 {
1241     if( sender == o_eyetv_nextProgram_btn )
1242     {
1243         int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: YES];
1244         [o_eyetv_channels_pop selectItemWithTag:chanNum];
1245         [self setMRL: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1246     }
1247     else if( sender == o_eyetv_previousProgram_btn )
1248     {
1249         int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: NO];
1250         [o_eyetv_channels_pop selectItemWithTag:chanNum];
1251         [self setMRL: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1252     }
1253     else if( sender == o_eyetv_channels_pop )
1254     {
1255         int chanNum = [[sender selectedItem] tag];
1256         [[[VLCMain sharedInstance] eyeTVController] selectChannel:chanNum];
1257         [self setMRL: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1258     }
1259     else
1260         msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
1261 }
1262
1263 - (IBAction)eyetvLaunch:(id)sender
1264 {
1265     [[[VLCMain sharedInstance] eyeTVController] launchEyeTV];
1266 }
1267
1268 - (IBAction)eyetvGetPlugin:(id)sender
1269 {
1270     [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"http://www.videolan.org/vlc/eyetv"]];
1271 }
1272
1273 - (void)eyetvChanged:(NSNotification *)o_notification
1274 {
1275     if( [[o_notification name] isEqualToString: @"DeviceAdded"] )
1276     {
1277         msg_Dbg( VLCIntf, "eyetv device was added" );
1278         [self showCaptureView: o_eyetv_running_view];
1279         [self setupChannelInfo];
1280     }
1281     else if( [[o_notification name] isEqualToString: @"DeviceRemoved"] )
1282     {
1283         /* leave the channel selection like that,
1284          * switch to our "no device" tab */
1285         msg_Dbg( VLCIntf, "eyetv device was removed" );
1286         setEyeTVUnconnected;
1287     }
1288     else if( [[o_notification name] isEqualToString: @"PluginQuit"] )
1289     {
1290         /* switch to the "launch eyetv" tab */
1291         msg_Dbg( VLCIntf, "eyetv was terminated" );
1292         [self showCaptureView: o_eyetv_notLaunched_view];
1293     }
1294     else if( [[o_notification name] isEqualToString: @"PluginInit"] )
1295     {
1296         /* we got no device yet */
1297         msg_Dbg( VLCIntf, "eyetv was launched, no device yet" );
1298         setEyeTVUnconnected;
1299     }
1300 }    
1301
1302 /* little helper method, since this code needs to be run by multiple objects */
1303 - (void)setupChannelInfo
1304 {
1305     /* set up channel selection */
1306     [o_eyetv_channels_pop removeAllItems];
1307     [o_eyetv_chn_bgbar setHidden: NO];
1308     [o_eyetv_chn_bgbar animate: self];
1309     [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
1310     [o_eyetv_chn_status_txt setHidden: NO];
1311  
1312     /* retrieve info */
1313     NSEnumerator *channels = [[[VLCMain sharedInstance] eyeTVController] allChannels];
1314     int x = -2;
1315     [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("Composite input")
1316                                                action: nil
1317                                         keyEquivalent: @""] setTag:x++];
1318     [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("S-Video input")
1319                                                action: nil
1320                                         keyEquivalent: @""] setTag:x++];
1321     if( channels ) 
1322     {
1323         NSString *channel;
1324         [[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]];
1325         while( channel = [channels nextObject] )
1326         {
1327             /* we have to add items this way, because we accept duplicates
1328              * additionally, we save a bit of time */
1329             [[[o_eyetv_channels_pop menu] addItemWithTitle: channel
1330                                                    action: nil
1331                                             keyEquivalent: @""] setTag:++x];
1332         }
1333         /* make Tuner the default */
1334         [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] eyeTVController] currentChannel]];
1335     }
1336  
1337     /* clean up GUI */
1338     [o_eyetv_chn_bgbar setHidden: YES];
1339     [o_eyetv_chn_status_txt setHidden: YES];
1340 }
1341
1342 - (IBAction)subsChanged:(id)sender
1343 {
1344     if ([o_file_sub_ckbox state] == NSOnState)
1345     {
1346         [o_file_sub_btn_settings setEnabled:YES];
1347         if (o_sub_path) {
1348             [o_file_subtitles_filename_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_sub_path]];
1349             [o_file_subtitles_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile:o_sub_path]];
1350         }
1351     }
1352     else
1353     {
1354         [o_file_sub_btn_settings setEnabled:NO];
1355         [o_file_subtitles_filename_lbl setStringValue: @""];
1356         [o_file_subtitles_icon_well setImage: NULL];
1357     }
1358 }
1359
1360 - (IBAction)subSettings:(id)sender
1361 {
1362     [NSApp beginSheet: o_file_sub_sheet
1363         modalForWindow: [sender window]
1364         modalDelegate: self
1365         didEndSelector: NULL
1366         contextInfo: nil];
1367 }
1368
1369 - (IBAction)subCloseSheet:(id)sender
1370 {
1371     [self subsChanged: nil];
1372     [o_file_sub_sheet orderOut:sender];
1373     [NSApp endSheet: o_file_sub_sheet];
1374 }
1375     
1376 - (IBAction)subFileBrowse:(id)sender
1377 {
1378     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
1379  
1380     [o_open_panel setAllowsMultipleSelection: NO];
1381     [o_open_panel setTitle: _NS("Open File")];
1382     [o_open_panel setPrompt: _NS("Open")];
1383
1384     if( [o_open_panel runModal] == NSOKButton )
1385     {
1386         o_sub_path = [[[o_open_panel URLs] objectAtIndex: 0] path];
1387         [o_sub_path retain];
1388         [o_file_subtitles_filename_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_sub_path]];
1389         [o_file_sub_path_fld setStringValue: [o_file_subtitles_filename_lbl stringValue]];
1390         [o_file_sub_path_lbl setHidden: YES];
1391         [o_file_subtitles_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile:o_sub_path]];
1392         [o_file_sub_icon_view setImage: [o_file_subtitles_icon_well image]];
1393     }
1394     else
1395     {
1396         [o_file_sub_path_lbl setHidden: NO];
1397         [o_file_sub_path_fld setStringValue:@""];
1398         [o_file_subtitles_filename_lbl setStringValue:@""];
1399         [o_file_subtitles_icon_well setImage: nil];
1400         [o_file_sub_icon_view setImage: nil];
1401     }
1402 }
1403
1404 - (IBAction)subOverride:(id)sender
1405 {
1406     BOOL b_state = [o_file_sub_override state];
1407     [o_file_sub_delay setEnabled: b_state];
1408     [o_file_sub_delay_stp setEnabled: b_state];
1409     [o_file_sub_fps setEnabled: b_state];
1410     [o_file_sub_fps_stp setEnabled: b_state];
1411 }
1412
1413 - (IBAction)subDelayStepperChanged:(id)sender
1414 {
1415     [o_file_sub_delay setIntValue: [o_file_sub_delay_stp intValue]];
1416 }
1417
1418 - (IBAction)subFpsStepperChanged:(id)sender;
1419 {
1420     [o_file_sub_fps setFloatValue: [o_file_sub_fps_stp floatValue]];
1421 }
1422
1423 - (IBAction)panelCancel:(id)sender
1424 {
1425     [NSApp stopModalWithCode: 0];
1426 }
1427
1428 - (IBAction)panelOk:(id)sender
1429 {
1430     if( [[self MRL] length] )
1431         [NSApp stopModalWithCode: 1];
1432     else
1433         NSBeep();
1434 }
1435
1436 - (NSArray *)qtkvideoDevices
1437 {
1438     if (!qtkvideoDevices)
1439         [self qtkrefreshDevices];
1440     return qtkvideoDevices;
1441 }
1442
1443 - (void)qtkrefreshDevices
1444 {
1445     [qtkvideoDevices release];
1446     qtkvideoDevices = [[[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo] arrayByAddingObjectsFromArray:[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeMuxed]] retain];
1447 }
1448
1449 @end
1450
1451 @implementation VLCOpenTextField
1452
1453 - (void)mouseDown:(NSEvent *)theEvent
1454 {
1455     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
1456                                                         object: self];
1457     [super mouseDown: theEvent];
1458 }
1459
1460 @end