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