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