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