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