]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/open.cpp
cdda/info.c: changes for libcddb 1.1.0 API
[vlc] / modules / gui / wxwindows / open.cpp
1 /*****************************************************************************
2  * open.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30 #include <stdio.h>
31
32 #include <vlc/vlc.h>
33 #ifdef HAVE_LIBCDIO
34 #include <cdio/cdio.h>
35 #include <cdio/cd_types.h>
36 #endif /* HAVE_LIBCDIO */
37
38 #include <wx/combobox.h>
39 #include <wx/statline.h>
40 #include <wx/tokenzr.h>
41
42 #include <vlc/intf.h>
43
44 #include <vector>
45
46 #include "wxwindows.h"
47 #include "preferences_widgets.h"
48
49 #ifndef wxRB_SINGLE
50 #   define wxRB_SINGLE 0
51 #endif
52
53 /*****************************************************************************
54  * Event Table.
55  *****************************************************************************/
56
57 /* IDs for the controls and the menu commands */
58 enum
59 {
60     Notebook_Event = wxID_HIGHEST,
61     MRL_Event,
62
63     FileBrowse_Event,
64     FileName_Event,
65
66     DiscType_Event,
67 #ifdef HAVE_LIBCDIO
68     DiscProbe_Event,
69 #endif
70     DiscDevice_Event,
71     DiscTitle_Event,
72     DiscChapter_Event,
73     DiscSub_Event,
74     DiscAudio_Event,
75
76     NetType_Event,
77     NetRadio1_Event, NetRadio2_Event, NetRadio3_Event, NetRadio4_Event,
78     NetPort1_Event, NetPort2_Event, NetPort3_Event,
79     NetAddr1_Event, NetAddr2_Event, NetAddr3_Event, NetAddr4_Event,
80     NetForceIPv6_Event, NetTimeshift_Event,
81
82     SubsFileEnable_Event,
83     SubsFileSettings_Event,
84
85     SoutEnable_Event,
86     SoutSettings_Event,
87
88     CachingEnable_Event,
89     CachingChange_Event,
90
91     AdvancedOptions_Event
92 };
93
94 BEGIN_EVENT_TABLE(OpenDialog, wxDialog)
95     /* Button events */
96     EVT_BUTTON(wxID_OK, OpenDialog::OnOk)
97     EVT_BUTTON(wxID_CANCEL, OpenDialog::OnCancel)
98
99     EVT_NOTEBOOK_PAGE_CHANGED(Notebook_Event, OpenDialog::OnPageChange)
100
101     EVT_TEXT(MRL_Event, OpenDialog::OnMRLChange)
102
103     /* Events generated by the file panel */
104     EVT_TEXT(FileName_Event, OpenDialog::OnFilePanelChange)
105     EVT_BUTTON(FileBrowse_Event, OpenDialog::OnFileBrowse)
106
107     /* Events generated by the disc panel */
108     EVT_RADIOBOX(DiscType_Event, OpenDialog::OnDiscTypeChange)
109 #ifdef HAVE_LIBCDIO
110     EVT_CHECKBOX(DiscProbe_Event, OpenDialog::OnDiscProbe)
111 #endif
112     EVT_TEXT(DiscDevice_Event, OpenDialog::OnDiscDeviceChange)
113     EVT_TEXT(DiscDevice_Event, OpenDialog::OnDiscPanelChange)
114     EVT_TEXT(DiscTitle_Event, OpenDialog::OnDiscPanelChange)
115     EVT_SPINCTRL(DiscTitle_Event, OpenDialog::OnDiscPanelChangeSpin)
116     EVT_TEXT(DiscChapter_Event, OpenDialog::OnDiscPanelChange)
117     EVT_SPINCTRL(DiscChapter_Event, OpenDialog::OnDiscPanelChangeSpin)
118     EVT_TEXT(DiscSub_Event, OpenDialog::OnDiscPanelChange)
119     EVT_TEXT(DiscAudio_Event, OpenDialog::OnDiscPanelChange)
120     EVT_SPINCTRL(DiscSub_Event, OpenDialog::OnDiscPanelChangeSpin)
121
122     /* Events generated by the net panel */
123     EVT_RADIOBUTTON(NetRadio1_Event, OpenDialog::OnNetTypeChange)
124     EVT_RADIOBUTTON(NetRadio2_Event, OpenDialog::OnNetTypeChange)
125     EVT_RADIOBUTTON(NetRadio3_Event, OpenDialog::OnNetTypeChange)
126     EVT_RADIOBUTTON(NetRadio4_Event, OpenDialog::OnNetTypeChange)
127     EVT_TEXT(NetPort1_Event, OpenDialog::OnNetPanelChange)
128     EVT_SPINCTRL(NetPort1_Event, OpenDialog::OnNetPanelChangeSpin)
129     EVT_TEXT(NetPort2_Event, OpenDialog::OnNetPanelChange)
130     EVT_SPINCTRL(NetPort2_Event, OpenDialog::OnNetPanelChangeSpin)
131     EVT_TEXT(NetPort3_Event, OpenDialog::OnNetPanelChange)
132     EVT_SPINCTRL(NetPort3_Event, OpenDialog::OnNetPanelChangeSpin)
133     EVT_TEXT(NetAddr2_Event, OpenDialog::OnNetPanelChange)
134     EVT_TEXT(NetAddr3_Event, OpenDialog::OnNetPanelChange)
135     EVT_TEXT(NetAddr4_Event, OpenDialog::OnNetPanelChange)
136     EVT_CHECKBOX(NetForceIPv6_Event, OpenDialog::OnNetPanelChange)
137     EVT_CHECKBOX(NetTimeshift_Event, OpenDialog::OnNetPanelChange)
138
139     /* Events generated by the subtitle file buttons */
140     EVT_CHECKBOX(SubsFileEnable_Event, OpenDialog::OnSubsFileEnable)
141     EVT_BUTTON(SubsFileSettings_Event, OpenDialog::OnSubsFileSettings)
142
143     /* Events generated by the stream output buttons */
144     EVT_CHECKBOX(SoutEnable_Event, OpenDialog::OnSoutEnable)
145     EVT_BUTTON(SoutSettings_Event, OpenDialog::OnSoutSettings)
146
147     /* Events generated by the caching button */
148     EVT_CHECKBOX(CachingEnable_Event, OpenDialog::OnCachingEnable)
149     EVT_TEXT(CachingChange_Event, OpenDialog::OnCachingChange)
150     EVT_SPINCTRL(CachingChange_Event, OpenDialog::OnCachingChangeSpin)
151
152     /* Hide the window when the user closes the window */
153     EVT_CLOSE(OpenDialog::OnClose)
154
155 END_EVENT_TABLE()
156
157 /*****************************************************************************
158  * AutoBuiltPanel.
159  *****************************************************************************/
160 WX_DEFINE_ARRAY(ConfigControl *, ArrayOfConfigControls);
161
162 class AutoBuiltPanel : public wxPanel
163 {
164 public:
165
166     AutoBuiltPanel() { }
167     AutoBuiltPanel( wxWindow *, OpenDialog *, intf_thread_t *,
168                     const module_t * );
169
170     virtual ~AutoBuiltPanel() {}
171
172     void UpdateAdvancedMRL();
173
174     wxString name;
175     ArrayOfConfigControls config_array;
176     ArrayOfConfigControls advanced_config_array;
177     wxComboBox *p_advanced_mrl_combo;
178
179 private:
180     intf_thread_t *p_intf;
181     OpenDialog *p_open_dialog;
182
183     void OnAdvanced( wxCommandEvent& event );
184     wxDialog *p_advanced_dialog;
185
186     DECLARE_EVENT_TABLE();
187 };
188
189 BEGIN_EVENT_TABLE(AutoBuiltPanel, wxPanel)
190     EVT_BUTTON(AdvancedOptions_Event, AutoBuiltPanel::OnAdvanced)
191 END_EVENT_TABLE()
192
193 static void AutoBuildCallback( void *p_data )
194 {
195     ((OpenDialog *)p_data)->UpdateMRL();
196 }
197
198 static void AutoBuildAdvancedCallback( void *p_data )
199 {
200     ((AutoBuiltPanel *)p_data)->UpdateAdvancedMRL();
201 }
202
203 AutoBuiltPanel::AutoBuiltPanel( wxWindow *parent, OpenDialog *dialog,
204                                 intf_thread_t *_p_intf,
205                                 const module_t *p_module )
206   : wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize ),
207     name( wxU(p_module->psz_object_name) ),
208     p_advanced_mrl_combo( NULL ),
209     p_intf( _p_intf ), p_open_dialog( dialog ), p_advanced_dialog( NULL )
210 {
211     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
212     module_config_t *p_item = p_module->p_config;
213     bool b_advanced = false;
214
215     if( p_item ) do
216     {
217         if( !(p_item->i_type & CONFIG_HINT) && p_item->b_advanced )
218             b_advanced = true;
219
220         if( p_item->i_type & CONFIG_HINT || p_item->b_advanced )
221             continue;
222
223         ConfigControl *control =
224             CreateConfigControl( VLC_OBJECT(p_intf), p_item, this );
225
226         config_array.Add( control );
227
228         /* Don't add items that were not recognized */
229         if( control == NULL ) continue;
230
231         control->SetUpdateCallback( AutoBuildCallback, (void *)dialog );
232
233         sizer->Add( control, 0, wxEXPAND | wxALL, 2 );
234     }
235     while( p_item->i_type != CONFIG_HINT_END && p_item++ );
236
237     if( b_advanced )
238     {
239         wxButton *button =
240             new wxButton( this, AdvancedOptions_Event,
241                           wxU(_("Advanced options...")) );
242         sizer->Add( button, 0, wxALL, 5 );
243
244         /* Build the advanced dialog */
245         p_advanced_dialog =
246             new wxDialog( this, -1, ((wxString)wxU(_("Advanced options"))) +
247                           wxT(" (") + wxU( p_module->psz_longname ) + wxT(")"),
248                           wxDefaultPosition, wxDefaultSize,
249                           wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER );
250
251         wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
252
253         /* Create MRL combobox */
254         wxBoxSizer *mrl_sizer_sizer = new wxBoxSizer( wxHORIZONTAL );
255         wxStaticBox *mrl_box =
256             new wxStaticBox( p_advanced_dialog, -1,
257                              wxU(_("Advanced options")) );
258         wxStaticBoxSizer *mrl_sizer =
259             new wxStaticBoxSizer( mrl_box, wxHORIZONTAL );
260         wxStaticText *mrl_label =
261             new wxStaticText( p_advanced_dialog, -1, wxU(_("Options:")) );
262         p_advanced_mrl_combo =
263             new wxComboBox( p_advanced_dialog, MRL_Event, wxT(""),
264                             wxDefaultPosition, wxDefaultSize );
265         mrl_sizer->Add( mrl_label, 0, wxALL | wxALIGN_CENTER, 5 );
266         mrl_sizer->Add( p_advanced_mrl_combo, 1, wxALL | wxALIGN_CENTER, 5 );
267         mrl_sizer_sizer->Add( mrl_sizer, 1, wxEXPAND | wxALL, 5 );
268         sizer->Add( mrl_sizer_sizer, 0, wxEXPAND | wxALL, 2 );
269
270         /* Add advanced options to panel */
271         module_config_t *p_item = p_module->p_config;
272         if( p_item ) do
273         {
274             if( p_item->i_type & CONFIG_HINT || !p_item->b_advanced )
275                 continue;
276
277             ConfigControl *control =
278                 CreateConfigControl( VLC_OBJECT(p_intf), p_item,
279                                      p_advanced_dialog );
280
281             advanced_config_array.Add( control );
282
283             /* Don't add items that were not recognized */
284             if( control == NULL ) continue;
285
286             control->SetUpdateCallback( AutoBuildAdvancedCallback,
287                                         (void *)this );
288
289             sizer->Add( control, 0, wxEXPAND | wxALL, 2 );
290         }
291         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
292
293         /* Separation */
294         wxPanel *dummy_panel = new wxPanel( p_advanced_dialog, -1 );
295         sizer->Add( dummy_panel, 1 );
296         wxStaticLine *static_line =
297             new wxStaticLine( p_advanced_dialog, wxID_OK );
298         sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
299
300         /* Create buttons */
301         wxButton *ok_button =
302             new wxButton( p_advanced_dialog, wxID_OK, wxU(_("OK")) );
303         ok_button->SetDefault();
304         wxButton *cancel_button =
305             new wxButton( p_advanced_dialog, wxID_CANCEL, wxU(_("Cancel")) );
306         wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
307         button_sizer->Add( ok_button, 0, wxALL, 5 );
308         button_sizer->Add( cancel_button, 0, wxALL, 5 );
309         button_sizer->Layout();
310         sizer->Add( button_sizer, 0, wxALL, 0 );
311
312         sizer->SetMinSize( 400, -1 );
313         p_advanced_dialog->SetSizerAndFit( sizer );
314     }
315
316     this->SetSizerAndFit( sizer );
317 }
318
319 void AutoBuiltPanel::OnAdvanced( wxCommandEvent& event )
320 {
321     if( p_advanced_dialog->ShowModal() == wxID_OK )
322     {
323         UpdateAdvancedMRL();
324         p_open_dialog->UpdateMRL();
325     }
326 }
327
328 void AutoBuiltPanel::UpdateAdvancedMRL()
329 {
330     wxString mrltemp;
331
332     for( int i = 0; i < (int)advanced_config_array.GetCount(); i++ )
333     {
334         ConfigControl *control = advanced_config_array.Item(i);
335
336         mrltemp += (i ? wxT(" :") : wxT(":"));
337
338         if( control->GetType() == CONFIG_ITEM_BOOL &&
339             !control->GetIntValue() ) mrltemp += wxT("no-");
340
341         mrltemp += control->GetName();
342
343         switch( control->GetType() )
344         {
345         case CONFIG_ITEM_STRING:
346         case CONFIG_ITEM_FILE:
347         case CONFIG_ITEM_DIRECTORY:
348         case CONFIG_ITEM_MODULE:
349             mrltemp += wxT("=\"") + control->GetPszValue() + wxT("\"");
350             break;
351         case CONFIG_ITEM_INTEGER:
352             mrltemp +=
353                 wxString::Format( wxT("=%i"), control->GetIntValue() );
354             break;
355         case CONFIG_ITEM_FLOAT:
356             mrltemp +=
357                 wxString::Format(wxT("=%f"), control->GetFloatValue());
358             break;
359         }
360     }
361
362     p_advanced_mrl_combo->SetValue( mrltemp );
363 }
364
365 /*****************************************************************************
366  * Constructor.
367  *****************************************************************************/
368 OpenDialog::OpenDialog( intf_thread_t *_p_intf, wxWindow *_p_parent,
369                         int i_access_method, int i_arg ):
370       wxDialog( _p_parent, -1, wxU(_("Open...")), wxDefaultPosition,
371              wxDefaultSize, wxDEFAULT_FRAME_STYLE )
372 {
373     OpenDialog( _p_intf, _p_parent, i_access_method, i_arg, OPEN_NORMAL );
374 }
375
376 OpenDialog::OpenDialog( intf_thread_t *_p_intf, wxWindow *_p_parent,
377                         int i_access_method, int i_arg, int _i_method ):
378       wxDialog( _p_parent, -1, wxU(_("Open...")), wxDefaultPosition,
379              wxDefaultSize, wxDEFAULT_FRAME_STYLE )
380 {
381     /* Initializations */
382     i_method = _i_method;
383     p_intf = _p_intf;
384     p_parent = _p_parent;
385     SetIcon( *p_intf->p_sys->p_icon );
386     file_dialog = NULL;
387     i_disc_type_selection = 0;
388     i_disc_title = 0;
389     i_open_arg = i_arg;
390
391     sout_dialog = NULL;
392     subsfile_dialog = NULL;
393     b_disc_device_changed = false;
394
395     /* Create a panel to put everything in */
396     wxPanel *panel = new wxPanel( this, -1 );
397     panel->SetAutoLayout( TRUE );
398
399     /* Create MRL combobox */
400     wxBoxSizer *mrl_sizer_sizer = new wxBoxSizer( wxHORIZONTAL );
401     wxStaticBox *mrl_box = new wxStaticBox( panel, -1,
402                                wxU(_("Media Resource Locator (MRL)")) );
403     wxStaticBoxSizer *mrl_sizer = new wxStaticBoxSizer( mrl_box,
404                                                         wxHORIZONTAL );
405     wxStaticText *mrl_label = new wxStaticText( panel, -1,
406                                                 wxU(_("Open:")) );
407     mrl_combo = new wxComboBox( panel, MRL_Event, wxT(""),
408                                 wxPoint(20,25), wxSize(120, -1) );
409     mrl_combo->SetToolTip( wxU(_("You can use this field directly by typing "
410         "the full MRL you want to open.\n""Alternatively, the field will be "
411         "filled automatically when you use the controls below.")) );
412
413     mrl_sizer->Add( mrl_label, 0, wxALL | wxALIGN_CENTER, 5 );
414     mrl_sizer->Add( mrl_combo, 1, wxALL | wxALIGN_CENTER, 5 );
415     mrl_sizer_sizer->Add( mrl_sizer, 1, wxEXPAND | wxALL, 5 );
416
417
418     /* Create Static Text */
419     wxStaticText *label = new wxStaticText( panel, -1,
420         wxU(_("Alternatively, you can build an MRL using one of the "
421               "following predefined targets:")) );
422
423     wxFlexGridSizer *common_opt_sizer = new wxFlexGridSizer( 5, 1, 20 );
424
425     if( i_method == OPEN_NORMAL )
426     {
427         /* Create Stream Output checkox */
428         sout_checkbox = new wxCheckBox( panel, SoutEnable_Event,
429                                          wxU(_("Stream output")) );
430         sout_checkbox->SetToolTip( wxU(_("Use VLC as a server of streams")) );
431         common_opt_sizer->Add( sout_checkbox, 0,
432                                wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
433
434         sout_button = new wxButton( panel, SoutSettings_Event,
435                                     wxU(_("Settings...")) );
436         sout_button->Disable();
437
438         char *psz_sout = config_GetPsz( p_intf, "sout" );
439         if( psz_sout && *psz_sout )
440         {
441             sout_checkbox->SetValue(TRUE);
442             sout_button->Enable();
443             subsfile_mrl.Add( wxString(wxT("sout=")) + wxL2U(psz_sout) );
444         }
445         if( psz_sout ) free( psz_sout );
446
447         common_opt_sizer->Add( sout_button, 1, wxALIGN_LEFT |
448                                wxALIGN_CENTER_VERTICAL );
449
450         common_opt_sizer->Add( new wxPanel( this, -1 ), 1,
451                                wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
452     }
453
454     /* Create caching options */
455     caching_checkbox = new wxCheckBox( panel, CachingEnable_Event,
456                                        wxU(_("Caching")) );
457     caching_checkbox->SetToolTip( wxU(_("Change the default caching value "
458                                         "(in milliseconds)")) );
459     common_opt_sizer->Add( caching_checkbox, 0,
460                            wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
461     caching_value = new wxSpinCtrl( panel, CachingChange_Event );
462     caching_value->SetRange( 0, 1000000 );
463     caching_value->Disable();
464     common_opt_sizer->Add( caching_value, 0,
465                            wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
466
467     /* Separation */
468     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
469
470     /* Create the buttons */
471     wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
472     ok_button->SetDefault();
473     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
474                                             wxU(_("Cancel")) );
475
476     /* Create notebook */
477     notebook = new wxNotebook( panel, Notebook_Event );
478
479 #if (!wxCHECK_VERSION(2,5,0))
480     wxNotebookSizer *notebook_sizer = new wxNotebookSizer( notebook );
481 #endif
482
483     notebook->AddPage( FilePanel( notebook ), wxU(_("File")),
484                        i_access_method == FILE_ACCESS );
485     notebook->AddPage( DiscPanel( notebook ), wxU(_("Disc")),
486                        i_access_method == DISC_ACCESS );
487     notebook->AddPage( NetPanel( notebook ), wxU(_("Network")),
488                        i_access_method == NET_ACCESS );
489
490     module_t *p_module = config_FindModule( VLC_OBJECT(p_intf), "v4l" );
491     if( p_module )
492     {
493         AutoBuiltPanel *autopanel =
494             new AutoBuiltPanel( notebook, this, p_intf, p_module );
495         input_tab_array.Add( autopanel );
496         notebook->AddPage( autopanel, wxU( p_module->psz_shortname ?
497                         p_module->psz_shortname : p_module->psz_object_name ),
498                            i_access_method == CAPTURE_ACCESS );
499     }
500
501     p_module = config_FindModule( VLC_OBJECT(p_intf), "pvr" );
502     if( p_module )
503     {
504         AutoBuiltPanel *autopanel =
505             new AutoBuiltPanel( notebook, this, p_intf, p_module );
506         input_tab_array.Add( autopanel );
507         notebook->AddPage( autopanel, wxU( p_module->psz_shortname ?
508                         p_module->psz_shortname : p_module->psz_object_name ),
509                            i_access_method == CAPTURE_ACCESS );
510     }
511
512     p_module = config_FindModule( VLC_OBJECT(p_intf), "dvb" );
513     if( p_module )
514     {
515         AutoBuiltPanel *autopanel =
516             new AutoBuiltPanel( notebook, this, p_intf, p_module );
517         input_tab_array.Add( autopanel );
518         notebook->AddPage( autopanel, wxU( p_module->psz_shortname ?
519                         p_module->psz_shortname : p_module->psz_object_name ),
520                            i_access_method == CAPTURE_ACCESS );
521     }
522
523     p_module = config_FindModule( VLC_OBJECT(p_intf), "dshow" );
524     if( p_module )
525     {
526         AutoBuiltPanel *autopanel =
527             new AutoBuiltPanel( notebook, this, p_intf, p_module );
528         input_tab_array.Add( autopanel );
529         notebook->AddPage( autopanel, wxU( p_module->psz_shortname ?
530                         p_module->psz_shortname : p_module->psz_object_name ),
531                            i_access_method == CAPTURE_ACCESS );
532     }
533
534     /* Update Disc panel */
535     wxCommandEvent dummy_event;
536     OnDiscTypeChange( dummy_event );
537
538     /* Update Net panel */
539     dummy_event.SetId( NetRadio1_Event );
540     OnNetTypeChange( dummy_event );
541
542     /* Update MRL */
543     wxNotebookEvent event( wxEVT_NULL, 0, i_access_method );
544     OnPageChange( event );
545
546     /* Place everything in sizers */
547     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
548     button_sizer->Add( ok_button, 0, wxALL, 5 );
549     button_sizer->Add( cancel_button, 0, wxALL, 5 );
550     button_sizer->Layout();
551     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
552     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
553     panel_sizer->Add( mrl_sizer_sizer, 0, wxEXPAND, 5 );
554     panel_sizer->Add( label, 0, wxEXPAND | wxALL, 5 );
555 #if (!wxCHECK_VERSION(2,5,0))
556     panel_sizer->Add( notebook_sizer, 1, wxEXPAND | wxALL, 5 );
557 #else
558     panel_sizer->Add( notebook, 1, wxEXPAND | wxALL, 5 );
559 #endif
560     panel_sizer->Add( common_opt_sizer, 0, wxALIGN_LEFT | wxALL, 5 );
561     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
562     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALL, 5 );
563     panel_sizer->Layout();
564     panel->SetSizerAndFit( panel_sizer );
565     main_sizer->Add( panel, 1, wxGROW, 0 );
566     main_sizer->Layout();
567     SetSizerAndFit( main_sizer );
568 }
569
570 OpenDialog::~OpenDialog()
571 {
572     /* Clean up */
573     if( file_dialog ) delete file_dialog;
574     if( sout_dialog ) delete sout_dialog;
575     if( subsfile_dialog ) delete subsfile_dialog;
576 }
577
578 int OpenDialog::Show( int i_access_method, int i_arg )
579 {
580     notebook->SetSelection( i_access_method );
581     int i_ret = wxDialog::Show();
582     Raise();
583     SetFocus();
584     i_open_arg = i_arg;
585     return i_ret;
586 }
587
588 int OpenDialog::Show()
589 {
590     int i_ret = wxDialog::Show();
591     Raise();
592     SetFocus();
593     return i_ret;
594 }
595
596 /*****************************************************************************
597  * Private methods.
598  *****************************************************************************/
599 wxPanel *OpenDialog::FilePanel( wxWindow* parent )
600 {
601     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
602                                   wxSize(200, 200) );
603
604     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
605
606     /* Create browse file line */
607     wxBoxSizer *file_sizer = new wxBoxSizer( wxHORIZONTAL );
608
609     file_combo = new wxComboBox( panel, FileName_Event, wxT(""),
610                                  wxPoint(20,25), wxSize(200, -1) );
611     wxButton *browse_button = new wxButton( panel, FileBrowse_Event,
612                                             wxU(_("Browse...")) );
613     file_sizer->Add( file_combo, 1, wxALL, 5 );
614     file_sizer->Add( browse_button, 0, wxALL, 5 );
615
616     /* Create Subtitles File checkox */
617     wxFlexGridSizer *subsfile_sizer = new wxFlexGridSizer( 2, 1, 20 );
618     subsfile_checkbox = new wxCheckBox( panel, SubsFileEnable_Event,
619                                         wxU(_("Subtitle options")) );
620     subsfile_checkbox->SetToolTip( wxU(_("Force options for separate subtitle files.")) );
621     subsfile_sizer->Add( subsfile_checkbox, 0,
622                          wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
623     subsfile_button = new wxButton( panel, SubsFileSettings_Event,
624                                     wxU(_("Settings...")) );
625     subsfile_button->Disable();
626
627     char *psz_subsfile = config_GetPsz( p_intf, "sub-file" );
628     if( psz_subsfile && *psz_subsfile )
629     {
630         subsfile_checkbox->SetValue(TRUE);
631         subsfile_button->Enable();
632         subsfile_mrl.Add( wxString(wxT("sub-file=")) + wxL2U(psz_subsfile) );
633     }
634     if( psz_subsfile ) free( psz_subsfile );
635
636     subsfile_sizer->Add( subsfile_button, 1,
637                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
638
639     sizer->Add( file_sizer, 0, wxEXPAND | wxALL, 5 );
640     sizer->Add( subsfile_sizer, 0, wxEXPAND | wxALL, 5 );
641     panel->SetSizerAndFit( sizer );
642     return panel;
643 }
644
645 wxPanel *OpenDialog::DiscPanel( wxWindow* parent )
646 {
647     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
648                                   wxSize(200, 200) );
649
650     wxBoxSizer *sizer_row = new wxBoxSizer( wxVERTICAL );
651     wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 3, 20 );
652
653     static const wxString disc_type_array[] =
654     {
655         wxU(_("DVD (menus)")),
656         wxU(_("DVD")),
657         wxU(_("VCD")),
658         wxU(_("Audio CD")),
659     };
660
661     disc_type = new wxRadioBox( panel, DiscType_Event, wxU(_("Disc type")),
662                                 wxDefaultPosition, wxDefaultSize,
663                                 WXSIZEOF(disc_type_array), disc_type_array,
664                                 WXSIZEOF(disc_type_array), wxRA_SPECIFY_COLS );
665
666 #ifdef HAVE_LIBCDIO
667     disc_probe = new wxCheckBox( panel, DiscProbe_Event, 
668                                  wxU(_("Probe Disc")) );
669 #endif
670
671     sizer_row->Add( disc_type, i_disc_type_selection, wxEXPAND | wxALL, 5 );
672     sizer_row->Add( disc_probe, 0, wxEXPAND | wxALL );
673
674     wxStaticText *label = new wxStaticText( panel, -1, wxU(_("Device name")) );
675     disc_device = new wxTextCtrl( panel, DiscDevice_Event, wxT(""),
676                                   wxDefaultPosition, wxDefaultSize,
677                                   wxTE_PROCESS_ENTER);
678
679     sizer->Add( label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
680     sizer->Add( disc_device, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
681
682     disc_title_label = new wxStaticText( panel, -1, wxU(_("Title")) );
683     disc_title = new wxSpinCtrl( panel, DiscTitle_Event );
684     sizer->Add( disc_title_label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
685     sizer->Add( disc_title, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
686
687     disc_chapter_label = new wxStaticText( panel, -1, wxU(_("Chapter")) );
688     disc_chapter = new wxSpinCtrl( panel, DiscChapter_Event );
689     sizer->Add( disc_chapter_label, 0,
690                 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
691     sizer->Add( disc_chapter, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
692
693     disc_sub_label = new wxStaticText( panel, -1, wxU(_("Subtitles track")) );
694     disc_sub = new wxSpinCtrl( panel, DiscSub_Event );
695     sizer->Add( disc_sub_label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
696     sizer->Add( disc_sub, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
697     disc_sub->SetRange( -1, 255 );
698     i_disc_sub = config_GetInt( p_intf, "sub-track" );
699     disc_sub->SetValue( i_disc_sub );
700
701     disc_audio_label = new wxStaticText( panel, -1, wxU(_("Audio track")) );
702     disc_audio = new wxSpinCtrl( panel, DiscAudio_Event );
703     sizer->Add( disc_audio_label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
704     sizer->Add( disc_audio, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
705     disc_audio->SetRange( -1, 255 );
706     i_disc_audio = config_GetInt( p_intf, "audio-track" );
707     disc_audio->SetValue( i_disc_audio );
708
709     sizer_row->Add( sizer, 0, wxEXPAND | wxALL, 5 );
710
711     panel->SetSizerAndFit( sizer_row );
712     return panel;
713 }
714
715 wxPanel *OpenDialog::NetPanel( wxWindow* parent )
716 {
717     int i;
718     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
719                                   wxSize(200, 200) );
720
721     wxBoxSizer *sizer_row = new wxBoxSizer( wxVERTICAL );
722     wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 4, 20 );
723
724     static const wxString net_type_array[] =
725     {
726         wxU(_("UDP/RTP")),
727         wxU(_("UDP/RTP Multicast")),
728         wxU(_("HTTP/HTTPS/FTP/MMS")),
729         wxU(_("RTSP"))
730     };
731
732     for( i=0; i<4; i++ )
733     {
734         net_radios[i] = new wxRadioButton( panel, NetRadio1_Event + i,
735                                            net_type_array[i],
736                                            wxDefaultPosition, wxDefaultSize,
737                                            wxRB_SINGLE );
738
739         net_subpanels[i] = new wxPanel( panel, -1,
740                                         wxDefaultPosition, wxDefaultSize );
741     }
742
743     /* Timeshift */
744     net_timeshift  = new wxCheckBox( panel, NetTimeshift_Event,
745                                      wxU(_("Allow timeshifting")) );
746
747     /* UDP/RTP row */
748     wxFlexGridSizer *subpanel_sizer;
749     wxStaticText *label;
750     i_net_ports[0] = config_GetInt( p_intf, "server-port" );
751     subpanel_sizer = new wxFlexGridSizer( 3, 1, 20 );
752     label = new wxStaticText( net_subpanels[0], -1, wxU(_("Port")) );
753     net_ports[0] = new wxSpinCtrl( net_subpanels[0], NetPort1_Event,
754                                    wxString::Format(wxT("%d"), i_net_ports[0]),
755                                    wxDefaultPosition, wxDefaultSize,
756                                    wxSP_ARROW_KEYS,
757                                    0, 65535, i_net_ports[0] );
758
759     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
760     subpanel_sizer->Add( net_ports[0], 1,
761                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
762     net_ipv6 = new wxCheckBox( net_subpanels[0], NetForceIPv6_Event,
763                                wxU(_("Force IPv6")));
764     subpanel_sizer->Add( net_ipv6, 0,
765                          wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
766     net_subpanels[0]->SetSizerAndFit( subpanel_sizer );
767     net_radios[0]->SetValue( TRUE );
768
769     /* UDP/RTP Multicast row */
770     subpanel_sizer = new wxFlexGridSizer( 4, 1, 20 );
771     label = new wxStaticText( net_subpanels[1], -1, wxU(_("Address")) );
772     net_addrs[1] = new wxTextCtrl( net_subpanels[1], NetAddr2_Event, wxT(""),
773                                    wxDefaultPosition, wxDefaultSize,
774                                    wxTE_PROCESS_ENTER);
775     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
776     subpanel_sizer->Add( net_addrs[1], 1,
777                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
778
779     label = new wxStaticText( net_subpanels[1], -1, wxU(_("Port")) );
780     i_net_ports[1] = i_net_ports[0];
781     net_ports[1] = new wxSpinCtrl( net_subpanels[1], NetPort2_Event,
782                                    wxString::Format(wxT("%d"), i_net_ports[1]),
783                                    wxDefaultPosition, wxDefaultSize,
784                                    wxSP_ARROW_KEYS,
785                                    0, 65535, i_net_ports[1] );
786
787     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
788     subpanel_sizer->Add( net_ports[1], 1,
789                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
790     net_subpanels[1]->SetSizerAndFit( subpanel_sizer );
791
792     /* HTTP and RTSP rows */
793     for( i=2; i<4; i++ )
794     {
795         subpanel_sizer = new wxFlexGridSizer( 2, 1, 20 );
796         label = new wxStaticText( net_subpanels[i], -1, wxU(_("URL")) );
797         net_addrs[i] = new wxTextCtrl( net_subpanels[i], NetAddr1_Event + i,
798                                        (i == 2) ? wxT("") : wxT("rtsp://"),
799                                        wxDefaultPosition, wxSize( 200, -1 ),
800                                        wxTE_PROCESS_ENTER);
801         subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
802         subpanel_sizer->Add( net_addrs[i], 1,
803                              wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
804         net_subpanels[i]->SetSizerAndFit( subpanel_sizer );
805     }
806
807     /* Stuff everything into the main panel */
808     for( i=0; i<4; i++ )
809     {
810         sizer->Add( net_radios[i], 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
811                     wxALL, 5 );
812         sizer->Add( net_subpanels[i], 1, wxEXPAND | wxALIGN_LEFT |
813                     wxALIGN_CENTER_VERTICAL | wxALL, 5  );
814     }
815     sizer->Add( net_timeshift, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
816                 wxALL, 5 );
817
818     sizer_row->Add( sizer, 0, wxEXPAND | wxALL, 5 );
819
820     panel->SetSizerAndFit( sizer_row );
821     return panel;
822 }
823
824 void OpenDialog::UpdateMRL()
825 {
826     UpdateMRL( i_current_access_method );
827 }
828
829 void OpenDialog::UpdateMRL( int i_access_method )
830 {
831     wxString mrltemp, caching_name;
832
833     i_current_access_method = i_access_method;
834
835     switch( i_access_method )
836     {
837     case FILE_ACCESS:
838         mrltemp = file_combo->GetValue();
839         caching_name = wxT("file-caching");
840         break;
841
842     case DISC_ACCESS:
843         i_disc_type_selection = disc_type->GetSelection();
844
845         switch ( i_disc_type_selection )
846         {
847         case 0: /* DVD with menus */
848         case 1: /* DVD without menus */
849             disc_device->SetToolTip( wxU(_("Name of DVD device "
850             "to read from.")) );
851             if( i_disc_type_selection == 0 )
852             {
853                 mrltemp = wxT("dvd://") + disc_device->GetValue();
854                 caching_name = wxT("dvdnav-caching");
855             }
856             else
857             {
858                 mrltemp = wxT("dvdsimple://") + disc_device->GetValue();
859                 caching_name = wxT("dvdread-caching");
860             }
861
862             if( i_disc_title > 0 )
863             {
864                 mrltemp += wxString::Format( wxT("@%d"), i_disc_title );
865
866                 if( i_disc_chapter > 0 )
867                     mrltemp += wxString::Format( wxT(":%d"), i_disc_chapter );
868             }
869
870             if( i_disc_sub >= 0 )
871                 mrltemp += wxString::Format( wxT("  :sub-track=%d"),
872                                              i_disc_sub );
873             if( i_disc_audio >= 0 )
874                 mrltemp += wxString::Format( wxT("  :audio-track=%d"),
875                                              i_disc_audio );
876             break;
877
878         case 2:  /* VCD of some sort */
879 #ifdef HAVE_VCDX
880             disc_device->SetToolTip( wxU(_("Name of CD-ROM device "
881             "to read Video CD from. If this field is left empty, we will scan "
882             "for a CD-ROM with a VCD in it.")) );
883             mrltemp = wxT("vcdx://") + disc_device->GetValue();
884             if( i_disc_title > 0 )
885                 mrltemp += wxString::Format( wxT("@%c%d"),
886                                   config_GetInt( p_intf, "vcdx-PBC"  )
887                                   ? 'P' : 'E', i_disc_title );
888 #else
889             disc_device->SetToolTip( wxU(_("Name of CD-ROM device "
890             "to read Video CD from.")) );
891             mrltemp = wxT("vcd://") + disc_device->GetValue();
892             if( i_disc_title > 0 )
893                 mrltemp += wxString::Format( wxT("@%d"), i_disc_title );
894 #endif
895
896             if( i_disc_sub >= 0 )
897                 mrltemp += wxString::Format( wxT("  :sub-track=%d"),
898                                              i_disc_sub );
899
900             if( i_disc_audio >= 0 )
901                 mrltemp += wxString::Format( wxT("  :audio-track=%d"),
902                                              i_disc_audio );
903             caching_name = wxT("vcd-caching");
904             break;
905
906         case 3: /* CD-DA */
907 #ifdef HAVE_CDDAX
908             disc_device->SetToolTip( wxU(_("Name of CD-ROM device "
909             "to read audio CD from. If this field is left empty, we will scan "
910             "for a CD-ROM with an audio CD in it." )) );
911             mrltemp = wxT("cddax://") 
912 #else
913             disc_device->SetToolTip( wxU(_("Name of CD-ROM device "
914             "to read audio CD from." )) );
915             mrltemp = wxT("cdda://") 
916 #endif
917               + disc_device->GetValue();
918             if( i_disc_title > 0 )
919                 mrltemp += wxString::Format( wxT("@%d"), i_disc_title );
920
921             caching_name = wxT("cdda-caching");
922             break;
923
924         default:
925             msg_Err( p_intf, "invalid selection (%d)",
926                      disc_type->GetSelection() );
927         }
928
929         break;
930
931     case NET_ACCESS:
932         switch( i_net_type )
933         {
934         case 0:
935             mrltemp = wxT("udp://@");
936             if ( net_ipv6->GetValue() )
937             {
938                 mrltemp += wxT("[::]");
939             }
940             if( i_net_ports[0] !=
941                 config_GetInt( p_intf, "server-port" ) )
942             {
943                 mrltemp += wxString::Format( wxT(":%d"), i_net_ports[0] );
944             }
945
946             caching_name = wxT("udp-caching");
947             break;
948
949         case 1:
950             mrltemp = wxT("udp://@");
951             if ((net_addrs[1]->GetLineText(0).Find (':') != -1)
952                 && (net_addrs[1]->GetLineText(0)[0u] != '['))
953             {
954                 /* automatically adds '[' and ']' to IPv6 addresses */
955                 mrltemp += wxT("[") + net_addrs[1]->GetLineText(0)
956                          + wxT("]");
957             }
958             else
959             {
960                 mrltemp += net_addrs[1]->GetLineText(0);
961             }
962             if( i_net_ports[1] != config_GetInt( p_intf, "server-port" ) )
963             {
964                 mrltemp += wxString::Format( wxT(":%d"), i_net_ports[1] );
965             }
966
967             caching_name = wxT("udp-caching");
968             break;
969
970         case 2:
971             /* http access */
972             if( net_addrs[2]->GetLineText(0).Find(wxT("://")) == -1 )
973                 mrltemp = wxT("http://");
974
975             mrltemp += net_addrs[2]->GetLineText(0);
976
977             caching_name = wxT("http-caching");
978             break;
979
980         case 3:
981             /* RTSP access */
982             if( net_addrs[3]->GetLineText(0).Find(wxT("rtsp://")) != 0 )
983             {
984                 mrltemp = wxT("rtsp://");
985             }
986             mrltemp += net_addrs[3]->GetLineText(0);
987
988             caching_name = wxT("rtsp-caching");
989             break;
990         }
991         if( net_timeshift->IsEnabled() && net_timeshift->IsChecked() )
992             mrltemp += wxT(" :access-filter=timeshift");
993         break;
994
995     default:
996         {
997             int i_item = i_access_method - MAX_ACCESS;
998
999             if( i_item < 0 || i_item >= (int)input_tab_array.GetCount() )
1000                 break;
1001
1002             AutoBuiltPanel *input_panel = input_tab_array.Item( i_item );
1003
1004             mrltemp = input_panel->name + wxT("://");
1005
1006             for( int i=0; i < (int)input_panel->config_array.GetCount(); i++ )
1007             {
1008                 ConfigControl *control = input_panel->config_array.Item(i);
1009
1010                 mrltemp += wxT(" :");
1011
1012                 if( control->GetType() == CONFIG_ITEM_BOOL &&
1013                     !control->GetIntValue() ) mrltemp += wxT("no-");
1014
1015                 mrltemp += control->GetName();
1016
1017                 switch( control->GetType() )
1018                 {
1019                 case CONFIG_ITEM_STRING:
1020                 case CONFIG_ITEM_FILE:
1021                 case CONFIG_ITEM_DIRECTORY:
1022                 case CONFIG_ITEM_MODULE:
1023                     mrltemp += wxT("=\"") + control->GetPszValue() + wxT("\"");
1024                     break;
1025                 case CONFIG_ITEM_INTEGER:
1026                     mrltemp +=
1027                         wxString::Format( wxT("=%i"), control->GetIntValue() );
1028                     break;
1029                 case CONFIG_ITEM_FLOAT:
1030                     mrltemp +=
1031                         wxString::Format(wxT("=%f"), control->GetFloatValue());
1032                     break;
1033                 }
1034             }
1035
1036             if( input_panel->p_advanced_mrl_combo &&
1037                 input_panel->p_advanced_mrl_combo->GetValue() )
1038             {
1039                 mrltemp += wxT(" ") +
1040                     input_panel->p_advanced_mrl_combo->GetValue();
1041             }
1042         }
1043         break;
1044     }
1045
1046     if( caching_name.size() )
1047     {
1048         if( caching_value->IsEnabled() )
1049         {
1050             mrltemp += wxT("  :") + caching_name +
1051                 wxString::Format( wxT("=%d"), i_caching );
1052         }
1053         else
1054         {
1055             int i_value = config_GetInt( p_intf, caching_name.mb_str() );
1056             caching_value->SetValue( i_value );
1057         }
1058     }
1059
1060     mrl_combo->SetValue( mrltemp );
1061 }
1062
1063 /*****************************************************************************
1064  * Events methods.
1065  *****************************************************************************/
1066 void OpenDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
1067 {
1068     mrl = SeparateEntries( mrl_combo->GetValue() );
1069     mrl_combo->Append( mrl_combo->GetValue() );
1070     if( mrl_combo->GetCount() > 10 ) mrl_combo->Delete( 0 );
1071     mrl_combo->SetSelection( mrl_combo->GetCount() - 1 );
1072
1073     if( i_method == OPEN_STREAM )
1074     {
1075         if( IsModal() ) EndModal( wxID_OK );
1076         Hide();
1077         return;
1078     }
1079
1080     /* Update the playlist */
1081     playlist_t *p_playlist =
1082         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1083                                        FIND_ANYWHERE );
1084     if( p_playlist == NULL ) return;
1085
1086     for( int i = 0; i < (int)mrl.GetCount(); i++ )
1087     {
1088         vlc_bool_t b_start = !i && i_open_arg;
1089         playlist_item_t *p_item =
1090             playlist_ItemNew( p_intf, (const char*)mrl[i].mb_str(),
1091                               (const char *)mrl[i].mb_str() );
1092
1093         /* Insert options */
1094         while( i + 1 < (int)mrl.GetCount() &&
1095                ((const char *)mrl[i + 1].mb_str())[0] == ':' )
1096         {
1097             playlist_ItemAddOption( p_item, mrl[i + 1].mb_str() );
1098             i++;
1099         }
1100
1101         /* Get the options from the subtitles dialog */
1102         if( subsfile_checkbox->IsChecked() && subsfile_mrl.GetCount() )
1103         {
1104             for( int j = 0; j < (int)subsfile_mrl.GetCount(); j++ )
1105             {
1106                 playlist_ItemAddOption( p_item, subsfile_mrl[j].mb_str() );
1107             }
1108         }
1109
1110         /* Get the options from the stream output dialog */
1111         if( sout_checkbox->IsChecked() && sout_mrl.GetCount() )
1112         {
1113             for( int j = 0; j < (int)sout_mrl.GetCount(); j++ )
1114             {
1115                 playlist_ItemAddOption( p_item, sout_mrl[j].mb_str() );
1116             }
1117         }
1118
1119         playlist_AddItem( p_playlist, p_item,
1120                           PLAYLIST_APPEND, PLAYLIST_END );
1121
1122         if( b_start )
1123         {
1124             playlist_Control( p_playlist, PLAYLIST_ITEMPLAY , p_item );
1125         }
1126     }
1127
1128     vlc_object_release( p_playlist );
1129
1130     Hide();
1131
1132     if( IsModal() ) EndModal( wxID_OK );
1133 }
1134
1135 void OpenDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
1136 {
1137     wxCloseEvent cevent;
1138     OnClose(cevent);
1139 }
1140
1141 void OpenDialog::OnClose( wxCloseEvent& WXUNUSED(event) )
1142 {
1143     Hide();
1144
1145     if( IsModal() ) EndModal( wxID_CANCEL );
1146 }
1147
1148 void OpenDialog::OnPageChange( wxNotebookEvent& event )
1149 {
1150     UpdateMRL( event.GetSelection() );
1151 }
1152
1153 void OpenDialog::OnMRLChange( wxCommandEvent& event )
1154 {
1155     //mrl = SeparateEntries( event.GetString() );
1156 }
1157
1158 /*****************************************************************************
1159  * File panel event methods.
1160  *****************************************************************************/
1161 void OpenDialog::OnFilePanelChange( wxCommandEvent& WXUNUSED(event) )
1162 {
1163     UpdateMRL( FILE_ACCESS );
1164 }
1165
1166 void OpenDialog::OnFileBrowse( wxCommandEvent& WXUNUSED(event) )
1167 {
1168     if( file_dialog == NULL )
1169         file_dialog = new wxFileDialog( this, wxU(_("Open File")),
1170             wxT(""), wxT(""), wxT("*"), wxOPEN | wxMULTIPLE );
1171
1172     if( file_dialog && file_dialog->ShowModal() == wxID_OK )
1173     {
1174         wxArrayString paths;
1175         wxString path;
1176
1177         file_dialog->GetPaths( paths );
1178
1179         for( size_t i = 0; i < paths.GetCount(); i++ )
1180         {
1181             if( paths[i].Find( wxT(' ') ) >= 0 )
1182                 path += wxT("\"") + paths[i] + wxT("\" ");
1183             else
1184                 path += paths[i] + wxT(" ");
1185         }
1186
1187         file_combo->SetValue( path );
1188         file_combo->Append( path );
1189         if( file_combo->GetCount() > 10 ) file_combo->Delete( 0 );
1190         UpdateMRL( FILE_ACCESS );
1191     }
1192 }
1193
1194 /*****************************************************************************
1195  * Disc panel event methods.
1196  *****************************************************************************/
1197 void OpenDialog::OnDiscPanelChangeSpin( wxSpinEvent& event )
1198 {
1199     wxCommandEvent cevent;
1200     cevent.SetId(event.GetId());
1201     cevent.SetInt(event.GetPosition());
1202     OnDiscPanelChange(cevent);
1203 }
1204
1205 void OpenDialog::OnDiscPanelChange( wxCommandEvent& event )
1206 {
1207     if( event.GetId() == DiscTitle_Event ) i_disc_title = event.GetInt();
1208     if( event.GetId() == DiscChapter_Event ) i_disc_chapter = event.GetInt();
1209     if( event.GetId() == DiscSub_Event ) i_disc_sub = event.GetInt();
1210     if( event.GetId() == DiscAudio_Event ) i_disc_audio = event.GetInt();
1211
1212     UpdateMRL( DISC_ACCESS );
1213 }
1214
1215 void OpenDialog::OnDiscDeviceChange( wxCommandEvent& event )
1216 {
1217     char *psz_device;
1218
1219     switch( disc_type->GetSelection() )
1220     {
1221         case 3:
1222             psz_device = config_GetPsz( p_intf, "cd-audio" );
1223             break;
1224
1225         case 2:
1226             psz_device = config_GetPsz( p_intf, "vcd" );
1227             break;
1228
1229         default:
1230             psz_device = config_GetPsz( p_intf, "dvd" );
1231             break;
1232     }
1233
1234     if ( !psz_device ) psz_device = "";
1235
1236     if( disc_device->GetValue().Cmp( wxL2U( psz_device ) ) )
1237     {
1238         b_disc_device_changed = true;
1239     }
1240
1241     UpdateMRL( DISC_ACCESS );
1242 }
1243
1244 #ifdef HAVE_LIBCDIO
1245
1246 /* Return a device that has a DVD in it. The caller needs to free
1247    the returned string.
1248 */
1249 static char * ProbeDVD()
1250 {
1251   char **ppsz_cd_drives = cdio_get_devices(DRIVER_DEVICE);
1252   if (ppsz_cd_drives) 
1253   {
1254       char **c;
1255       for( c = ppsz_cd_drives; *c != NULL; c++ ) 
1256       {
1257           CdIo_t *p_cdio = cdio_open (*c, DRIVER_UNKNOWN);
1258           if (p_cdio) 
1259           {
1260               discmode_t discmode = cdio_get_discmode(p_cdio);
1261               cdio_destroy(p_cdio);
1262               if( cdio_is_discmode_dvd(discmode) )
1263               {
1264                   char *psz_drive = strdup(*c);
1265                   cdio_free_device_list(ppsz_cd_drives);
1266                   return strdup(psz_drive);
1267               }
1268           }
1269         
1270       }
1271       cdio_free_device_list(ppsz_cd_drives);
1272   }
1273   return NULL;
1274 }
1275
1276
1277 static char * ProbeDevice(char **search_devices, cdio_fs_anal_t mask, 
1278                           bool b_any)
1279 {
1280     char **ppsz_devices;
1281
1282     /* Start out trying the device that has been entered so far. */
1283     ppsz_devices = cdio_get_devices_with_cap(search_devices, mask, b_any);
1284      
1285     if (ppsz_devices && *ppsz_devices) 
1286     {
1287         char *psz_device = strdup(*ppsz_devices);
1288         cdio_free_device_list(ppsz_devices);
1289         return psz_device;
1290     }
1291
1292     /* If there was no device specified on the first try then give up
1293        now. Otherwise accept any CD-ROM in the class (e.g. VCD or DVD).
1294     */
1295     if (!search_devices[0]) return NULL;
1296
1297     ppsz_devices = cdio_get_devices_with_cap(NULL, mask, b_any);
1298      
1299     if (ppsz_devices && *ppsz_devices) 
1300     {
1301         char *psz_device = strdup(*ppsz_devices);
1302         cdio_free_device_list(ppsz_devices);
1303         return psz_device;
1304     }
1305
1306     return NULL;
1307 }
1308
1309
1310 /* Return a device that has a CD-DA in it. The caller needs to free
1311    the returned string.
1312 */
1313 static char * ProbeCDDA(const wxChar *device)
1314 {
1315    char *ppsz_device[2];
1316    const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(device);
1317    char *psz_device = (char *) tmp_buf;
1318    ppsz_device[0] = (device && *device) ? psz_device : NULL;
1319    ppsz_device[1] = NULL;
1320    return ProbeDevice(ppsz_device, CDIO_FS_AUDIO, false);
1321 }
1322
1323 /* Return a device that has a VCD in it. The caller needs to free
1324    the returned string.
1325 */
1326 static char * ProbeVCD(const wxChar *device)
1327 {
1328    char *ppsz_device[2];
1329    const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(device);
1330    char *psz_device = (char *) tmp_buf;
1331    ppsz_device[0] = (device && *device) ? psz_device : NULL;
1332    ppsz_device[1] = NULL;
1333    return ProbeDevice(ppsz_device, 
1334                       (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD|CDIO_FS_ANAL_VIDEOCD
1335                        |CDIO_FS_UNKNOWN), true);
1336 }
1337
1338
1339 /* 
1340    Probe (find anywhere) a CD-DA, VCD, or a DVD.
1341    First we try the device name that may have been entered for the media class
1342    selected. If that doesn't work we try any device for the media class.
1343    If that doesn't work the try looking for CD-ROMs or DVD drives and set the
1344    media selection to whatever we find.
1345 */
1346 void OpenDialog::OnDiscProbe( wxCommandEvent& WXUNUSED(event) )
1347 {
1348     wxCommandEvent dummy_event;
1349     char *psz_device = NULL;
1350     bool b_probed_DVD = false;
1351     bool b_probed_VCD = false;
1352
1353  retry:
1354     switch( disc_type->GetSelection() )
1355     {
1356
1357     case 0: /* DVD with menus */
1358     case 1: /* DVD without menus */
1359       /* If not a DVD then try for a VCD. If VCD fails it will
1360          try for a CD-DA. */
1361       if (!psz_device) psz_device = ProbeDVD();
1362       if (!psz_device)
1363       {
1364           b_probed_DVD = true;
1365           disc_type->SetSelection(2);
1366           OnDiscTypeChange( dummy_event );
1367           goto retry;
1368       }
1369       disc_device->SetValue( wxL2U(psz_device) );
1370       free(psz_device);
1371       break;
1372
1373     case 2:  /* VCD probe of some sort */
1374       if(!psz_device) psz_device = ProbeVCD(disc_device->GetValue());
1375       if( psz_device  ) 
1376       {
1377           CdIo_t *p_cdio = cdio_open (psz_device, DRIVER_UNKNOWN);
1378           disc_device->SetValue( wxL2U(psz_device) );
1379
1380           /* Set track range accurately if possible. */
1381           if (p_cdio) 
1382           {
1383               track_t i_last_track = cdio_get_last_track_num(p_cdio);
1384               disc_title->SetRange( 0, i_last_track-1 );  
1385           }
1386           free(psz_device);
1387           cdio_destroy(p_cdio);
1388           break;
1389       }
1390
1391       b_probed_VCD = true;
1392
1393       /* Not a VCD. Try for a DVD unless we've been there before. */
1394       if( !b_probed_DVD && (psz_device = ProbeDVD()) ) 
1395       {
1396           disc_type->SetSelection(0);
1397           OnDiscTypeChange( dummy_event );
1398           goto retry;
1399       }
1400       b_probed_DVD = true;
1401       
1402       /* Couldn't find a VCD or DVD. See if we can find a CD-DA. */
1403       psz_device = ProbeCDDA(disc_device->GetValue());
1404       if( psz_device  ) 
1405       {
1406           disc_type->SetSelection(3);
1407           OnDiscTypeChange( dummy_event );
1408           goto retry;
1409       }
1410       break;
1411
1412     case 3: /* CD-DA Probe */
1413       if(!psz_device) psz_device = ProbeCDDA(disc_device->GetValue());
1414       if( psz_device  ) 
1415       {
1416           CdIo_t *p_cdio = cdio_open (psz_device, DRIVER_UNKNOWN);
1417           disc_device->SetValue( wxL2U(psz_device) );
1418           if (p_cdio) 
1419           {
1420               track_t i_last_track = cdio_get_last_track_num(p_cdio);
1421               disc_title->SetRange( 0, i_last_track );  
1422           }
1423           free(psz_device);
1424           cdio_destroy(p_cdio);
1425           break;
1426       }
1427
1428       /* Not a CD-DA. Try for a DVD unless we've been there before. */
1429       if( !b_probed_DVD && (psz_device = ProbeDVD()) ) 
1430       {
1431           disc_type->SetSelection(0);
1432           OnDiscTypeChange( dummy_event );
1433           goto retry;
1434       }
1435       
1436       /* Couldn't find a CD-DA or DVD. See if we can find a VCD, unless
1437          we've tried that before. */
1438       if (!b_probed_VCD) psz_device = ProbeVCD(disc_device->GetValue());
1439       if( psz_device  ) 
1440       {
1441           disc_type->SetSelection(2);
1442           OnDiscTypeChange( dummy_event );
1443           goto retry;
1444       }
1445       break;
1446
1447     default:
1448         msg_Err( p_intf, "invalid Disc type selection (%d)",
1449                  disc_type->GetSelection() );
1450         break;
1451     }
1452
1453     disc_probe->SetValue(FALSE);
1454    
1455     UpdateMRL( DISC_ACCESS );
1456 }
1457 #endif /* HAVE_LIBCDIO */
1458
1459 void OpenDialog::OnDiscTypeChange( wxCommandEvent& WXUNUSED(event) )
1460 {
1461     char *psz_device = NULL;
1462
1463     switch( disc_type->GetSelection() )
1464     {
1465
1466     case 0: /* DVD with menus */
1467     case 1: /* DVD without menus */
1468         disc_sub->Enable(); disc_sub_label->Enable();
1469         disc_audio->Enable(); disc_audio_label->Enable();
1470         disc_chapter->Enable(); disc_chapter_label->Enable();
1471         disc_title_label->SetLabel ( wxU(_("Title")) );
1472         psz_device = config_GetPsz( p_intf, "dvd" );
1473         if( !b_disc_device_changed )
1474         {
1475             if( psz_device ) disc_device->SetValue( wxL2U(psz_device) );
1476             else disc_device->SetValue( wxT("") );
1477         }
1478         disc_title->SetRange( 0, 255 );
1479         disc_sub->SetRange( -1, 31 );  // up to 32 subtitles -1: no subtitle
1480         disc_audio->SetRange( 0, 7 );  // up to 8 audio channels
1481         disc_chapter->SetRange( 0, 255 );
1482         disc_title->SetToolTip( wxU(_("Title number.")) );
1483         disc_sub->SetToolTip( wxU(_(
1484           "DVD's can have up to 32 subtitles numbered 0..31. "
1485           "Note this is not the same thing as a subtitle name e.g. 'en'. "
1486           "If a value -1 is used, no subtitle will be shown." )) );
1487         disc_audio->SetToolTip( wxU(_("Audio track number. "
1488           "DVD's can have up to 8 audio tracks numbered 0..7."
1489         )) );
1490         break;
1491
1492     case 2:  /* VCD of some sort */
1493         disc_sub->Enable(); disc_sub_label->Enable();
1494         disc_audio->Enable(); disc_audio_label->Enable();
1495         disc_chapter->Disable(); disc_chapter_label->Disable();
1496         psz_device = config_GetPsz( p_intf, "vcd" );
1497         if( !b_disc_device_changed )
1498         {
1499             if( psz_device ) disc_device->SetValue( wxL2U(psz_device) );
1500             else disc_device->SetValue( wxT("") );
1501         }
1502
1503 #ifdef HAVE_VCDX
1504         if (config_GetInt( p_intf, "vcdx-PBC"  )) 
1505         {
1506           disc_title_label->SetLabel ( wxT("Playback LID") );
1507           disc_title->SetToolTip( wxU(_(
1508           "Playback control (PBC) usually starts with number 1." )) );
1509         } 
1510         else 
1511         {
1512           disc_title_label->SetLabel ( wxT("Entry") );
1513           disc_title->SetToolTip( wxU(_(
1514           "The first entry (the beginning of the first MPEG track) is 0." )) );
1515         }
1516         
1517 #else
1518         disc_title_label->SetLabel ( wxU(_("Track")) );
1519         disc_title->SetToolTip( wxU(_("Track number.")) );
1520 #endif
1521         disc_title->SetRange( 0, 99 );  // only 100 tracks allowed on VCDs
1522         disc_sub->SetRange( -1, 3 );    // up to 4 subtitles -1 = no subtitle
1523         disc_audio->SetRange( 0, 1 );   // up to 2 audio tracks
1524         disc_sub->SetToolTip( wxU(_(
1525           "SVCD's can have up to 4 subtitles numbered 0..3. "
1526           "If a value -1 is used, no subtitle will be shown." )) );
1527         disc_audio->SetToolTip( wxU(_("Audio track number. "
1528           "VCD's can have up to 2 audio tracks numbered 0 or 1. "
1529         )) );
1530         break;
1531
1532     case 3: /* CD-DA */
1533         disc_sub->Disable(); disc_sub_label->Disable();
1534         disc_chapter->Disable(); disc_chapter_label->Disable();
1535         disc_audio->Disable(); disc_audio_label->Disable();
1536         disc_title_label->SetLabel ( wxU(_("Track")) );
1537 #ifdef HAVE_CDDAX
1538         disc_title->SetToolTip( wxU(_(
1539         "Audio CDs can have up to 100 tracks, the first track is usually 1. "
1540         "If 0 is given, then all tracks are played.")) );
1541 #else
1542         disc_title->SetToolTip( wxU(_(
1543         "Audio CDs can have up to 100 tracks, the first track is usually 1."
1544         )) );
1545 #endif
1546         psz_device = config_GetPsz( p_intf, "cd-audio" );
1547         if( !b_disc_device_changed )
1548         {
1549             if( psz_device ) disc_device->SetValue( wxL2U(psz_device) );
1550             else disc_device->SetValue( wxT("") );
1551         }
1552
1553         /* There are at most 100 tracks in a CD-DA */
1554         disc_title->SetRange( 0, 100 );
1555         break;
1556
1557     default:
1558         msg_Err( p_intf, "invalid Disc type selection (%d)",
1559                  disc_type->GetSelection() );
1560         break;
1561     }
1562
1563     disc_title->SetValue( 0 ); i_disc_title = 0;
1564     disc_chapter->SetValue( 0 ); i_disc_chapter = 0;
1565
1566     if( psz_device ) free( psz_device );
1567
1568     UpdateMRL( DISC_ACCESS );
1569 }
1570
1571 /*****************************************************************************
1572  * Net panel event methods.
1573  *****************************************************************************/
1574 void OpenDialog::OnNetPanelChangeSpin( wxSpinEvent& event )
1575 {
1576     wxCommandEvent cevent;
1577     cevent.SetId(event.GetId());
1578     cevent.SetInt(event.GetPosition());
1579     OnNetPanelChange(cevent);
1580 }
1581
1582 void OpenDialog::OnNetPanelChange( wxCommandEvent& event )
1583 {
1584     if( event.GetId() >= NetPort1_Event && event.GetId() <= NetPort3_Event )
1585     {
1586         i_net_ports[event.GetId() - NetPort1_Event] = event.GetInt();
1587     }
1588
1589     UpdateMRL( NET_ACCESS );
1590 }
1591
1592 void OpenDialog::OnNetTypeChange( wxCommandEvent& event )
1593 {
1594     int i;
1595
1596     i_net_type = event.GetId() - NetRadio1_Event;
1597
1598     for(i=0; i<4; i++)
1599     {
1600         net_radios[i]->SetValue( event.GetId() == (NetRadio1_Event+i) );
1601         net_subpanels[i]->Enable( event.GetId() == (NetRadio1_Event+i) );
1602     }
1603     /* UDP Unicast or multicast -> timeshift */
1604     if( i_net_type == 0 || i_net_type == 1 )
1605         net_timeshift->Enable();
1606     else
1607         net_timeshift->Disable();
1608
1609     UpdateMRL( NET_ACCESS );
1610 }
1611
1612 /*****************************************************************************
1613  * Subtitles file event methods.
1614  *****************************************************************************/
1615 void OpenDialog::OnSubsFileEnable( wxCommandEvent& event )
1616 {
1617     subsfile_button->Enable( event.GetInt() != 0 );
1618 }
1619
1620 void OpenDialog::OnSubsFileSettings( wxCommandEvent& WXUNUSED(event) )
1621 {
1622     /* Show/hide the open dialog */
1623     if( subsfile_dialog == NULL )
1624         subsfile_dialog = new SubsFileDialog( p_intf, this );
1625
1626     if( subsfile_dialog && subsfile_dialog->ShowModal() == wxID_OK )
1627     {
1628         subsfile_mrl.Empty();
1629         subsfile_mrl.Add( wxString(wxT("sub-file=")) +
1630                           subsfile_dialog->file_combo->GetValue() );
1631         if( subsfile_dialog->encoding_combo )
1632         {
1633             subsfile_mrl.Add( wxString(wxT("subsdec-encoding=")) +
1634                               subsfile_dialog->encoding_combo->GetValue() );
1635         }
1636         if( subsfile_dialog->align_combo )
1637         {
1638             subsfile_mrl.Add( wxString::Format(wxT("subsdec-align=%i"),
1639                               (int)subsfile_dialog->align_combo->GetClientData(
1640                               subsfile_dialog->align_combo->GetSelection()) ) );
1641         }
1642         if( subsfile_dialog->size_combo )
1643         {
1644             subsfile_mrl.Add( wxString::Format( wxT("freetype-rel-fontsize=%i"),
1645                               (int)subsfile_dialog->size_combo->GetClientData(
1646                               subsfile_dialog->size_combo->GetSelection()) ) );
1647         }
1648         subsfile_mrl.Add( wxString::Format( wxT("sub-fps=%i"),
1649                           subsfile_dialog->fps_spinctrl->GetValue() ) );
1650         subsfile_mrl.Add( wxString::Format( wxT("sub-delay=%i"),
1651                           subsfile_dialog->delay_spinctrl->GetValue() ) );
1652     }
1653 }
1654
1655 /*****************************************************************************
1656  * Stream output event methods.
1657  *****************************************************************************/
1658 void OpenDialog::OnSoutEnable( wxCommandEvent& event )
1659 {
1660     sout_button->Enable( event.GetInt() != 0 );
1661 }
1662
1663 void OpenDialog::OnSoutSettings( wxCommandEvent& WXUNUSED(event) )
1664 {
1665     /* Show/hide the open dialog */
1666     if( sout_dialog == NULL )
1667         sout_dialog = new SoutDialog( p_intf, this );
1668
1669     if( sout_dialog && sout_dialog->ShowModal() == wxID_OK )
1670     {
1671         sout_mrl = sout_dialog->GetOptions();
1672     }
1673 }
1674
1675 /*****************************************************************************
1676  * Caching event methods.
1677  *****************************************************************************/
1678 void OpenDialog::OnCachingEnable( wxCommandEvent& event )
1679 {
1680     caching_value->Enable( event.GetInt() != 0 );
1681     i_caching = caching_value->GetValue();
1682     UpdateMRL();
1683 }
1684
1685 void OpenDialog::OnCachingChangeSpin( wxSpinEvent& event )
1686 {
1687     wxCommandEvent cevent;
1688     OnCachingChange(cevent);
1689 }
1690
1691 void OpenDialog::OnCachingChange( wxCommandEvent& event )
1692 {
1693     i_caching = event.GetInt();
1694     UpdateMRL();
1695 }
1696
1697 /*****************************************************************************
1698  * Utility functions.
1699  *****************************************************************************/
1700 wxArrayString SeparateEntries( wxString entries )
1701 {
1702     vlc_bool_t b_quotes_mode = VLC_FALSE;
1703
1704     wxArrayString entries_array;
1705     wxString entry;
1706
1707     wxStringTokenizer token( entries, wxT(" \t\r\n\""), wxTOKEN_RET_DELIMS );
1708
1709     while( token.HasMoreTokens() )
1710     {
1711         entry += token.GetNextToken();
1712
1713         if( entry.IsEmpty() ) continue;
1714
1715         if( !b_quotes_mode && entry.Last() == wxT('\"') )
1716         {
1717             /* Enters quotes mode */
1718             entry.RemoveLast();
1719             b_quotes_mode = VLC_TRUE;
1720         }
1721         else if( b_quotes_mode && entry.Last() == wxT('\"') )
1722         {
1723             /* Finished the quotes mode */
1724             entry.RemoveLast();
1725             b_quotes_mode = VLC_FALSE;
1726         }
1727         else if( !b_quotes_mode && entry.Last() != wxT('\"') )
1728         {
1729             /* we found a non-quoted standalone string */
1730             if( token.HasMoreTokens() ||
1731                 entry.Last() == wxT(' ') || entry.Last() == wxT('\t') ||
1732                 entry.Last() == wxT('\r') || entry.Last() == wxT('\n') )
1733                 entry.RemoveLast();
1734             if( !entry.IsEmpty() ) entries_array.Add( entry );
1735             entry.Empty();
1736         }
1737         else
1738         {;}
1739     }
1740
1741     if( !entry.IsEmpty() ) entries_array.Add( entry );
1742
1743     return entries_array;
1744 }