]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/preferences.cpp
Preferences
[vlc] / modules / gui / qt4 / components / preferences.cpp
1 /*****************************************************************************
2  * preferences_tree.cpp : Tree of modules for preferences
3  ****************************************************************************
4  * Copyright (C) 2000-2005 the VideoLAN team
5  * $Id: wxwidgets.cpp 15731 2006-05-25 14:43:53Z zorglub $
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include "components/preferences.hpp"
25 #include "components/preferences_widgets.hpp"
26 #include <vlc_config_cat.h>
27
28 #include "pixmaps/audio.xpm"
29 #include "pixmaps/video.xpm"
30 #include "pixmaps/type_net.xpm"
31 #include "pixmaps/type_playlist.xpm"
32 #include "pixmaps/advanced.xpm"
33 #include "pixmaps/codec.xpm"
34 #include "pixmaps/intf.xpm"
35
36 #include <QLabel>
37 #include <QTreeWidget>
38 #include <QTreeWidgetItem>
39 #include <QVariant>
40 #include <QString>
41 #include <QFont>
42 #include <QGroupBox>
43 #include <QScrollArea>
44 #include <QVBoxLayout>
45 #include <QHBoxLayout>
46
47 #define ITEM_HEIGHT 25
48
49 /*********************************************************************
50  * The Tree
51  *********************************************************************/
52 PrefsTree::PrefsTree( intf_thread_t *_p_intf, QWidget *_parent ) :
53                             QTreeWidget( _parent ), p_intf( _p_intf )
54 {
55     module_t *p_module;
56     vlc_list_t *p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
57                                         FIND_ANYWHERE );
58     if( !p_list ) return;
59
60     setColumnCount( 1 );
61     setIconSize( QSize( ITEM_HEIGHT,ITEM_HEIGHT ) );
62
63 #define BI( a,b) QIcon a##_icon = QIcon( QPixmap( b##_xpm ))
64     BI( audio, audio );
65     BI( video, video );
66     BI( input, codec );
67     BI( sout, type_net );
68     BI( advanced, advanced );
69     BI( playlist, type_playlist );
70     BI( interface, intf );
71 #undef BI
72
73     /* Build the tree for the main module */
74     int i_index;
75     for( i_index = 0; i_index < p_list->i_count; i_index++ )
76     {
77         p_module = (module_t *)p_list->p_values[i_index].p_object;
78         if( !strcmp( p_module->psz_object_name, "main" ) )
79              break;
80     }
81     if( i_index < p_list->i_count )
82     {
83         module_config_t *p_item = p_module->p_config;
84         PrefsItemData *data = NULL;
85         QTreeWidgetItem *current_item = NULL;
86         if( p_item ) do
87         {
88             char *psz_help;
89             QIcon icon;
90             switch( p_item->i_type )
91             {
92             case CONFIG_CATEGORY:
93                 if( p_item->i_value == -1 ) break;
94                 data = new PrefsItemData();
95                 data->name = QString( config_CategoryNameGet
96                                                ( p_item->i_value ) );
97                 psz_help = config_CategoryHelpGet( p_item->i_value );
98                 if( psz_help )
99                     data->help = QString( psz_help );
100                 else
101                     data->help.clear();
102                 data->i_type = TYPE_CATEGORY;
103                 data->i_object_id = p_item->i_value;
104
105                 switch( p_item->i_value )
106                 {
107 #define CI(a,b) case a: icon = b##_icon;break
108                 CI( CAT_AUDIO, audio );
109                 CI( CAT_VIDEO, video );
110                 CI( CAT_INPUT, input );
111                 CI( CAT_SOUT, sout );
112                 CI( CAT_ADVANCED, advanced );
113                 CI( CAT_PLAYLIST, playlist );
114                 CI( CAT_INTERFACE, interface );
115 #undef CI
116                 }
117
118                 current_item = new QTreeWidgetItem();
119                 current_item->setText( 0, data->name );
120                 current_item->setIcon( 0 , icon );
121                 current_item->setData( 0, Qt::UserRole,
122                                        qVariantFromValue( data ) );
123                 addTopLevelItem( current_item );
124                 //fprintf( stderr, "Adding %s\n", current_item->text(0).toLatin1().data() );
125                 break;
126             case CONFIG_SUBCATEGORY:
127                 if( p_item->i_value == -1 ) break;
128                 if( data &&
129                     ( p_item->i_value == SUBCAT_VIDEO_GENERAL ||
130                       p_item->i_value == SUBCAT_ADVANCED_MISC ||
131                       p_item->i_value == SUBCAT_INPUT_GENERAL ||
132                       p_item->i_value == SUBCAT_INTERFACE_GENERAL ||
133                       p_item->i_value == SUBCAT_SOUT_GENERAL||
134                       p_item->i_value == SUBCAT_PLAYLIST_GENERAL||
135                       p_item->i_value == SUBCAT_AUDIO_GENERAL ) )
136                 {
137                     // Data still contains the correct thing
138                     data->i_type = TYPE_CATSUBCAT;
139                     data->i_subcat_id = p_item->i_value;
140                     data->name = QString( config_CategoryNameGet(
141                                                 p_item->i_value ) );
142                     psz_help = config_CategoryHelpGet( p_item->i_value );
143                     if( psz_help )
144                         data->help = QString( psz_help );
145                     else
146                         data->help.clear();
147                     current_item->setData( 0, Qt::UserRole,
148                                            QVariant::fromValue( data ) );
149                     continue;
150                 }
151                 data = new PrefsItemData();
152                 data->name = QString( config_CategoryNameGet( p_item->i_value));
153                 psz_help = config_CategoryHelpGet( p_item->i_value );
154                 if( psz_help )
155                     data->help = QString( psz_help );
156                 else
157                     data->help.clear();
158                 data->i_type = TYPE_SUBCATEGORY;
159                 data->i_object_id = p_item->i_value;
160
161                 assert( current_item );
162
163                 /* TODO : Choose the image */
164                 QTreeWidgetItem *subcat_item = new QTreeWidgetItem();
165                 subcat_item->setText( 0, data->name );
166                 //item->setIcon( 0 , XXX );
167                 subcat_item->setData( 0, Qt::UserRole,
168                                       qVariantFromValue(data) );
169                 subcat_item->setSizeHint( 0, QSize( -1, ITEM_HEIGHT ) );
170                 current_item->addChild( subcat_item );
171                 break;
172             }
173         } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
174     }
175
176     /* Build the tree of plugins */
177     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
178     {
179         module_config_t *p_item;
180         int i_subcategory = -1, i_category = -1, i_options = 0;
181         p_module = (module_t *)p_list->p_values[i_index].p_object;
182
183         // Main module excluded
184         if( !strcmp( p_module->psz_object_name, "main" ) ) continue;
185
186         /* Exclude empty plugins (submodules don't have config options, they
187          * are stored in the parent module) */
188         if( p_module->b_submodule ) continue;
189
190         p_item = p_module->p_config;
191         if( !p_item ) continue;
192
193         do {
194             if( p_item->i_type == CONFIG_CATEGORY )
195                 i_category = p_item->i_value;
196             else if( p_item->i_type == CONFIG_SUBCATEGORY )
197                 i_subcategory = p_item->i_value;
198             if( p_item->i_type & CONFIG_ITEM )
199                 i_options++;
200
201             if( i_options > 0 && i_category >= 0 && i_subcategory >= 0 )
202                 break;
203         } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
204
205         if( !i_options ) continue; // Nothing to display
206
207         // Locate the category item;
208         QTreeWidgetItem *subcat_item = NULL;
209         bool b_found = false;
210         for( int i_cat_index = 0 ; i_cat_index < topLevelItemCount();
211                                    i_cat_index++ )
212         {
213             QTreeWidgetItem *cat_item = topLevelItem( i_cat_index );
214             PrefsItemData *data = cat_item->data( 0, Qt::UserRole ).
215                                              value<PrefsItemData *>();
216             if( data->i_object_id == i_category )
217             {
218                 for( int i_sc_index = 0; i_sc_index < cat_item->childCount();
219                          i_sc_index++ )
220                 {
221                     subcat_item = cat_item->child( i_sc_index );
222                     PrefsItemData *sc_data = subcat_item->data(0, Qt::UserRole).
223                                                 value<PrefsItemData *>();
224                     if( sc_data && sc_data->i_object_id == i_subcategory )
225                     {
226                         b_found = true;
227                         break;
228                     }
229                 }
230                 if( !b_found )
231                 {
232                     subcat_item = cat_item;
233                     b_found = true;
234                 }
235                 break;
236             }
237         }
238         if( !b_found ) continue;
239
240         PrefsItemData *module_data = new PrefsItemData();
241         module_data->b_submodule = p_module->b_submodule;
242         module_data->i_type = TYPE_MODULE;
243         module_data->i_object_id = p_module->b_submodule ?
244                          ((module_t *)p_module->p_parent)->i_object_id :
245                          p_module->i_object_id;
246         module_data->help.clear();
247         // TODO image
248         QTreeWidgetItem *module_item = new QTreeWidgetItem();
249         module_item->setText( 0, p_module->psz_shortname ?
250                       p_module->psz_shortname : p_module->psz_object_name );
251         //item->setIcon( 0 , XXX );
252         module_item->setData( 0, Qt::UserRole,
253                               QVariant::fromValue( module_data) );
254         module_item->setSizeHint( 0, QSize( -1, ITEM_HEIGHT ) );
255         subcat_item->addChild( module_item );
256     }
257
258     /* We got everything, just sort a bit */
259     sortItems( 0, Qt::AscendingOrder );
260
261     vlc_list_release( p_list );
262 }
263
264 PrefsTree::~PrefsTree() {}
265
266 void PrefsTree::ApplyAll()
267 {
268     DoAll( false );
269 }
270
271 void PrefsTree::CleanAll()
272 {
273     DoAll( true );
274 }
275
276 /// \todo When cleaning, we should remove the panel ?
277 void PrefsTree::DoAll( bool doclean )
278 {
279     for( int i_cat_index = 0 ; i_cat_index < topLevelItemCount();
280              i_cat_index++ )
281     {
282         QTreeWidgetItem *cat_item = topLevelItem( i_cat_index );
283         for( int i_sc_index = 0; i_sc_index <= cat_item->childCount();
284                  i_sc_index++ )
285         {
286             QTreeWidgetItem *sc_item = cat_item->child( i_sc_index );
287             for( int i_module = 0 ; i_module <= sc_item->childCount();
288                      i_module++ )
289             {
290                 PrefsItemData *data = sc_item->child( i_sc_index )->
291                                                  data( 0, Qt::UserRole ).
292                                                  value<PrefsItemData *>();
293                 if( data->panel && doclean )
294                     data->panel->Clean();
295                 else if( data->panel )
296                     data->panel->Apply();
297             }
298         }
299     }
300 }
301
302
303 /*********************************************************************
304  * The Panel
305  *********************************************************************/
306 PrefsPanel::PrefsPanel( QWidget *_parent ) : QWidget( _parent )
307 {}
308
309 PrefsPanel::PrefsPanel( intf_thread_t *_p_intf, QWidget *_parent,
310                         PrefsItemData * data ) :
311                         QWidget( _parent ), p_intf( _p_intf )
312 {
313     module_config_t *p_item;
314     module_t *p_module;
315     vlc_list_t *p_list = NULL;
316     global_layout = new QVBoxLayout();
317
318     if( data->i_type == TYPE_CATEGORY )
319     {
320         /* TODO */
321             return;
322     }
323     else if( data->i_type == TYPE_MODULE )
324     {
325         p_module = (module_t *) vlc_object_get( p_intf, data->i_object_id );
326     }
327     else
328     {
329         /* List the plugins */
330         int i_index;
331         vlc_bool_t b_found = VLC_FALSE;
332         p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
333         if( !p_list ) return;
334
335         for( i_index = 0; i_index < p_list->i_count; i_index++ )
336         {
337             p_module = (module_t *)p_list->p_values[i_index].p_object;
338             if( !strcmp( p_module->psz_object_name, "main" ) )
339             {
340                 b_found = VLC_TRUE;
341                 break;
342             }
343         }
344         if( !p_module && !b_found )
345         {
346             msg_Warn( p_intf, "unable to create preferences (main not found)");
347             return;
348         }
349     }
350
351     if( p_module->b_submodule )
352         p_item = ((module_t *)p_module->p_parent)->p_config;
353     else
354         p_item = p_module->p_config;
355
356     if( data->i_type == TYPE_SUBCATEGORY || data->i_type ==  TYPE_CATSUBCAT )
357     {
358         do
359         {
360             if( p_item->i_type == CONFIG_SUBCATEGORY &&
361                             ( data->i_type == TYPE_SUBCATEGORY &&
362                               p_item->i_value == data->i_object_id ) ||
363                             ( data->i_type == TYPE_CATSUBCAT &&
364                               p_item->i_value == data->i_subcat_id ) )
365             {
366                 break;
367             }
368             if( p_item->i_type == CONFIG_HINT_END ) break;
369         } while( p_item++ );
370     }
371
372     QString head;
373     if( data->i_type == TYPE_SUBCATEGORY || data->i_type ==  TYPE_CATSUBCAT )
374     {
375         head = QString( data->name );
376         p_item++; // Why that ?
377     }
378     else
379         head = QString( p_module->psz_longname );
380
381     QLabel *label = new QLabel( head, this );
382     QFont font = label->font();
383     font.setPointSize( font.pointSize() + 2 ); font.setBold( true );
384     label->setFont( font );
385     QLabel *help = new QLabel( data->help, this );
386     help->setWordWrap( true );
387
388     global_layout->addWidget( label );
389     global_layout->addWidget( help );
390
391     QGroupBox *box = NULL;
392     QVBoxLayout *boxlayout = NULL;
393
394     QScrollArea *scroller= new QScrollArea;
395     QWidget *scrolled_area = new QWidget;
396
397     QVBoxLayout *layout = new QVBoxLayout();
398
399     if( p_item ) do
400     {
401         if( ( ( data->i_type == TYPE_SUBCATEGORY &&
402                 p_item->i_value != data->i_object_id ) ||
403               ( data->i_type == TYPE_CATSUBCAT  &&
404                 p_item->i_value != data->i_subcat_id ) ) &&
405             ( p_item->i_type == CONFIG_CATEGORY ||
406               p_item->i_type == CONFIG_SUBCATEGORY ) )
407             break;
408         if( p_item->b_internal == VLC_TRUE ) continue;
409
410         if( p_item->i_type == CONFIG_SECTION )
411         {
412             if( box )
413             {
414                 box->setLayout( boxlayout );
415                 layout->addWidget( box, 1 );
416             }
417             box = new QGroupBox( p_item->psz_text );
418             boxlayout = new QVBoxLayout();
419         }
420
421         ConfigControl *control = ConfigControl::createControl(
422                                     VLC_OBJECT( p_intf ), p_item,
423                                     NULL );
424         if( !control )
425         {
426             continue;
427         }
428         if( !box )
429             layout->addWidget( control );
430         else
431             boxlayout->addWidget( control );
432
433         controls.append( control );
434     }
435     while( !(p_item->i_type == CONFIG_HINT_END ||
436            ( ( data->i_type == TYPE_SUBCATEGORY ||
437                data->i_type == TYPE_CATSUBCAT ) &&
438              ( p_item->i_type == CONFIG_CATEGORY ||
439                p_item->i_type == CONFIG_SUBCATEGORY ) ) ) && p_item++ );
440
441     if( box )
442     {
443         box->setLayout( boxlayout );
444         layout->addWidget( box, 1 );
445     }
446
447     scrolled_area->setSizePolicy( QSizePolicy::Preferred,QSizePolicy::Fixed );
448     scrolled_area->setLayout( layout );
449     scroller->setWidget( scrolled_area );
450     scroller->setWidgetResizable( true );
451     global_layout->addWidget( scroller );
452
453     some_hidden_text = new QLabel( "Some options are available but hidden. "\
454                                   "Check \"Advanced options\" to see them." );
455     some_hidden_text->setWordWrap( true );
456
457     setLayout( global_layout );
458     setAdvanced( false );
459 }
460
461 void PrefsPanel::Apply()
462 {
463     /* todo */
464     QList<ConfigControl *>::Iterator i;
465     for( i = controls.begin() ; i != controls.end() ; i++ )
466     {
467         VIntConfigControl *vicc = qobject_cast<VIntConfigControl *>(*i);
468         if( !vicc )
469         {
470             VFloatConfigControl *vfcc = qobject_cast<VFloatConfigControl *>(*i);
471             if( !vfcc)
472             {
473                 VStringConfigControl *vscc =
474                                qobject_cast<VStringConfigControl *>(*i);
475                 assert( vscc );
476                 config_PutPsz( p_intf, vscc->getName().toAscii().data(),
477                                        vscc->getValue().toAscii().data() );
478                 continue;
479             }
480             config_PutFloat( p_intf, vfcc->getName().toAscii().data(),
481                                      vfcc->getValue() );
482             continue;
483         }
484         config_PutInt( p_intf, vicc->getName().toAscii().data(),
485                                vicc->getValue() );
486     }
487 }
488
489 void PrefsPanel::Clean()
490 {}
491
492 void PrefsPanel::setAdvanced( bool adv )
493 {
494     bool some_hidden = false;
495     if( adv == advanced ) return;
496
497     advanced = adv;
498     QList<ConfigControl *>::Iterator i;
499     for( i = controls.begin() ; i != controls.end() ; i++ )
500     {
501         if( (*i)->isAdvanced() )
502         {
503             fprintf( stderr, "Showing \n" );
504             if( !advanced ) some_hidden = true;
505             (*i)->setVisible( advanced );
506         }
507     }
508     if( some_hidden_text )
509     {
510         global_layout->removeWidget( some_hidden_text );
511         some_hidden_text->hide();
512     }
513     if( some_hidden )
514     {
515         global_layout->addWidget( some_hidden_text );
516         some_hidden_text->show();
517     }
518 }