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