]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/complete_preferences.cpp
UI: prefix/namespace resources for better maintainability
[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 <assert.h>
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     /* General Qt options */
56     setColumnCount( 1 );
57     setAlternatingRowColors( true );
58     header()->hide();
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( QPixmap( 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 }
283
284 PrefsTree::~PrefsTree() {}
285
286 void PrefsTree::applyAll()
287 {
288     doAll( false );
289 }
290
291 void PrefsTree::cleanAll()
292 {
293     doAll( true );
294 }
295
296 void PrefsTree::doAll( bool doclean )
297 {
298     for( int i_cat_index = 0 ; i_cat_index < topLevelItemCount();
299              i_cat_index++ )
300     {
301         QTreeWidgetItem *cat_item = topLevelItem( i_cat_index );
302         for( int i_sc_index = 0; i_sc_index < cat_item->childCount();
303                  i_sc_index++ )
304         {
305             QTreeWidgetItem *sc_item = cat_item->child( i_sc_index );
306             for( int i_module = 0 ; i_module < sc_item->childCount();
307                      i_module++ )
308             {
309                 PrefsItemData *data = sc_item->child( i_module )->
310                                data( 0, Qt::UserRole).value<PrefsItemData *>();
311                 if( data->panel && doclean )
312                 {
313                     delete data->panel;
314                     data->panel = NULL;
315                 }
316                 else if( data->panel )
317                     data->panel->apply();
318             }
319             PrefsItemData *data = sc_item->data( 0, Qt::UserRole).
320                                             value<PrefsItemData *>();
321             if( data->panel && doclean )
322             {
323                 delete data->panel;
324                 data->panel = NULL;
325             }
326             else if( data->panel )
327                 data->panel->apply();
328         }
329         PrefsItemData *data = cat_item->data( 0, Qt::UserRole).
330                                             value<PrefsItemData *>();
331         if( data->panel && doclean )
332         {
333             delete data->panel;
334             data->panel = NULL;
335         }
336         else if( data->panel )
337             data->panel->apply();
338     }
339 }
340
341 /*********************************************************************
342  * The Panel
343  *********************************************************************/
344 AdvPrefsPanel::AdvPrefsPanel( QWidget *_parent ) : QWidget( _parent )
345 {}
346
347 AdvPrefsPanel::AdvPrefsPanel( intf_thread_t *_p_intf, QWidget *_parent,
348                         PrefsItemData * data ) :
349                         QWidget( _parent ), p_intf( _p_intf )
350 {
351     /* Find our module */
352     module_t *p_module = NULL;
353     if( data->i_type == TYPE_CATEGORY )
354         return;
355     else if( data->i_type == TYPE_MODULE )
356         p_module = module_find( data->psz_name );
357     else
358     {
359         p_module = module_get_main();
360         assert( p_module );
361     }
362
363     unsigned confsize;
364     module_config_t *const p_config = module_config_get (p_module, &confsize),
365                     *p_item = p_config,
366                     *p_end = p_config + confsize;
367
368     if( data->i_type == TYPE_SUBCATEGORY || data->i_type ==  TYPE_CATSUBCAT )
369     {
370         while (p_item < p_end)
371         {
372             if(  p_item->i_type == CONFIG_SUBCATEGORY &&
373                             ( ( data->i_type == TYPE_SUBCATEGORY &&
374                               p_item->value.i == data->i_object_id ) ||
375                             ( data->i_type == TYPE_CATSUBCAT &&
376                               p_item->value.i == data->i_subcat_id ) ) )
377                 break;
378             p_item++;
379         }
380     }
381
382     /* Widgets now */
383     global_layout = new QVBoxLayout();
384     global_layout->setMargin( 2 );
385     QString head;
386     QString help;
387
388     help = QString( data->help );
389
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         const char *psz_help = module_get_help (p_module);
398         head = QString( qtr( module_GetLongName( p_module ) ) );
399         if( psz_help )
400         {
401             help.append( "\n" );
402             help.append( qtr( psz_help ) );
403         }
404     }
405
406     QLabel *titleLabel = new QLabel( head );
407     QFont titleFont = QApplication::font( static_cast<QWidget*>(0) );
408     titleFont.setPointSize( titleFont.pointSize() + 6 );
409     titleFont.setFamily( "Verdana" );
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