]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/complete_preferences.cpp
Merge branch 'master' into lpcm_encoder
[vlc] / modules / gui / qt4 / components / complete_preferences.cpp
1 /*****************************************************************************
2  * preferences.cpp : "Normal preferences"
3  ****************************************************************************
4  * Copyright (C) 2006-2007 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 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <QApplication>
28 #include <QLabel>
29 #include <QTreeWidget>
30 #include <QTreeWidgetItem>
31 #include <QVariant>
32 #include <QString>
33 #include <QFont>
34 #include <QGroupBox>
35 #include <QScrollArea>
36 #include <QVBoxLayout>
37 #include <QGridLayout>
38 #include <QHeaderView>
39
40 #include "components/complete_preferences.hpp"
41 #include "components/preferences_widgets.hpp"
42
43 #include <vlc_config_cat.h>
44 #include <vlc_intf_strings.h>
45 #include <vlc_modules.h>
46 #include <assert.h>
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     /* General Qt options */
57     setAlternatingRowColors( true );
58     setHeaderHidden( true );
59
60     setIconSize( QSize( ITEM_HEIGHT,ITEM_HEIGHT ) );
61     setTextElideMode( Qt::ElideNone );
62
63     /* Nice icons */
64 #define BI( a,b) QIcon a##_icon = QIcon( b )
65     BI( audio, ":/prefsmenu/advanced/audio" );
66     BI( video, ":/prefsmenu/advanced/video" );
67     BI( input, ":/prefsmenu/advanced/codec" );
68     BI( sout, ":/prefsmenu/advanced/sout" );
69     BI( advanced, ":/prefsmenu/advanced/extended" );
70     BI( playlist, ":/prefsmenu/advanced/playlist" );
71     BI( interface, ":/prefsmenu/advanced/intf" );
72 #undef BI
73
74     /* Build the tree for the main module */
75     module_t *p_module = module_get_main();
76
77     /* Initialisation and get the confsize */
78     PrefsItemData *data = NULL;
79     PrefsItemData *data_sub = NULL;
80     QTreeWidgetItem *current_item = NULL;
81     unsigned confsize;
82     module_config_t *const p_config = module_config_get (p_module, &confsize);
83
84     /* Go through the list of conf */
85     for( size_t i = 0; i < confsize; i++ )
86     {
87         const char *psz_help;
88         QIcon icon;
89
90         /* Work on a new item */
91         module_config_t *p_item = p_config + i;
92
93         switch( p_item->i_type )
94         {
95         /* This is a category */
96         case CONFIG_CATEGORY:
97             if( p_item->value.i == -1 ) break;
98
99             /* PrefsItemData Init */
100             data = new PrefsItemData();
101             data->name = qtr( config_CategoryNameGet( p_item->value.i ) );
102             psz_help = config_CategoryHelpGet( p_item->value.i );
103             if( psz_help )
104                 data->help = qtr( psz_help );
105             else
106                 data->help.clear();
107             data->i_type = TYPE_CATEGORY;
108             data->i_object_id = p_item->value.i;
109
110             /* This is a category, put a nice icon */
111             switch( p_item->value.i )
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             }
122 #undef CI
123
124             /* Create a new QTreeItem to display it in the tree at top level */
125             current_item = new QTreeWidgetItem();
126             current_item->setText( 0, data->name );
127             current_item->setIcon( 0 , icon );
128             //current_item->setSizeHint( 0, QSize( -1, ITEM_HEIGHT ) );
129             current_item->setData( 0, Qt::UserRole,
130                                    qVariantFromValue( data ) );
131             addTopLevelItem( current_item );
132             break;
133
134         /* This is a subcategory */
135         case CONFIG_SUBCATEGORY:
136             if( p_item->value.i == -1 ) break;
137
138             /* Special cases: move the main subcategories to the parent cat*/
139             if( data &&
140                 ( p_item->value.i == SUBCAT_VIDEO_GENERAL ||
141                   p_item->value.i == SUBCAT_ADVANCED_MISC ||
142                   p_item->value.i == SUBCAT_INPUT_GENERAL ||
143                   p_item->value.i == SUBCAT_INTERFACE_GENERAL ||
144                   p_item->value.i == SUBCAT_SOUT_GENERAL||
145                   p_item->value.i == SUBCAT_PLAYLIST_GENERAL||
146                   p_item->value.i == SUBCAT_AUDIO_GENERAL ) )
147             {
148                 /* Data still contains the correct thing */
149                 data->i_type = TYPE_CATSUBCAT;
150                 data->i_subcat_id = p_item->value.i;
151                 data->name = qtr( config_CategoryNameGet( p_item->value.i ) );
152                 psz_help = config_CategoryHelpGet( p_item->value.i );
153                 if( psz_help )
154                     data->help = qtr( psz_help );
155                 else
156                     data->help.clear();
157                 current_item->setData( 0, Qt::UserRole,
158                                        QVariant::fromValue( data ) );
159                 continue;
160             }
161
162             /* Normal Subcategories */
163
164             /* Process the Data */
165             data_sub = new PrefsItemData();
166             data_sub->name = qtr( config_CategoryNameGet( p_item->value.i) );
167             psz_help = config_CategoryHelpGet( p_item->value.i );
168             if( psz_help )
169                 data_sub->help = qtr( psz_help );
170             else
171                 data_sub->help.clear();
172             data_sub->i_type = TYPE_SUBCATEGORY;
173             data_sub->i_object_id = p_item->value.i;
174
175             /* Create a new TreeWidget */
176             QTreeWidgetItem *subcat_item = new QTreeWidgetItem();
177             subcat_item->setText( 0, data_sub->name );
178             subcat_item->setData( 0, Qt::UserRole,
179                                   qVariantFromValue( data_sub ) );
180             //subcat_item->setSizeHint( 0, QSize( -1, ITEM_HEIGHT ) );
181
182             /* Add it to the parent */
183             assert( current_item );
184             current_item->addChild( subcat_item );
185             break;
186
187         /* Other items don't need yet a place on the tree */
188         }
189     }
190     module_config_free( p_config );
191     module_release( p_module );
192
193
194     module_t **p_list = module_list_get( NULL );
195     /* Build the tree of plugins */
196     for( size_t i = 0; (p_module = p_list[i]) != NULL; i++ )
197     {
198         // Main module excluded
199         if( module_is_main( p_module) ) continue;
200
201         unsigned  confsize;
202         int i_subcategory = 0, i_category = 0;
203
204         bool b_options = false;
205         module_config_t *const p_config = module_config_get (p_module, &confsize);
206
207         /* Loop through the configurations items */
208         for (size_t i = 0; i < confsize; i++)
209         {
210             const module_config_t *p_item = p_config + i;
211
212             if( p_item->i_type == CONFIG_CATEGORY )
213                 i_category = p_item->value.i;
214             else if( p_item->i_type == CONFIG_SUBCATEGORY )
215                 i_subcategory = p_item->value.i;
216
217             if( p_item->i_type & CONFIG_ITEM )
218                 b_options = true;
219
220             if( b_options && i_category && i_subcategory )
221                 break;
222         }
223         module_config_free (p_config);
224
225         /* Dummy item, please proceed */
226         if( !b_options || i_category == 0 || i_subcategory == 0 ) continue;
227
228
229         // Locate the category item;
230         QTreeWidgetItem *subcat_item = NULL;
231         bool b_found = false;
232
233         for( int i_cat_index = 0 ; i_cat_index < topLevelItemCount();
234                                    i_cat_index++ )
235         {
236             /* Get the treeWidgetItem that correspond to the category */
237             QTreeWidgetItem *cat_item = topLevelItem( i_cat_index );
238             PrefsItemData *data = cat_item->data( 0, Qt::UserRole ).
239                                              value<PrefsItemData *>();
240
241             /* If we match the good category */
242             if( data->i_object_id == i_category )
243             {
244                 for( int i_sc_index = 0; i_sc_index < cat_item->childCount();
245                          i_sc_index++ )
246                 {
247                     subcat_item = cat_item->child( i_sc_index );
248                     PrefsItemData *sc_data = subcat_item->data(0, Qt::UserRole).
249                                                 value<PrefsItemData *>();
250                     if( sc_data && sc_data->i_object_id == i_subcategory )
251                     {
252                         b_found = true;
253                         break;
254                     }
255                 }
256                 if( !b_found )
257                 {
258                     subcat_item = cat_item;
259                     b_found = true;
260                 }
261                 break;
262             }
263         }
264         if( !b_found ) continue;
265
266         PrefsItemData *module_data = new PrefsItemData();
267         module_data->i_type = TYPE_MODULE;
268         module_data->psz_name = strdup( module_get_object( p_module ) );
269         module_data->help.clear();
270         QTreeWidgetItem *module_item = new QTreeWidgetItem();
271         module_item->setText( 0, qtr( module_get_name( p_module, false ) ) );
272         module_item->setData( 0, Qt::UserRole,
273                               QVariant::fromValue( module_data) );
274         //module_item->setSizeHint( 0, QSize( -1, ITEM_HEIGHT ) );
275         subcat_item->addChild( module_item );
276     }
277
278     /* We got everything, just sort a bit */
279     sortItems( 0, Qt::AscendingOrder );
280
281     module_list_free( p_list );
282     resizeColumnToContents( 0 );
283 }
284
285 PrefsTree::~PrefsTree() {}
286
287 void PrefsTree::applyAll()
288 {
289     doAll( false );
290 }
291
292 void PrefsTree::cleanAll()
293 {
294     doAll( true );
295 }
296
297 void PrefsTree::doAll( bool doclean )
298 {
299     for( int i_cat_index = 0 ; i_cat_index < topLevelItemCount();
300              i_cat_index++ )
301     {
302         QTreeWidgetItem *cat_item = topLevelItem( i_cat_index );
303         for( int i_sc_index = 0; i_sc_index < cat_item->childCount();
304                  i_sc_index++ )
305         {
306             QTreeWidgetItem *sc_item = cat_item->child( i_sc_index );
307             for( int i_module = 0 ; i_module < sc_item->childCount();
308                      i_module++ )
309             {
310                 PrefsItemData *data = sc_item->child( i_module )->
311                                data( 0, Qt::UserRole).value<PrefsItemData *>();
312                 if( data->panel && doclean )
313                 {
314                     delete data->panel;
315                     data->panel = NULL;
316                 }
317                 else if( data->panel )
318                     data->panel->apply();
319             }
320             PrefsItemData *data = sc_item->data( 0, Qt::UserRole).
321                                             value<PrefsItemData *>();
322             if( data->panel && doclean )
323             {
324                 delete data->panel;
325                 data->panel = NULL;
326             }
327             else if( data->panel )
328                 data->panel->apply();
329         }
330         PrefsItemData *data = cat_item->data( 0, Qt::UserRole).
331                                             value<PrefsItemData *>();
332         if( data->panel && doclean )
333         {
334             delete data->panel;
335             data->panel = NULL;
336         }
337         else if( data->panel )
338             data->panel->apply();
339     }
340 }
341
342 /*********************************************************************
343  * The Panel
344  *********************************************************************/
345 AdvPrefsPanel::AdvPrefsPanel( QWidget *_parent ) : QWidget( _parent )
346 {}
347
348 AdvPrefsPanel::AdvPrefsPanel( intf_thread_t *_p_intf, QWidget *_parent,
349                         PrefsItemData * data ) :
350                         QWidget( _parent ), p_intf( _p_intf )
351 {
352     /* Find our module */
353     module_t *p_module = NULL;
354     if( data->i_type == TYPE_CATEGORY )
355         return;
356     else if( data->i_type == TYPE_MODULE )
357         p_module = module_find( data->psz_name );
358     else
359     {
360         p_module = module_get_main();
361         assert( p_module );
362     }
363
364     unsigned confsize;
365     module_config_t *const p_config = module_config_get (p_module, &confsize),
366                     *p_item = p_config,
367                     *p_end = p_config + confsize;
368
369     if( data->i_type == TYPE_SUBCATEGORY || data->i_type ==  TYPE_CATSUBCAT )
370     {
371         while (p_item < p_end)
372         {
373             if(  p_item->i_type == CONFIG_SUBCATEGORY &&
374                             ( ( data->i_type == TYPE_SUBCATEGORY &&
375                               p_item->value.i == data->i_object_id ) ||
376                             ( data->i_type == TYPE_CATSUBCAT &&
377                               p_item->value.i == data->i_subcat_id ) ) )
378                 break;
379             p_item++;
380         }
381     }
382
383     /* Widgets now */
384     global_layout = new QVBoxLayout();
385     global_layout->setMargin( 2 );
386     QString head;
387     QString help;
388
389     help = QString( data->help );
390
391     if( data->i_type == TYPE_SUBCATEGORY || data->i_type ==  TYPE_CATSUBCAT )
392     {
393         head = QString( data->name );
394         p_item++; // Why that ?
395     }
396     else
397     {
398         const char *psz_help = module_get_help (p_module);
399         head = QString( qtr( module_GetLongName( p_module ) ) );
400         if( psz_help )
401         {
402             help.append( "\n" );
403             help.append( qtr( psz_help ) );
404         }
405     }
406
407     QLabel *titleLabel = new QLabel( head );
408     QFont titleFont = QApplication::font();
409     titleFont.setPointSize( titleFont.pointSize() + 6 );
410     titleLabel->setFont( titleFont );
411
412     // Title <hr>
413     QFrame *title_line = new QFrame;
414     title_line->setFrameShape(QFrame::HLine);
415     title_line->setFrameShadow(QFrame::Sunken);
416
417     QLabel *helpLabel = new QLabel( help, this );
418     helpLabel->setWordWrap( true );
419
420     global_layout->addWidget( titleLabel );
421     global_layout->addWidget( title_line );
422     global_layout->addWidget( helpLabel );
423
424     QGroupBox *box = NULL;
425     QGridLayout *boxlayout = NULL;
426
427     QScrollArea *scroller= new QScrollArea;
428     scroller->setFrameStyle( QFrame::NoFrame );
429     QWidget *scrolled_area = new QWidget;
430
431     QGridLayout *layout = new QGridLayout();
432     int i_line = 0, i_boxline = 0;
433     bool has_hotkey = false;
434
435     if( p_item ) do
436     {
437         if( ( ( data->i_type == TYPE_SUBCATEGORY &&
438                 p_item->value.i != data->i_object_id ) ||
439               ( data->i_type == TYPE_CATSUBCAT  &&
440                 p_item->value.i != data->i_subcat_id ) ) &&
441             ( p_item->i_type == CONFIG_CATEGORY ||
442               p_item->i_type == CONFIG_SUBCATEGORY ) )
443             break;
444         if( p_item->b_internal == true ) continue;
445
446         if( p_item->i_type == CONFIG_SECTION )
447         {
448             if( box )
449             {
450                 box->setLayout( boxlayout );
451                 box->show();
452                 layout->addWidget( box, i_line, 0, 1, -1 );
453                 i_line++;
454             }
455             box = new QGroupBox( qtr( p_item->psz_text ), this );
456             box->hide();
457             boxlayout = new QGridLayout();
458         }
459         /* Only one hotkey control */
460         if( has_hotkey && p_item->i_type & CONFIG_ITEM && p_item->psz_name &&
461                                          strstr( p_item->psz_name, "key-" ) )
462             continue;
463         if( p_item->i_type & CONFIG_ITEM && p_item->psz_name &&
464                                             strstr( p_item->psz_name, "key-" ) )
465             has_hotkey = true;
466
467         ConfigControl *control;
468         if( ! box )
469             control = ConfigControl::createControl( VLC_OBJECT( p_intf ),
470                                         p_item, this, layout, i_line );
471         else
472             control = ConfigControl::createControl( VLC_OBJECT( p_intf ),
473                                     p_item, this, boxlayout, i_boxline );
474         if( !control )
475             continue;
476
477         if( box ) i_boxline++;
478         else i_line++;
479         controls.append( control );
480     }
481     while( !( ( data->i_type == TYPE_SUBCATEGORY ||
482                data->i_type == TYPE_CATSUBCAT ) &&
483              ( p_item->i_type == CONFIG_CATEGORY ||
484                p_item->i_type == CONFIG_SUBCATEGORY ) )
485         && ( ++p_item < p_end ) );
486
487     if( box )
488     {
489         box->setLayout( boxlayout );
490         box->show();
491         layout->addWidget( box, i_line, 0, 1, -1 );
492     }
493
494     module_release (p_module);
495
496     scrolled_area->setSizePolicy( QSizePolicy::Preferred,QSizePolicy::Fixed );
497     scrolled_area->setLayout( layout );
498     scroller->setWidget( scrolled_area );
499     scroller->setWidgetResizable( true );
500     global_layout->addWidget( scroller );
501     setLayout( global_layout );
502 }
503
504 void AdvPrefsPanel::apply()
505 {
506     QList<ConfigControl *>::Iterator i;
507     for( i = controls.begin() ; i != controls.end() ; i++ )
508     {
509         ConfigControl *c = qobject_cast<ConfigControl *>(*i);
510         c->doApply( p_intf );
511     }
512 }
513
514 void AdvPrefsPanel::clean()
515 {}
516
517 AdvPrefsPanel::~AdvPrefsPanel()
518 {
519     qDeleteAll( controls ); controls.clear();
520 }
521