lower case the module_* functions
[vlc.git] / modules / gui / wxwidgets / dialogs / preferences.cpp
1 /*****************************************************************************
2  * preferences.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include "dialogs/preferences.hpp"
29 #include <vlc_config_cat.h>
30 #include "dialogs/preferences_widgets.h"
31
32 #include <wx/combobox.h>
33 #include <wx/statline.h>
34 #include <wx/clntdata.h>
35 #include <wx/dynarray.h>
36 #include <wx/imaglist.h>
37 #include <wx/treectrl.h>
38
39 #include "bitmaps/type_net.xpm"
40 #include "bitmaps/codec.xpm"
41 #include "bitmaps/video.xpm"
42 #include "bitmaps/type_playlist.xpm"
43 #include "bitmaps/advanced.xpm"
44 #include "bitmaps/intf.xpm"
45 #include "bitmaps/audio.xpm"
46
47 #ifndef wxRB_SINGLE
48 #   define wxRB_SINGLE 0
49 #endif
50
51 #define TYPE_CATEGORY 0
52 #define TYPE_CATSUBCAT 1  /* Category with embedded subcategory */
53 #define TYPE_SUBCATEGORY 2
54 #define TYPE_MODULE 3
55
56 /*****************************************************************************
57  * Classes declarations.
58  *****************************************************************************/
59 class ConfigTreeData;
60 class PrefsTreeCtrl : public wxTreeCtrl
61 {
62 public:
63
64     PrefsTreeCtrl() { }
65     PrefsTreeCtrl( wxWindow *parent, intf_thread_t *_p_intf,
66                    PrefsDialog *p_prefs_dialog, wxBoxSizer *_p_sizer );
67     virtual ~PrefsTreeCtrl();
68
69     void ApplyChanges();
70     void CleanChanges();
71
72 private:
73     /* Event handlers (these functions should _not_ be virtual) */
74     void OnSelectTreeItem( wxTreeEvent& event );
75     void OnAdvanced( wxCommandEvent& event );
76
77     ConfigTreeData *FindModuleConfig( ConfigTreeData *config_data );
78
79     DECLARE_EVENT_TABLE()
80
81     intf_thread_t *p_intf;
82     PrefsDialog *p_prefs_dialog;
83     wxBoxSizer *p_sizer;
84     wxWindow *p_parent;
85     bool b_advanced;
86
87     wxPanel *p_current;
88
89     wxTreeItemId root_item;
90     wxTreeItemId plugins_item;
91 };
92
93 WX_DEFINE_ARRAY(ConfigControl *, ArrayOfConfigControls);
94
95 class PrefsPanel : public wxPanel
96 {
97 public:
98
99     PrefsPanel() { }
100     PrefsPanel( wxWindow *parent, intf_thread_t *_p_intf,
101                 PrefsDialog *, ConfigTreeData* );
102     virtual ~PrefsPanel() {}
103
104     void ApplyChanges();
105     void SwitchAdvanced( bool );
106
107 private:
108     intf_thread_t *p_intf;
109     PrefsDialog *p_prefs_dialog;
110
111     bool b_advanced;
112
113     wxStaticText *hidden_text;
114     wxBoxSizer *config_sizer;
115     wxScrolledWindow *config_window;
116
117     ArrayOfConfigControls config_array;
118 };
119
120 class ConfigTreeData : public wxTreeItemData
121 {
122 public:
123
124     ConfigTreeData() { b_submodule = 0; panel = NULL; psz_name = NULL;
125                        psz_help = NULL; }
126     virtual ~ConfigTreeData() {
127                                  delete panel;
128                                  free( psz_name );
129                                  free( psz_help );
130                               };
131
132     bool b_submodule;
133
134     PrefsPanel *panel;
135     wxBoxSizer *sizer;
136
137     module_t *p_module;
138     int i_object_id;
139     int i_subcat_id;
140     int i_type;
141     char *psz_name;
142     char *psz_help;
143 };
144
145 /*****************************************************************************
146  * Event Table.
147  *****************************************************************************/
148
149 /* IDs for the controls and the menu commands */
150 enum
151 {
152     Notebook_Event = wxID_HIGHEST,
153     MRL_Event,
154     ResetAll_Event,
155     Advanced_Event,
156 };
157
158 BEGIN_EVENT_TABLE(PrefsDialog, wxFrame)
159     /* Button events */
160     EVT_BUTTON(wxID_OK, PrefsDialog::OnOk)
161     EVT_BUTTON(wxID_CANCEL, PrefsDialog::OnCancel)
162     EVT_BUTTON(wxID_SAVE, PrefsDialog::OnSave)
163     EVT_BUTTON(ResetAll_Event, PrefsDialog::OnResetAll)
164     EVT_CHECKBOX(Advanced_Event, PrefsDialog::OnAdvanced)
165
166     /* Don't destroy the window when the user closes it */
167     EVT_CLOSE(PrefsDialog::OnClose)
168 END_EVENT_TABLE()
169
170 // menu and control ids
171 enum
172 {
173     PrefsTree_Ctrl = wxID_HIGHEST
174 };
175
176 BEGIN_EVENT_TABLE(PrefsTreeCtrl, wxTreeCtrl)
177     EVT_TREE_SEL_CHANGED(PrefsTree_Ctrl, PrefsTreeCtrl::OnSelectTreeItem)
178     EVT_COMMAND(Advanced_Event, wxEVT_USER_FIRST, PrefsTreeCtrl::OnAdvanced)
179 END_EVENT_TABLE()
180
181 /*****************************************************************************
182  * Constructor.
183  *****************************************************************************/
184 PrefsDialog::PrefsDialog( intf_thread_t *_p_intf, wxWindow *p_parent)
185   :  wxFrame( p_parent, -1, wxU(_("Preferences")), wxDefaultPosition,
186               wxSize(700,450), wxDEFAULT_FRAME_STYLE )
187 {
188     /* Initializations */
189     p_intf = _p_intf;
190     SetIcon( *p_intf->p_sys->p_icon );
191
192     /* Create a panel to put everything in */
193     wxPanel *panel = new wxPanel( this, -1 );
194     panel->SetAutoLayout( TRUE );
195
196     /* Create the preferences tree control */
197     wxBoxSizer *controls_sizer = new wxBoxSizer( wxHORIZONTAL );
198     prefs_tree =
199         new PrefsTreeCtrl( panel, p_intf, this, controls_sizer );
200
201     /* Separation */
202     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
203
204 #if 0
205     /* Create the buttons */
206     wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
207     ok_button->SetDefault();
208 #endif
209     wxButton *save_button = new wxButton( panel, wxID_SAVE, wxU(_("&Save")) );
210     save_button->SetDefault();
211     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
212                                             wxU(_("&Cancel")) );
213     wxButton *reset_button = new wxButton( panel, ResetAll_Event,
214                                            wxU(_("Reset All")) );
215
216     wxPanel *dummy_panel = new wxPanel( this, -1 );
217     wxCheckBox *advanced_checkbox =
218         new wxCheckBox( panel, Advanced_Event, wxU(_("Advanced options")) );
219
220     if( config_GetInt( p_intf, "advanced" ) )
221     {
222         advanced_checkbox->SetValue(TRUE);
223         wxCommandEvent dummy_event;
224         dummy_event.SetInt(TRUE);
225         OnAdvanced( dummy_event );
226     }
227
228     /* Place everything in sizers */
229     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
230 #if 0
231     button_sizer->Add( ok_button, 0, wxALL, 5 );
232 #endif
233     button_sizer->Add( save_button, 0, wxALL, 5 );
234     button_sizer->Add( cancel_button, 0, wxALL, 5 );
235     button_sizer->Add( reset_button, 0, wxALL, 5 );
236     button_sizer->Add( dummy_panel, 1, wxALL, 5 );
237     button_sizer->Add( advanced_checkbox, 0, wxALL | wxALIGN_RIGHT |
238                        wxALIGN_CENTER_VERTICAL, 0 );
239     button_sizer->Layout();
240
241     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
242     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
243     panel_sizer->Add( controls_sizer, 1, wxEXPAND | wxALL, 5 );
244     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
245     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
246                       wxALL | wxEXPAND, 5 );
247     panel_sizer->Layout();
248     panel->SetSizer( panel_sizer );
249     main_sizer->Add( panel, 1, wxEXPAND, 0 );
250     main_sizer->Layout();
251     SetSizer( main_sizer );
252 }
253
254 PrefsDialog::~PrefsDialog()
255 {
256 }
257
258 /*****************************************************************************
259  * Private methods.
260  *****************************************************************************/
261
262
263 /*****************************************************************************
264  * Events methods.
265  *****************************************************************************/
266 void PrefsDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
267 {
268     prefs_tree->ApplyChanges();
269     this->Hide();
270     prefs_tree->CleanChanges();
271 }
272
273 void PrefsDialog::OnClose( wxCloseEvent& WXUNUSED(event) )
274 {
275     wxCommandEvent cevent;
276     OnCancel(cevent);
277 }
278
279 void PrefsDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
280 {
281     this->Hide();
282     prefs_tree->CleanChanges();
283 }
284
285 void PrefsDialog::OnSave( wxCommandEvent& WXUNUSED(event) )
286 {
287     prefs_tree->ApplyChanges();
288     config_SaveConfigFile( p_intf, NULL );
289     this->Hide();
290 }
291
292 void PrefsDialog::OnResetAll( wxCommandEvent& WXUNUSED(event) )
293 {
294     wxMessageDialog dlg( this,
295         wxU(_("This will reset your VLC media player preferences.\n"
296               "Are you sure you want to continue?")),
297         wxU(_("Reset Preferences")), wxYES_NO|wxNO_DEFAULT|wxCENTRE );
298
299     if ( dlg.ShowModal() == wxID_YES )
300     {
301         /* TODO: need to reset all the controls */
302         config_ResetAll( p_intf );
303         prefs_tree->CleanChanges();
304         config_SaveConfigFile( p_intf, NULL );
305     }
306 }
307
308 void PrefsDialog::OnAdvanced( wxCommandEvent& event )
309 {
310     wxCommandEvent newevent( wxEVT_USER_FIRST, Advanced_Event );
311     newevent.SetInt( event.GetInt() );
312
313     prefs_tree->AddPendingEvent( newevent );
314 }
315
316 /*****************************************************************************
317  * PrefsTreeCtrl class definition.
318  *****************************************************************************/
319 PrefsTreeCtrl::PrefsTreeCtrl( wxWindow *_p_parent, intf_thread_t *_p_intf,
320                               PrefsDialog *_p_prefs_dialog,
321                               wxBoxSizer *_p_sizer )
322   : wxTreeCtrl( _p_parent, PrefsTree_Ctrl, wxDefaultPosition, wxSize(200,-1),
323                 wxTR_NO_LINES | wxTR_FULL_ROW_HIGHLIGHT |
324                 wxTR_LINES_AT_ROOT | wxTR_HIDE_ROOT |
325                 wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS | wxSUNKEN_BORDER )
326 {
327     vlc_list_t      *p_list = NULL;;
328     module_t        *p_module;
329     module_config_t *p_item, *p_end;
330     int i_index, i_image=0;
331
332     /* Initializations */
333     p_intf = _p_intf;
334     p_prefs_dialog = _p_prefs_dialog;
335     p_sizer = _p_sizer;
336     p_parent = _p_parent;
337     b_advanced = false;
338
339     root_item = AddRoot( wxT("") );
340     wxASSERT_MSG(root_item.IsOk(), wxT("Could not add root item"));
341
342     wxImageList *p_images = new wxImageList( 16,16,TRUE );
343     p_images->Add( wxIcon( audio_xpm ) );
344     p_images->Add( wxIcon( video_xpm ) );
345     p_images->Add( wxIcon( codec_xpm ) );
346     p_images->Add( wxIcon( type_net_xpm ) );
347     p_images->Add( wxIcon( advanced_xpm ) );
348     p_images->Add( wxIcon( type_playlist_xpm ) );
349     p_images->Add( wxIcon( intf_xpm ) );
350     AssignImageList( p_images );
351
352     /* List the plugins */
353     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
354     if( !p_list ) return;
355
356     /* Build the categories list */
357     for( i_index = 0; i_index < p_list->i_count; i_index++ )
358     {
359         p_module = (module_t *)p_list->p_values[i_index].p_object;
360         if( !strcmp( module_get_object(p_module), "main" ) )
361             break;
362     }
363     if( i_index < p_list->i_count )
364     {
365         wxTreeItemId current_item;
366         const char *psz_help;
367         unsigned int i_confsize;
368         module_config_t *p_config;
369
370         /* We found the main module */
371
372         /* Enumerate config categories and store a reference so we can
373          * generate their config panel them when it is asked by the user. */
374
375         p_config = module_config_get( p_module, &i_confsize );
376         for( size_t i = 0; i < i_confsize; i++ )
377         {
378             module_config_t *p_item = p_config + i;
379             ConfigTreeData *config_data;
380             switch( p_item->i_type )
381             {
382             case CONFIG_CATEGORY:
383                 if( p_item->value.i == -1 )   break; // Don't display it
384
385                 config_data = new ConfigTreeData;
386                 config_data->psz_name = strdup( config_CategoryNameGet(
387                                                             p_item->value.i ) );
388                 psz_help = config_CategoryHelpGet( p_item->value.i );
389                 if( psz_help )
390                 {
391                     config_data->psz_help = wraptext( strdup( psz_help ), 72 );
392                 }
393                 else
394                 {
395                     config_data->psz_help = NULL;
396                 }
397                 config_data->i_type = TYPE_CATEGORY;
398                 config_data->i_object_id = p_item->value.i;
399
400                 /* Add the category to the tree */
401                 switch( p_item->value.i )
402                 {
403                     case CAT_AUDIO:
404                         i_image = 0; break;
405                     case CAT_VIDEO:
406                         i_image = 1; break;
407                     case CAT_INPUT:
408                         i_image = 2; break;
409                     case CAT_SOUT:
410                         i_image = 3; break;
411                     case CAT_ADVANCED:
412                         i_image = 4; break;
413                     case CAT_PLAYLIST:
414                         i_image = 5; break;
415                     case CAT_INTERFACE:
416                         i_image = 6; break;
417                 }
418                 current_item = AppendItem( root_item,
419                                            wxU( _(config_data->psz_name) ),
420                                            i_image, -1, config_data );
421
422                 break;
423             case CONFIG_SUBCATEGORY:
424                 if( p_item->value.i == -1 ) break; // Don't display it
425                 /* Special case: move the "general" subcategories to their
426                  * parent category */
427                 if( p_item->value.i == SUBCAT_VIDEO_GENERAL ||
428                     p_item->value.i == SUBCAT_ADVANCED_MISC ||
429                     p_item->value.i == SUBCAT_INPUT_GENERAL ||
430                     p_item->value.i == SUBCAT_INTERFACE_GENERAL ||
431                     p_item->value.i == SUBCAT_SOUT_GENERAL||
432                     p_item->value.i == SUBCAT_PLAYLIST_GENERAL||
433                     p_item->value.i == SUBCAT_AUDIO_GENERAL )
434                 {
435                     ConfigTreeData *cd = (ConfigTreeData *)
436                                             GetItemData( current_item );
437                     cd->i_type = TYPE_CATSUBCAT;
438                     cd->i_subcat_id = p_item->value.i;
439                     free( cd->psz_name );
440                     cd->psz_name = strdup(  config_CategoryNameGet(
441                                                       p_item->value.i ) );
442                     free( cd->psz_help );
443                     const char *psz_help = config_CategoryHelpGet( p_item->value.i );
444                     if( psz_help )
445                     {
446                         cd->psz_help = wraptext( strdup( psz_help ), 72 );
447                     }
448                     else
449                     {
450                         cd->psz_help = NULL;
451                     }
452                     continue;
453                 }
454
455                 config_data = new ConfigTreeData;
456
457                 config_data->psz_name = strdup(  config_CategoryNameGet(
458                                                            p_item->value.i ) );
459                 psz_help = config_CategoryHelpGet( p_item->value.i );
460                 if( psz_help )
461                 {
462                     config_data->psz_help = wraptext( strdup( psz_help ), 72 );
463                 }
464                 else
465                 {
466                     config_data->psz_help = NULL;
467                 }
468                 config_data->i_type = TYPE_SUBCATEGORY;
469                 config_data->i_object_id = p_item->value.i;
470                 /* WXMSW doesn't know image -1 ... FIXME */
471                 #ifdef __WXMSW__
472                 switch( p_item->value.i / 100 )
473                 {
474                     case CAT_AUDIO:
475                         i_image = 0; break;
476                     case CAT_VIDEO:
477                         i_image = 1; break;
478                     case CAT_INPUT:
479                         i_image = 2; break;
480                     case CAT_SOUT:
481                         i_image = 3; break;
482                     case CAT_ADVANCED:
483                         i_image = 4; break;
484                     case CAT_PLAYLIST:
485                         i_image = 5; break;
486                     case CAT_INTERFACE:
487                         i_image = 6; break;
488                 }
489                 #else
490                 i_image = -1;
491                 #endif
492                 AppendItem( current_item, wxU( _(config_data->psz_name) ),
493                             i_image, -1, config_data );
494                 break;
495             }
496         }
497
498         module_config_free( p_config );
499     }
500
501
502     /*
503      * Build a tree of all the plugins
504      */
505     for( i_index = 0; i_index < p_list->i_count; i_index++ )
506     {
507         int i_category = -1, i_subcategory = -1, i_options = 0;
508         unsigned int i_confsize;
509         module_config_t *p_config;
510
511         p_module = (module_t *)p_list->p_values[i_index].p_object;
512
513         /* Exclude the main module */
514         if( !strcmp( module_get_object(p_module), "main" ) )
515             continue;
516 #if 0
517         /* Exclude empty plugins (submodules don't have config options, they
518          * are stored in the parent module) */
519         if( module_IsSubModule(p_module) )
520             continue;
521 #endif
522         p_config = module_config_get( p_module, &i_confsize );
523         for( size_t i = 0; i < i_confsize; i++ )
524         {
525             module_config_t *p_item = p_config + i;
526             if( p_item->i_type == CONFIG_CATEGORY )
527             {
528                 i_category = p_item->value.i;
529             }
530             else if( p_item->i_type == CONFIG_SUBCATEGORY )
531             {
532                 i_subcategory = p_item->value.i;
533             }
534             if( p_item->i_type & CONFIG_ITEM )
535                 i_options ++;
536             if( i_options > 0 && i_category >= 0 && i_subcategory >= 0 )
537             {
538                 break;
539             }
540         }
541
542         if( !i_options ) continue;
543
544         /* Find the right category item */
545         wxTreeItemIdValue cookie;
546         bool b_found = false;
547
548         wxTreeItemId category_item = GetFirstChild( root_item , cookie);
549         while( category_item.IsOk() )
550         {
551             ConfigTreeData *config_data =
552                     (ConfigTreeData *)GetItemData( category_item );
553             if( config_data->i_object_id == i_category )
554             {
555                 b_found = true;
556                 break;
557             }
558             category_item = GetNextChild( root_item, cookie );
559         }
560         if( !b_found ) continue;
561
562         /* Find subcategory item */
563         b_found = false;
564         //cookie = -1;
565         wxTreeItemId subcategory_item = GetFirstChild( category_item, cookie );
566         while( subcategory_item.IsOk() )
567         {
568             ConfigTreeData *config_data =
569                     (ConfigTreeData *)GetItemData( subcategory_item );
570             if( config_data->i_object_id == i_subcategory )
571             {
572                 b_found = true;
573                 break;
574             }
575             subcategory_item = GetNextChild( category_item, cookie );
576         }
577         if( !b_found )
578         {
579             subcategory_item = category_item;
580         }
581
582         /* Add the plugin to the tree */
583         ConfigTreeData *config_data = new ConfigTreeData;
584 #if 0
585         config_data->b_submodule = module_IsSubModule(p_module);
586 #endif
587         config_data->i_type = TYPE_MODULE;
588         config_data->p_module = config_data->b_submodule ?
589             ((module_t*)((vlc_object_t*)p_module)->p_parent) : p_module;
590         config_data->psz_help = NULL;
591
592         /* WXMSW doesn't know image -1 ... FIXME */
593         #ifdef __WXMSW__
594         switch( i_subcategory / 100 )
595         {
596             case CAT_AUDIO:
597                 i_image = 0; break;
598             case CAT_VIDEO:
599                 i_image = 1; break;
600             case CAT_INPUT:
601                 i_image = 2; break;
602             case CAT_SOUT:
603                 i_image = 3; break;
604             case CAT_ADVANCED:
605                 i_image = 4; break;
606             case CAT_PLAYLIST:
607                 i_image = 5; break;
608             case CAT_INTERFACE:
609                 i_image = 6; break;
610         }
611         #else
612         i_image = -1;
613         #endif
614         AppendItem( subcategory_item, wxU( module_get_name(p_module, 0) ),
615                     i_image, -1, config_data );
616     }
617
618     /* Sort all this mess */
619     wxTreeItemIdValue cookie;
620     size_t i_child_index;
621     wxTreeItemId capability_item = GetFirstChild( root_item, cookie);
622     for( i_child_index = 0;
623          (capability_item.IsOk() &&
624           //(i_child_index < GetChildrenCount( plugins_item, FALSE )));
625           (i_child_index < GetChildrenCount( root_item, FALSE )));
626          i_child_index++ )
627     {
628         SortChildren( capability_item );
629         //capability_item = GetNextChild( plugins_item, cookie );
630         capability_item = GetNextChild( root_item, cookie );
631     }
632
633     /* Clean-up everything */
634     vlc_list_release( p_list );
635
636     p_sizer->Add( this, 1, wxEXPAND | wxALL, 0 );
637     p_sizer->Layout();
638
639     p_current = NULL;
640
641     /* Update Tree Ctrl */
642 #ifndef WIN32 /* Workaround a bug in win32 implementation */
643     SelectItem( GetFirstChild( root_item, cookie ) );
644 #endif
645
646     //cannot expand hidden root item
647     //Expand( root_item );
648 }
649
650 PrefsTreeCtrl::~PrefsTreeCtrl(){
651 }
652
653 void PrefsTreeCtrl::ApplyChanges()
654 {
655     wxTreeItemIdValue cookie, cookie2, cookie3;
656     ConfigTreeData *config_data;
657
658     wxTreeItemId category = GetFirstChild( root_item, cookie );
659     while( category.IsOk() )
660     {
661         wxTreeItemId subcategory = GetFirstChild( category, cookie2 );
662         while( subcategory.IsOk() )
663         {
664             wxTreeItemId module = GetFirstChild( subcategory, cookie3 );
665             while( module.IsOk() )
666             {
667                 config_data = (ConfigTreeData *)GetItemData( module );
668                 if( config_data && config_data->panel )
669                 {
670                     config_data->panel->ApplyChanges();
671                 }
672                 module = GetNextChild( subcategory, cookie3 );
673             }
674             config_data = (ConfigTreeData *)GetItemData( subcategory );
675             if( config_data && config_data->panel )
676             {
677                 config_data->panel->ApplyChanges();
678             }
679             subcategory = GetNextChild( category, cookie2 );
680         }
681         config_data = (ConfigTreeData *)GetItemData( category );
682         if( config_data && config_data->panel )
683         {
684             config_data->panel->ApplyChanges();
685         }
686         category = GetNextChild( root_item, cookie );
687     }
688 }
689
690 void PrefsTreeCtrl::CleanChanges()
691 {
692     wxTreeItemIdValue cookie, cookie2, cookie3;
693     ConfigTreeData *config_data;
694
695     config_data = !GetSelection() ? NULL :
696         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
697     if( config_data  )
698     {
699         config_data->panel->Hide();
700 #if (wxCHECK_VERSION(2,5,0))
701         p_sizer->Detach( config_data->panel );
702 #else
703         p_sizer->Remove( config_data->panel );
704 #endif
705         p_current = NULL;
706     }
707
708     wxTreeItemId category = GetFirstChild( root_item, cookie );
709     while( category.IsOk() )
710     {
711         wxTreeItemId subcategory = GetFirstChild( category, cookie2 );
712         while( subcategory.IsOk() )
713         {
714             wxTreeItemId module = GetFirstChild( subcategory, cookie3 );
715             while( module.IsOk() )
716             {
717                 config_data = (ConfigTreeData *)GetItemData( module );
718                 if( config_data && config_data->panel )
719                 {
720                     delete config_data->panel;
721                     config_data->panel = NULL;
722                 }
723                 module = GetNextChild( subcategory, cookie3 );
724             }
725             config_data = (ConfigTreeData *)GetItemData( subcategory );
726             if( config_data && config_data->panel )
727             {
728                 delete config_data->panel;
729                 config_data->panel = NULL;
730             }
731             subcategory = GetNextChild( category, cookie2 );
732         }
733         config_data = (ConfigTreeData *)GetItemData( category );
734         if( config_data && config_data->panel )
735         {
736             delete config_data->panel;
737             config_data->panel = NULL;
738         }
739         category = GetNextChild( root_item, cookie );
740     }
741
742     if( GetSelection() )
743     {
744         wxTreeEvent event;
745         OnSelectTreeItem( event );
746     }
747 }
748
749 ConfigTreeData *PrefsTreeCtrl::FindModuleConfig( ConfigTreeData *config_data )
750 {
751     /* We need this complexity because submodules don't have their own config
752      * options. They use the parent module ones. */
753
754     if( !config_data || !config_data->b_submodule )
755     {
756         return config_data;
757     }
758
759     wxTreeItemIdValue cookie, cookie2, cookie3;
760     ConfigTreeData *config_new;
761     wxTreeItemId category = GetFirstChild( root_item, cookie );
762     while( category.IsOk() )
763     {
764         wxTreeItemId subcategory = GetFirstChild( category, cookie2 );
765         while( subcategory.IsOk() )
766         {
767             wxTreeItemId module = GetFirstChild( subcategory, cookie3 );
768             while( module.IsOk() )
769             {
770                 config_new = (ConfigTreeData *)GetItemData( module );
771                 if( config_new && !config_new->b_submodule &&
772                     config_new->p_module == config_data->p_module )
773                 {
774                     return config_new;
775                 }
776                 module = GetNextChild( subcategory, cookie3 );
777             }
778             subcategory = GetNextChild( category, cookie2 );
779         }
780         category = GetNextChild( root_item, cookie );
781     }
782
783     /* Found nothing */
784     return NULL;
785 }
786
787 void PrefsTreeCtrl::OnSelectTreeItem( wxTreeEvent& event )
788 {
789     ConfigTreeData *config_data = NULL;
790
791     if( p_current )
792     {
793         p_current->Hide();
794 #if (wxCHECK_VERSION(2,5,0))
795         p_sizer->Detach( p_current  );
796 #else
797         p_sizer->Remove( p_current );
798 #endif
799         p_current = NULL;
800     }
801
802     /* Don't use event.GetItem() because we also send fake events */
803     config_data = FindModuleConfig( (ConfigTreeData *)GetItemData(
804                                     GetSelection() ) );
805     if( config_data )
806     {
807         if( !config_data->panel )
808         {
809             /* The panel hasn't been created yet. Let's do it. */
810             config_data->panel =
811                 new PrefsPanel( p_parent, p_intf, p_prefs_dialog,
812                                 config_data );
813             config_data->panel->SwitchAdvanced( b_advanced );
814         }
815         else
816         {
817             config_data->panel->SwitchAdvanced( b_advanced );
818             config_data->panel->Show();
819         }
820
821         p_current = config_data->panel;
822
823         p_sizer->Add( config_data->panel, 3, wxEXPAND | wxALL, 0 );
824         p_sizer->Layout();
825     }
826 }
827
828 void PrefsTreeCtrl::OnAdvanced( wxCommandEvent& event )
829 {
830     b_advanced = event.GetInt();
831
832     ConfigTreeData *config_data = !GetSelection() ? NULL :
833         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
834     if( config_data  )
835     {
836         config_data->panel->Hide();
837 #if (wxCHECK_VERSION(2,5,0))
838         p_sizer->Detach( config_data->panel );
839 #else
840         p_sizer->Remove( config_data->panel );
841 #endif
842         p_current = NULL;
843     }
844
845     if( GetSelection() )
846     {
847         wxTreeEvent event;
848         OnSelectTreeItem( event );
849     }
850 }
851
852 /*****************************************************************************
853  * PrefsPanel class definition.
854  *****************************************************************************/
855 PrefsPanel::PrefsPanel( wxWindow* parent, intf_thread_t *_p_intf,
856                         PrefsDialog *_p_prefs_dialog,
857                         ConfigTreeData *config_data )
858   :  wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize )
859 {
860     module_config_t *p_item, *p_start, *p_end;
861     unsigned int i_confsize;
862     vlc_list_t *p_list = NULL;;
863
864     wxStaticText *label;
865     wxStaticText *help;
866     wxArrayString array;
867
868     module_t *p_module = NULL;
869
870     /* Initializations */
871     p_intf = _p_intf;
872     p_prefs_dialog =_p_prefs_dialog,
873
874     b_advanced = true;
875     SetAutoLayout( TRUE );
876     Hide();
877
878     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
879
880
881     if( config_data->i_type == TYPE_CATEGORY )
882     {
883         label = new wxStaticText( this, -1,wxU(_( config_data->psz_name )));
884         wxFont heading_font = label->GetFont();
885         heading_font.SetPointSize( heading_font.GetPointSize() + 5 );
886         label->SetFont( heading_font );
887         sizer->Add( label, 0, wxEXPAND | wxLEFT, 10 );
888         sizer->Add( new wxStaticLine( this, 0 ), 0,
889                     wxEXPAND | wxLEFT | wxRIGHT, 2 );
890
891         hidden_text = NULL;
892         help = new wxStaticText( this, -1, wxU(_( config_data->psz_help ) ) );
893         sizer->Add( help ,0 ,wxEXPAND | wxALL, 5 );
894
895         config_sizer = NULL; config_window = NULL;
896     }
897     else
898     {
899         /* Get a pointer to the module */
900         if( config_data->i_type == TYPE_MODULE )
901         {
902             p_module = config_data->p_module;
903         }
904         else
905         {
906             /* List the plugins */
907             int i_index;
908             bool b_found = false;
909             p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
910             if( !p_list ) return;
911
912             for( i_index = 0; i_index < p_list->i_count; i_index++ )
913             {
914                 p_module = (module_t *)p_list->p_values[i_index].p_object;
915                 if( !strcmp( module_get_object(p_module), "main" ) )
916                 {
917                     b_found = true;
918                     break;
919                 }
920             }
921             if( !p_module && !b_found )
922             {
923                 msg_Warn( p_intf, "unable to create preferences "
924                                   "(main module not found)" );
925                 return;
926             }
927         }
928
929         /* Enumerate config options and add corresponding config boxes
930          * (submodules don't have config options, they are stored in the
931          *  parent module) */
932 #if 0
933         if( module_IsSubModule(p_module) )
934             p_start = module_config_get((module_t *)(((vlc_object_t *)p_module)->p_parent), &i_confsize);
935         else
936 #endif
937             p_start = module_config_get(p_module, &i_confsize);
938
939         p_item = p_start;
940         p_end = p_start + i_confsize;
941
942         /* Find the category if it has been specified */
943         if( config_data->i_type == TYPE_SUBCATEGORY ||
944             config_data->i_type == TYPE_CATSUBCAT )
945         {
946             for( ; p_item && p_item < p_end; p_item++ )
947             {
948                 if( p_item->i_type == CONFIG_SUBCATEGORY &&
949                     ( config_data->i_type == TYPE_SUBCATEGORY &&
950                       p_item->value.i == config_data->i_object_id ) ||
951                     ( config_data->i_type == TYPE_CATSUBCAT &&
952                       p_item->value.i == config_data->i_subcat_id ) )
953                 {
954                     break;
955                 }
956             }
957         }
958
959         /* Add a head title to the panel */
960         const char *psz_head;
961         if( config_data->i_type == TYPE_SUBCATEGORY ||
962             config_data->i_type == TYPE_CATSUBCAT )
963         {
964             psz_head = config_data->psz_name;
965             p_item++;
966         }
967         else
968         {
969             psz_head = module_GetLongName(p_module);
970         }
971
972         label = new wxStaticText( this, -1,
973                       wxU(_( psz_head ? psz_head : _("Unknown") ) ) );
974         wxFont heading_font = label->GetFont();
975         heading_font.SetPointSize( heading_font.GetPointSize() + 5 );
976         label->SetFont( heading_font );
977         sizer->Add( label, 0, wxEXPAND | wxLEFT, 10 );
978         sizer->Add( new wxStaticLine( this, 0 ), 0,
979                     wxEXPAND | wxLEFT | wxRIGHT, 2 );
980
981         /* Now put all the config options into a scrolled window */
982         config_sizer = new wxBoxSizer( wxVERTICAL );
983         config_window = new wxScrolledWindow( this, -1, wxDefaultPosition,
984             wxDefaultSize, wxBORDER_NONE | wxHSCROLL | wxVSCROLL );
985         config_window->SetAutoLayout( TRUE );
986         config_window->SetScrollRate( 5, 5 );
987
988         for( ; p_item && p_item < p_end; p_item++ )
989         {
990             /* If a category has been specified, check we finished the job */
991             if( ( ( config_data->i_type == TYPE_SUBCATEGORY &&
992                     p_item->value.i != config_data->i_object_id ) ||
993                   ( config_data->i_type == TYPE_CATSUBCAT  &&
994                     p_item->value.i != config_data->i_subcat_id ) ) &&
995                 (p_item->i_type == CONFIG_CATEGORY ||
996                   p_item->i_type == CONFIG_SUBCATEGORY ) )
997                 break;
998
999             ConfigControl *control =
1000                 CreateConfigControl( VLC_OBJECT(p_intf),
1001                                      p_item, config_window );
1002
1003             /* Don't add items that were not recognized */
1004             if( control == NULL ) continue;
1005
1006             /* Add the config data to our array so we can keep a trace of it */
1007             config_array.Add( control );
1008
1009             config_sizer->Add( control, 0, wxEXPAND | wxALL, 2 );
1010         }
1011
1012         module_config_free( p_start );
1013
1014         config_sizer->Layout();
1015         config_window->SetSizer( config_sizer );
1016         sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
1017         hidden_text = new wxStaticText( this, -1,
1018                         wxU( _( "Some options are available but hidden. " \
1019                                 "Check \"Advanced options\" to see them." ) ) );
1020         sizer->Add( hidden_text );
1021
1022         /* And at last put a useful help string if available */
1023         if( config_data->psz_help && *config_data->psz_help )
1024         {
1025             sizer->Add( new wxStaticLine( this, 0 ), 0,
1026                         wxEXPAND | wxLEFT | wxRIGHT, 2 );
1027             help = new wxStaticText( this, -1, wxU(_(config_data->psz_help)),
1028                                      wxDefaultPosition, wxDefaultSize,
1029                                      wxALIGN_LEFT,
1030                                      wxT("") );
1031             sizer->Add( help ,0 ,wxEXPAND | wxALL, 5 );
1032         }
1033
1034         if( config_data->i_type == TYPE_MODULE )
1035         {
1036             module_release (p_module);
1037         }
1038         else
1039         {
1040             vlc_list_release( p_list );
1041         }
1042     }
1043     sizer->Layout();
1044     SetSizer( sizer );
1045     Show();
1046 }
1047
1048 void PrefsPanel::ApplyChanges()
1049 {
1050     vlc_value_t val;
1051
1052     for( size_t i = 0; i < config_array.GetCount(); i++ )
1053     {
1054         ConfigControl *control = config_array.Item(i);
1055
1056         switch( control->GetType() )
1057         {
1058         case CONFIG_ITEM_STRING:
1059         case CONFIG_ITEM_FILE:
1060         case CONFIG_ITEM_DIRECTORY:
1061         case CONFIG_ITEM_MODULE:
1062         case CONFIG_ITEM_MODULE_CAT:
1063         case CONFIG_ITEM_MODULE_LIST:
1064         case CONFIG_ITEM_MODULE_LIST_CAT:
1065             config_PutPsz( p_intf, control->GetName().mb_str(wxConvUTF8),
1066                            control->GetPszValue().mb_str(wxConvUTF8) );
1067             break;
1068         case CONFIG_ITEM_KEY:
1069             /* So you don't need to restart to have the changes take effect */
1070             val.i_int = control->GetIntValue();
1071             var_Set( p_intf->p_libvlc, control->GetName().mb_str(wxConvUTF8), val );
1072         case CONFIG_ITEM_INTEGER:
1073         case CONFIG_ITEM_BOOL:
1074             config_PutInt( p_intf, control->GetName().mb_str(wxConvUTF8),
1075                            control->GetIntValue() );
1076             break;
1077         case CONFIG_ITEM_FLOAT:
1078             config_PutFloat( p_intf, control->GetName().mb_str(wxConvUTF8),
1079                              control->GetFloatValue() );
1080             break;
1081         }
1082     }
1083 }
1084
1085 void PrefsPanel::SwitchAdvanced( bool b_new_advanced )
1086 {
1087     bool hidden = false;
1088
1089     if( b_advanced == b_new_advanced )
1090     {
1091         goto hide;
1092     }
1093
1094     if( config_sizer && config_window )
1095     {
1096         b_advanced = b_new_advanced;
1097
1098         for( size_t i = 0; i < config_array.GetCount(); i++ )
1099         {
1100             ConfigControl *control = config_array.Item(i);
1101             if( control->IsAdvanced() )
1102             {
1103                 if( !b_advanced ) hidden = true;
1104                 control->Show( b_advanced );
1105                 config_sizer->Show( control, b_advanced );
1106             }
1107         }
1108
1109         config_sizer->Layout();
1110         config_window->FitInside();
1111         config_window->Refresh();
1112     }
1113 hide:
1114     if( hidden && hidden_text )
1115     {
1116         hidden_text->Show( true );
1117         config_sizer->Show( hidden_text, true );
1118     }
1119     else if ( hidden_text )
1120     {
1121         hidden_text->Show( false );
1122         config_sizer->Show( hidden_text, false );
1123     }
1124     return;
1125 }