* disable Screen Capturing on OSX until it is fixed because it blocks all builds...
[vlc.git] / modules / gui / qt4 / components / preferences_widgets.cpp
1 /*****************************************************************************
2  * preferences_widgets.cpp : Widgets for preferences displays
3  ****************************************************************************
4  * Copyright (C) 2006-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *          Antoine Cellerier <dionoea@videolan.org>
9  *          Jean-Baptiste Kempf <jb@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /**
27  * Todo:
28  *  - Finish implementation (see WX, there might be missing a
29  *    i_action handler for IntegerLists, but I don't see any module using it...
30  *  - Improvements over WX
31  *      - Validator for modulelist
32  */
33
34 #include "components/preferences_widgets.hpp"
35 #include "util/customwidgets.hpp"
36
37 #include <vlc_keys.h>
38
39 #include <QString>
40 #include <QVariant>
41 #include <QGridLayout>
42 #include <QSlider>
43 #include <QFileDialog>
44 #include <QFontDialog>
45 #include <QGroupBox>
46 #include <QTreeWidgetItem>
47 #include <QSignalMapper>
48 #include <QDialogButtonBox>
49
50 QString formatTooltip(const QString & tooltip)
51 {
52     QString formatted =
53     "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">"
54     " p, li { white-space: pre-wrap; } </style></head><body style=\" font-family:'Sans Serif';"
55     " font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;\">"
56     "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; "
57     "-qt-block-indent:0; text-indent:0px;\">" +
58     tooltip +
59     "</p></body></html>";
60     return formatted;
61 }
62
63 ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
64                                              module_config_t *p_item,
65                                              QWidget *parent )
66 {
67     int i=0;
68     return createControl( p_this, p_item, parent, NULL, i );
69 }
70
71 ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
72                                              module_config_t *p_item,
73                                              QWidget *parent,
74                                              QGridLayout *l, int &line )
75 {
76     ConfigControl *p_control = NULL;
77     if( p_item->psz_current || p_item->b_unsaveable ) return NULL;
78
79     switch( p_item->i_type )
80     {
81     case CONFIG_ITEM_MODULE:
82         p_control = new ModuleConfigControl( p_this, p_item, parent, false,
83                                              l, line );
84         break;
85     case CONFIG_ITEM_MODULE_CAT:
86         p_control = new ModuleConfigControl( p_this, p_item, parent, true,
87                                              l, line );
88         break;
89     case CONFIG_ITEM_MODULE_LIST:
90         p_control = new ModuleListConfigControl( p_this, p_item, parent, false,
91                                              l, line );
92         break;
93     case CONFIG_ITEM_MODULE_LIST_CAT:
94         p_control = new ModuleListConfigControl( p_this, p_item, parent, true,
95                                              l, line );
96         break;
97     case CONFIG_ITEM_STRING:
98         if( !p_item->i_list )
99             p_control = new StringConfigControl( p_this, p_item, parent,
100                                                  l, line, false );
101         else
102             p_control = new StringListConfigControl( p_this, p_item,
103                                             parent, false, l, line );
104         break;
105     case CONFIG_ITEM_PASSWORD:
106         if( !p_item->i_list )
107             p_control = new StringConfigControl( p_this, p_item, parent,
108                                                  l, line, true );
109         else
110             p_control = new StringListConfigControl( p_this, p_item,
111                                             parent, true, l, line );
112         break;
113     case CONFIG_ITEM_INTEGER:
114         if( p_item->i_list )
115             p_control = new IntegerListConfigControl( p_this, p_item,
116                                             parent, false, l, line );
117         else if( p_item->min.i || p_item->max.i )
118             p_control = new IntegerRangeConfigControl( p_this, p_item, parent,
119                                                        l, line );
120         else
121             p_control = new IntegerConfigControl( p_this, p_item, parent,
122                                                   l, line );
123         break;
124     case CONFIG_ITEM_FILE:
125         p_control = new FileConfigControl( p_this, p_item, parent, l,
126                                                 line, false );
127         break;
128     case CONFIG_ITEM_DIRECTORY:
129         p_control = new DirectoryConfigControl( p_this, p_item, parent, l,
130                                                 line, false );
131         break;
132     case CONFIG_ITEM_FONT:
133         p_control = new FontConfigControl( p_this, p_item, parent, l,
134                                            line, false );
135         break;
136     case CONFIG_ITEM_KEY:
137         p_control = new KeySelectorControl( p_this, p_item, parent, l, line );
138         break;
139     case CONFIG_ITEM_BOOL:
140         p_control = new BoolConfigControl( p_this, p_item, parent, l, line );
141         break;
142     case CONFIG_ITEM_FLOAT:
143         if( p_item->min.f || p_item->max.f )
144             p_control = new FloatRangeConfigControl( p_this, p_item, parent,
145                                                      l, line );
146         else
147             p_control = new FloatConfigControl( p_this, p_item, parent,
148                                                   l, line );
149         break;
150     default:
151         break;
152     }
153     return p_control;
154 }
155
156 void ConfigControl::doApply( intf_thread_t *p_intf )
157 {
158     switch( getType() )
159     {
160         case 1:
161         {
162             VIntConfigControl *vicc = qobject_cast<VIntConfigControl *>(this);
163             assert( vicc );
164             config_PutInt( p_intf, vicc->getName(), vicc->getValue() );
165             break;
166         }
167         case 2:
168         {
169             VFloatConfigControl *vfcc =
170                                     qobject_cast<VFloatConfigControl *>(this);
171             assert( vfcc );
172             config_PutFloat( p_intf, vfcc->getName(), vfcc->getValue() );
173             break;
174         }
175         case 3:
176         {
177             VStringConfigControl *vscc =
178                             qobject_cast<VStringConfigControl *>(this);
179             assert( vscc );
180             config_PutPsz( p_intf, vscc->getName(), qta( vscc->getValue() ) );
181             break;
182         }
183         case 4:
184         {
185             KeySelectorControl *ksc = qobject_cast<KeySelectorControl *>(this);
186             assert( ksc );
187             ksc->doApply();
188         }
189     }
190 }
191
192 /**************************************************************************
193  * String-based controls
194  *************************************************************************/
195
196 /*********** String **************/
197 StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
198                                           module_config_t *_p_item,
199                                           QWidget *_parent, QGridLayout *l,
200                                           int &line, bool pwd ) :
201                            VStringConfigControl( _p_this, _p_item, _parent )
202 {
203     label = new QLabel( qtr(p_item->psz_text) );
204     text = new QLineEdit( qfu(p_item->value.psz) );
205     if( pwd ) text->setEchoMode( QLineEdit::Password );
206     finish();
207
208     if( !l )
209     {
210         QHBoxLayout *layout = new QHBoxLayout();
211         layout->addWidget( label, 0 ); layout->addWidget( text, 1 );
212         widget->setLayout( layout );
213     }
214     else
215     {
216         l->addWidget( label, line, 0 ); l->addWidget( text, line, 1 );
217     }
218 }
219
220 StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
221                                    module_config_t *_p_item,
222                                    QLabel *_label, QLineEdit *_text, bool pwd ):
223                            VStringConfigControl( _p_this, _p_item )
224 {
225     text = _text;
226     label = _label;
227     finish( );
228 }
229
230 void StringConfigControl::finish()
231 {
232     text->setText( qfu(p_item->value.psz) );
233     text->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
234     if( label )
235         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
236 }
237
238 /*********** File **************/
239 FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
240                                           module_config_t *_p_item,
241                                           QWidget *_parent, QGridLayout *l,
242                                           int &line, bool pwd ) :
243                            VStringConfigControl( _p_this, _p_item, _parent )
244 {
245     label = new QLabel( qtr(p_item->psz_text) );
246     text = new QLineEdit( qfu(p_item->value.psz) );
247     browse = new QPushButton( qtr( "Browse..." ) );
248     QHBoxLayout *textAndButton = new QHBoxLayout();
249     textAndButton->setMargin( 0 );
250     textAndButton->addWidget( text, 2 );
251     textAndButton->addWidget( browse, 0 );
252
253     BUTTONACT( browse, updateField() );
254
255     finish();
256
257     if( !l )
258     {
259         QHBoxLayout *layout = new QHBoxLayout();
260         layout->addWidget( label, 0 );
261         layout->addLayout( textAndButton, 1 );
262         widget->setLayout( layout );
263     }
264     else
265     {
266         l->addWidget( label, line, 0 );
267         l->addLayout( textAndButton, line, 1 );
268     }
269 }
270
271
272 FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
273                                    module_config_t *_p_item,
274                                    QLabel *_label, QLineEdit *_text,
275                                    QPushButton *_button, bool pwd ):
276                            VStringConfigControl( _p_this, _p_item )
277 {
278     browse = _button;
279     text = _text;
280     label = _label;
281
282     BUTTONACT( browse, updateField() );
283
284     finish( );
285 }
286
287 void FileConfigControl::updateField()
288 {
289     QString file = QFileDialog::getOpenFileName( NULL,
290                   qtr( "Select File" ), qfu( p_this->p_libvlc->psz_homedir ) );
291     if( file.isNull() ) return;
292     text->setText( file );
293 }
294
295 void FileConfigControl::finish()
296 {
297     text->setText( qfu(p_item->value.psz) );
298     text->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
299     if( label )
300         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
301 }
302
303 /********* String / Directory **********/
304 DirectoryConfigControl::DirectoryConfigControl( vlc_object_t *_p_this,
305                         module_config_t *_p_item, QWidget *_p_widget,
306                         QGridLayout *_p_layout, int& _int, bool _pwd ) :
307      FileConfigControl( _p_this, _p_item, _p_widget, _p_layout, _int, _pwd)
308 {}
309
310 DirectoryConfigControl::DirectoryConfigControl( vlc_object_t *_p_this,
311                         module_config_t *_p_item, QLabel *_p_label,
312                         QLineEdit *_p_line, QPushButton *_p_button, bool _pwd ):
313      FileConfigControl( _p_this, _p_item, _p_label, _p_line, _p_button, _pwd)
314 {}
315
316 void DirectoryConfigControl::updateField()
317 {
318     QString dir = QFileDialog::getExistingDirectory( NULL,
319                       qtr( "Select Directory" ),
320                       text->text().isEmpty() ?
321                         qfu( p_this->p_libvlc->psz_homedir ) : text->text(),
322                       QFileDialog::ShowDirsOnly |
323                         QFileDialog::DontResolveSymlinks );
324     if( dir.isNull() ) return;
325     text->setText( dir );
326 }
327
328 /********* String / Font **********/
329 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
330                         module_config_t *_p_item, QWidget *_p_widget,
331                         QGridLayout *_p_layout, int& _int, bool _pwd ) :
332      FileConfigControl( _p_this, _p_item, _p_widget, _p_layout, _int, _pwd)
333 {}
334
335 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
336                         module_config_t *_p_item, QLabel *_p_label,
337                         QLineEdit *_p_line, QPushButton *_p_button, bool _pwd ):
338      FileConfigControl( _p_this, _p_item, _p_label, _p_line, _p_button, _pwd)
339 {}
340
341 void FontConfigControl::updateField()
342 {
343     bool ok;
344     QFont font = QFontDialog::getFont( &ok, QFont( text->text() ), NULL );
345     if( !ok ) return;
346     text->setText( font.family() );
347 }
348
349 /********* String / choice list **********/
350 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
351                module_config_t *_p_item, QWidget *_parent, bool bycat,
352                QGridLayout *l, int &line) :
353                VStringConfigControl( _p_this, _p_item, _parent )
354 {
355     label = new QLabel( qtr(p_item->psz_text) );
356     combo = new QComboBox();
357     finish( bycat );
358     if( !l )
359     {
360         QHBoxLayout *layout = new QHBoxLayout();
361         layout->addWidget( label ); layout->addWidget( combo );
362         widget->setLayout( layout );
363     }
364     else
365     {
366         l->addWidget( label, line, 0 );
367         l->addWidget( combo, line, 1, Qt::AlignRight );
368     }
369
370     if( p_item->i_action )
371     {
372         QSignalMapper *signalMapper = new QSignalMapper(this);
373
374         /* Some stringLists like Capture listings have action associated */
375         for( int i = 0; i < p_item->i_action; i++ )
376         {
377             QPushButton *button =
378                 new QPushButton( qfu( p_item->ppsz_action_text[i] ));
379             CONNECT( button, clicked(), signalMapper, map() );
380             signalMapper->setMapping( button, i );
381             l->addWidget( button, line, 2 + i, Qt::AlignRight );
382         }
383         CONNECT( signalMapper, mapped( int ),
384                 this, actionRequested( int ) );
385     }
386 }
387
388 void StringListConfigControl::actionRequested( int i_action )
389 {
390     /* Supplementary check for boundaries */
391     if( i_action < 0 || i_action >= p_item->i_action ) return;
392
393     vlc_value_t val;
394     val.psz_string =
395         qtu( (combo->itemData( combo->currentIndex() ).toString() ) );
396
397     p_item->ppf_action[i_action]( p_this, getName(), val, val, 0 );
398
399     if( p_item->b_dirty )
400     {
401         combo->clear();
402         finish( true );
403         p_item->b_dirty = VLC_FALSE;
404     }
405 }
406 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
407                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
408                 bool bycat ) : VStringConfigControl( _p_this, _p_item )
409 {
410     combo = _combo;
411     label = _label;
412     finish( bycat );
413 }
414
415 void StringListConfigControl::finish( bool bycat )
416 {
417     combo->setEditable( false );
418
419     for( int i_index = 0; i_index < p_item->i_list; i_index++ )
420     {
421         combo->addItem( qfu(p_item->ppsz_list_text ?
422                             p_item->ppsz_list_text[i_index] :
423                             p_item->ppsz_list[i_index] ),
424                         QVariant( p_item->ppsz_list[i_index] ) );
425         if( p_item->value.psz && !strcmp( p_item->value.psz,
426                                           p_item->ppsz_list[i_index] ) )
427             combo->setCurrentIndex( combo->count() - 1 );
428     }
429     combo->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
430     if( label )
431         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
432 }
433
434 QString StringListConfigControl::getValue()
435 {
436     return combo->itemData( combo->currentIndex() ).toString();
437 }
438
439 void setfillVLCConfigCombo( const char *configname, intf_thread_t *p_intf,
440                         QComboBox *combo, QWidget *parent )
441 {
442     module_config_t *p_config =
443                       config_FindConfig( VLC_OBJECT(p_intf), configname );
444     if( p_config )
445     {
446         for ( int i_index = 0; i_index < p_config->i_list; i_index++ )
447         {
448             combo->addItem( qfu( p_config->ppsz_list_text[i_index] ),
449                     QVariant( p_config->pi_list[i_index] ) );
450             if( p_config->value.i == p_config->pi_list[i_index] )
451             {
452                 combo->setCurrentIndex( i_index );
453             }
454         }
455         combo->setToolTip( qfu( p_config->psz_longtext ) );
456     }
457 }
458
459 /********* Module **********/
460 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
461                module_config_t *_p_item, QWidget *_parent, bool bycat,
462                QGridLayout *l, int &line) :
463                VStringConfigControl( _p_this, _p_item, _parent )
464 {
465     label = new QLabel( qtr(p_item->psz_text) );
466     combo = new QComboBox();
467     finish( bycat );
468     if( !l )
469     {
470         QHBoxLayout *layout = new QHBoxLayout();
471         layout->addWidget( label ); layout->addWidget( combo );
472         widget->setLayout( layout );
473     }
474     else
475     {
476         l->addWidget( label, line, 0 );
477         l->addWidget( combo, line, 1, Qt::AlignRight );
478     }
479 }
480
481 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
482                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
483                 bool bycat ) : VStringConfigControl( _p_this, _p_item )
484 {
485     combo = _combo;
486     label = _label;
487     finish( bycat );
488 }
489
490 void ModuleConfigControl::finish( bool bycat )
491 {
492     vlc_list_t *p_list;
493     module_t *p_parser;
494
495     combo->setEditable( false );
496
497     /* build a list of available modules */
498     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
499     combo->addItem( qtr("Default") );
500     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
501     {
502         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
503
504         if( bycat )
505         {
506             if( !strcmp( module_GetObjName( p_parser ), "main" ) ) continue;
507
508             for (size_t i = 0; i < p_parser->confsize; i++)
509             {
510                 module_config_t *p_config = p_parser->p_config + i;
511                 /* Hack: required subcategory is stored in i_min */
512                 if( p_config->i_type == CONFIG_SUBCATEGORY &&
513                     p_config->value.i == p_item->min.i )
514                     combo->addItem( qtr( module_GetLongName( p_parser )),
515                                     QVariant( module_GetObjName( p_parser ) ) );
516                 if( p_item->value.psz && !strcmp( p_item->value.psz,
517                                                   module_GetObjName( p_parser ) ) )
518                     combo->setCurrentIndex( combo->count() - 1 );
519             }
520         }
521         else if( module_IsCapable( p_parser, p_item->psz_type ) )
522         {
523             combo->addItem( qtr(module_GetLongName( p_parser ) ),
524                             QVariant( module_GetObjName( p_parser ) ) );
525             if( p_item->value.psz && !strcmp( p_item->value.psz,
526                                               module_GetObjName( p_parser ) ) )
527                 combo->setCurrentIndex( combo->count() - 1 );
528         }
529     }
530     vlc_list_release( p_list );
531     combo->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
532     if( label )
533         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
534 }
535
536 QString ModuleConfigControl::getValue()
537 {
538     return combo->itemData( combo->currentIndex() ).toString();
539 }
540
541 /********* Module list **********/
542 ModuleListConfigControl::ModuleListConfigControl( vlc_object_t *_p_this,
543         module_config_t *_p_item, QWidget *_parent, bool bycat,
544         QGridLayout *l, int &line) :
545     VStringConfigControl( _p_this, _p_item, _parent )
546 {
547     groupBox = new QGroupBox ( qtr(p_item->psz_text) );
548     text = new QLineEdit();
549     QGridLayout *layoutGroupBox = new QGridLayout( groupBox );
550
551     finish( bycat );
552
553     int boxline = 0;
554     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
555             it != modules.end(); it++ )
556     {
557         layoutGroupBox->addWidget( (*it)->checkBox, boxline++, 0 );
558     }
559     layoutGroupBox->addWidget( text, boxline, 0 );
560
561     if( !l )
562     {
563         QVBoxLayout *layout = new QVBoxLayout();
564         layout->addWidget( groupBox, line, 0 );
565         widget->setLayout( layout );
566     }
567     else
568     {
569         l->addWidget( groupBox, line, 0, 1, -1 );
570     }
571
572     text->setToolTip( formatTooltip( qtr( p_item->psz_longtext) ) );
573 }
574
575 ModuleListConfigControl::~ModuleListConfigControl()
576 {
577     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
578             it != modules.end(); it++ )
579     {
580         delete *it;
581     }
582     delete groupBox;
583     delete text;
584 }
585
586 #define CHECKBOX_LISTS \
587 { \
588        QCheckBox *cb = new QCheckBox( qtr( module_GetLongName( p_parser ) ) );\
589        checkBoxListItem *cbl = new checkBoxListItem; \
590 \
591        CONNECT( cb, stateChanged( int ), this, onUpdate( int ) );\
592        cb->setToolTip( formatTooltip( qtr( module_GetLongName( p_parser ))));\
593        cbl->checkBox = cb; \
594 \
595        int i = -1; \
596        while( p_parser->pp_shortcuts[++i] != NULL); \
597        i--; \
598 \
599        cbl->psz_module = strdup( i>=0?p_parser->pp_shortcuts[i] \
600                                  : module_GetObjName( p_parser ) ); \
601        modules.push_back( cbl ); \
602 }
603
604
605 void ModuleListConfigControl::finish( bool bycat )
606 {
607     vlc_list_t *p_list;
608     module_t *p_parser;
609
610     /* build a list of available modules */
611     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
612     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
613     {
614         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
615
616         if( bycat )
617         {
618             if( !strcmp( module_GetObjName( p_parser ), "main" ) ) continue;
619
620             for (size_t i = 0; i < p_parser->confsize; i++)
621             {
622                 module_config_t *p_config = p_parser->p_config + i;
623                 /* Hack: required subcategory is stored in i_min */
624                 if( p_config->i_type == CONFIG_SUBCATEGORY &&
625                         p_config->value.i == p_item->min.i )
626                 {
627                     CHECKBOX_LISTS;
628                 }
629             }
630         }
631         else if( module_IsCapable( p_parser, p_item->psz_type ) )
632         {
633             CHECKBOX_LISTS;
634         }
635     }
636     vlc_list_release( p_list );
637     text->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
638     if( groupBox )
639         groupBox->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
640 }
641 #undef CHECKBOX_LISTS
642
643 QString ModuleListConfigControl::getValue()
644 {
645     return text->text();
646 }
647
648 void ModuleListConfigControl::hide()
649 {
650     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
651          it != modules.end(); it++ )
652     {
653         (*it)->checkBox->hide();
654     }
655     groupBox->hide();
656 }
657
658 void ModuleListConfigControl::show()
659 {
660     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
661          it != modules.end(); it++ )
662     {
663         (*it)->checkBox->show();
664     }
665     groupBox->show();
666 }
667
668
669 void ModuleListConfigControl::onUpdate( int value )
670 {
671     text->clear();
672     bool first = true;
673
674     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
675          it != modules.end(); it++ )
676     {
677         if( (*it)->checkBox->isChecked() )
678         {
679             if( first )
680             {
681                 text->setText( text->text() + (*it)->psz_module );
682                 first = false;
683             }
684             else
685             {
686                 text->setText( text->text() + ":" + (*it)->psz_module );
687             }
688         }
689     }
690 }
691
692 /**************************************************************************
693  * Integer-based controls
694  *************************************************************************/
695
696 /*********** Integer **************/
697 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
698                                             module_config_t *_p_item,
699                                             QWidget *_parent, QGridLayout *l,
700                                             int &line ) :
701                            VIntConfigControl( _p_this, _p_item, _parent )
702 {
703     label = new QLabel( qtr(p_item->psz_text) );
704     spin = new QSpinBox; spin->setMinimumWidth( 80 );
705     spin->setAlignment( Qt::AlignRight );
706     spin->setMaximumWidth( 90 );
707     finish();
708
709     if( !l )
710     {
711         QHBoxLayout *layout = new QHBoxLayout();
712         layout->addWidget( label, 0 ); layout->addWidget( spin, 1 );
713         widget->setLayout( layout );
714     }
715     else
716     {
717         l->addWidget( label, line, 0 );
718         l->addWidget( spin, line, 1, Qt::AlignRight );
719     }
720 }
721 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
722                                             module_config_t *_p_item,
723                                             QLabel *_label, QSpinBox *_spin ) :
724                                       VIntConfigControl( _p_this, _p_item )
725 {
726     spin = _spin;
727     label = _label;
728     finish();
729 }
730
731 void IntegerConfigControl::finish()
732 {
733     spin->setMaximum( 2000000000 );
734     spin->setMinimum( -2000000000 );
735     spin->setValue( p_item->value.i );
736     spin->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
737     if( label )
738         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
739 }
740
741 int IntegerConfigControl::getValue()
742 {
743     return spin->value();
744 }
745
746 /********* Integer range **********/
747 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
748                                             module_config_t *_p_item,
749                                             QWidget *_parent, QGridLayout *l,
750                                             int &line ) :
751             IntegerConfigControl( _p_this, _p_item, _parent, l, line )
752 {
753     finish();
754 }
755
756 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
757                                             module_config_t *_p_item,
758                                             QLabel *_label, QSpinBox *_spin ) :
759             IntegerConfigControl( _p_this, _p_item, _label, _spin )
760 {
761     finish();
762 }
763
764 void IntegerRangeConfigControl::finish()
765 {
766     spin->setMaximum( p_item->max.i );
767     spin->setMinimum( p_item->min.i );
768 }
769
770 IntegerRangeSliderConfigControl::IntegerRangeSliderConfigControl(
771                                             vlc_object_t *_p_this,
772                                             module_config_t *_p_item,
773                                             QLabel *_label, QSlider *_slider ):
774                     VIntConfigControl( _p_this, _p_item )
775 {
776     slider = _slider;
777     label = _label;
778     slider->setMaximum( p_item->max.i );
779     slider->setMinimum( p_item->min.i );
780     slider->setValue( p_item->value.i );
781     slider->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
782     if( label )
783         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
784 }
785
786 int IntegerRangeSliderConfigControl::getValue()
787 {
788         return slider->value();
789 }
790
791
792 /********* Integer / choice list **********/
793 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
794                module_config_t *_p_item, QWidget *_parent, bool bycat,
795                QGridLayout *l, int &line) :
796                VIntConfigControl( _p_this, _p_item, _parent )
797 {
798     label = new QLabel( qtr(p_item->psz_text) );
799     combo = new QComboBox();
800     finish( bycat );
801     if( !l )
802     {
803         QHBoxLayout *layout = new QHBoxLayout();
804         layout->addWidget( label ); layout->addWidget( combo );
805         widget->setLayout( layout );
806     }
807     else
808     {
809         l->addWidget( label, line, 0 );
810         l->addWidget( combo, line, 1, Qt::AlignRight );
811     }
812 }
813 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
814                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
815                 bool bycat ) : VIntConfigControl( _p_this, _p_item )
816 {
817     combo = _combo;
818     label = _label;
819     finish( bycat );
820 }
821
822 void IntegerListConfigControl::finish( bool bycat )
823 {
824     combo->setEditable( false );
825
826     for( int i_index = 0; i_index < p_item->i_list; i_index++ )
827     {
828         combo->addItem( qtr(p_item->ppsz_list_text[i_index] ),
829                         QVariant( p_item->pi_list[i_index] ) );
830         if( p_item->value.i == p_item->pi_list[i_index] )
831             combo->setCurrentIndex( combo->count() - 1 );
832     }
833     combo->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
834     if( label )
835         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
836 }
837
838 int IntegerListConfigControl::getValue()
839 {
840     return combo->itemData( combo->currentIndex() ).toInt();
841 }
842
843 /*********** Boolean **************/
844 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
845                                       module_config_t *_p_item,
846                                       QWidget *_parent, QGridLayout *l,
847                                       int &line ) :
848                     VIntConfigControl( _p_this, _p_item, _parent )
849 {
850     checkbox = new QCheckBox( qtr(p_item->psz_text) );
851     finish();
852
853     if( !l )
854     {
855         QHBoxLayout *layout = new QHBoxLayout();
856         layout->addWidget( checkbox, 0 );
857         widget->setLayout( layout );
858     }
859     else
860     {
861         l->addWidget( checkbox, line, 0 );
862     }
863 }
864 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
865                                       module_config_t *_p_item,
866                                       QLabel *_label,
867                                       QCheckBox *_checkbox,
868                                       bool bycat ) :
869                    VIntConfigControl( _p_this, _p_item )
870 {
871     checkbox = _checkbox;
872     finish();
873 }
874
875 void BoolConfigControl::finish()
876 {
877     checkbox->setCheckState( p_item->value.i == VLC_TRUE ? Qt::Checked
878                                                         : Qt::Unchecked );
879     checkbox->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
880 }
881
882 int BoolConfigControl::getValue()
883 {
884     return checkbox->checkState() == Qt::Checked ? VLC_TRUE : VLC_FALSE;
885 }
886
887 /**************************************************************************
888  * Float-based controls
889  *************************************************************************/
890
891 /*********** Float **************/
892 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
893                                         module_config_t *_p_item,
894                                         QWidget *_parent, QGridLayout *l,
895                                         int &line ) :
896                     VFloatConfigControl( _p_this, _p_item, _parent )
897 {
898     label = new QLabel( qtr(p_item->psz_text) );
899     spin = new QDoubleSpinBox; spin->setMinimumWidth( 80 );
900     spin->setMaximumWidth( 90 );
901     spin->setAlignment( Qt::AlignRight );
902     finish();
903
904     if( !l )
905     {
906         QHBoxLayout *layout = new QHBoxLayout();
907         layout->addWidget( label, 0 ); layout->addWidget( spin, 1 );
908         widget->setLayout( layout );
909     }
910     else
911     {
912         l->addWidget( label, line, 0 );
913         l->addWidget( spin, line, 1, Qt::AlignRight );
914     }
915 }
916
917 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
918                                         module_config_t *_p_item,
919                                         QLabel *_label,
920                                         QDoubleSpinBox *_spin ) :
921                     VFloatConfigControl( _p_this, _p_item )
922 {
923     spin = _spin;
924     label = _label;
925     finish();
926 }
927
928 void FloatConfigControl::finish()
929 {
930     spin->setMaximum( 2000000000. );
931     spin->setMinimum( -2000000000. );
932     spin->setSingleStep( 0.1 );
933     spin->setValue( (double)p_item->value.f );
934     spin->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
935     if( label )
936         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
937 }
938
939 float FloatConfigControl::getValue()
940 {
941     return (float)spin->value();
942 }
943
944 /*********** Float with range **************/
945 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
946                                         module_config_t *_p_item,
947                                         QWidget *_parent, QGridLayout *l,
948                                         int &line ) :
949                 FloatConfigControl( _p_this, _p_item, _parent, l, line )
950 {
951     finish();
952 }
953
954 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
955                                         module_config_t *_p_item,
956                                         QLabel *_label,
957                                         QDoubleSpinBox *_spin ) :
958                 FloatConfigControl( _p_this, _p_item, _label, _spin )
959 {
960     finish();
961 }
962
963 void FloatRangeConfigControl::finish()
964 {
965     spin->setMaximum( (double)p_item->max.f );
966     spin->setMinimum( (double)p_item->min.f );
967 }
968
969
970 /**********************************************************************
971  * Key selector widget
972  **********************************************************************/
973 KeySelectorControl::KeySelectorControl( vlc_object_t *_p_this,
974                                       module_config_t *_p_item,
975                                       QWidget *_parent, QGridLayout *l,
976                                       int &line ) :
977                                 ConfigControl( _p_this, _p_item, _parent )
978
979 {
980     QWidget *keyContainer = new QWidget;
981     QGridLayout *gLayout = new QGridLayout( keyContainer );
982
983     label = new QLabel(
984             qtr( "Select an action to change the associated hotkey") );
985
986     /* Deactivated for now
987     QLabel *searchLabel = new QLabel( qtr( "Search" ) );
988     QLineEdit *actionSearch = new QLineEdit;*/
989
990     table = new QTreeWidget;
991     table->setColumnCount(2);
992     table->headerItem()->setText( 0, qtr( "Action" ) );
993     table->headerItem()->setText( 1, qtr( "Shortcut" ) );
994
995     shortcutValue = new KeyShortcutEdit;
996     shortcutValue->setReadOnly(true);
997
998     QPushButton *clearButton = new QPushButton( qtr( "Clear" ) );
999     QPushButton *setButton = new QPushButton( qtr( "Set" ) );
1000     finish();
1001
1002     gLayout->addWidget( label, 0, 0, 1, 4 );
1003   /* deactivated for now
1004     gLayout->addWidget( searchLabel, 1, 0, 1, 2 );
1005     gLayout->addWidget( actionSearch, 1, 2, 1, 2 ); */
1006     gLayout->addWidget( table, 2, 0, 1, 4 );
1007     gLayout->addWidget( clearButton, 3, 0, 1, 1 );
1008     gLayout->addWidget( shortcutValue, 3, 1, 1, 2 );
1009     gLayout->addWidget( setButton, 3, 3, 1, 1 );
1010
1011     l->addWidget( keyContainer, line, 0, 1, 2 );
1012
1013     CONNECT( clearButton, clicked(), shortcutValue, clear() );
1014     BUTTONACT( setButton, setTheKey() );
1015 }
1016
1017 void KeySelectorControl::finish()
1018 {
1019     if( label )
1020         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1021
1022     /* Fill the table */
1023     table->setColumnCount( 2 );
1024     table->setAlternatingRowColors( true );
1025
1026     module_t *p_main = config_FindModule( p_this, "main" );
1027     assert( p_main );
1028
1029     for (size_t i = 0; i < p_main->confsize; i++)
1030     {
1031         module_config_t *p_item = p_main->p_config + i;
1032
1033         if( p_item->i_type & CONFIG_ITEM && p_item->psz_name &&
1034             strstr( p_item->psz_name , "key-" ) && !EMPTY_STR( p_item->psz_text ) )
1035         {
1036             QTreeWidgetItem *treeItem = new QTreeWidgetItem();
1037             treeItem->setText( 0, qtr( p_item->psz_text ) );
1038             treeItem->setText( 1, VLCKeyToString( p_item->value.i ) );
1039             treeItem->setData( 0, Qt::UserRole,
1040                                   QVariant::fromValue( (void*)p_item ) );
1041             values += p_item;
1042             table->addTopLevelItem( treeItem );
1043         }
1044     }
1045     table->resizeColumnToContents( 0 );
1046
1047     CONNECT( table, itemClicked( QTreeWidgetItem *, int ),
1048              this, select1Key( QTreeWidgetItem * ) );
1049     CONNECT( table, itemDoubleClicked( QTreeWidgetItem *, int ),
1050              this, selectKey( QTreeWidgetItem * ) );
1051     CONNECT( shortcutValue, pressed(), this, selectKey() );
1052 }
1053
1054 void KeySelectorControl::select1Key( QTreeWidgetItem *keyItem )
1055 {
1056     shortcutValue->setText( keyItem->text( 1 ) );
1057 }
1058
1059 void KeySelectorControl::selectKey( QTreeWidgetItem *keyItem )
1060 {
1061     /* This happens when triggered by ClickEater */
1062     if( keyItem == NULL ) keyItem = table->currentItem();
1063
1064     /* This can happen when nothing is selected on the treeView
1065        and the shortcutValue is clicked */
1066     if( !keyItem ) return;
1067
1068     module_config_t *p_keyItem = static_cast<module_config_t*>
1069                           (keyItem->data( 0, Qt::UserRole ).value<void*>());
1070
1071     KeyInputDialog *d = new KeyInputDialog( values, p_keyItem->psz_text, widget );
1072     d->exec();
1073     if( d->result() == QDialog::Accepted )
1074     {
1075         p_keyItem->value.i = d->keyValue;
1076         if( d->conflicts )
1077         {
1078             for( int i = 0; i < table->topLevelItemCount() ; i++ )
1079             {
1080                 QTreeWidgetItem *it = table->topLevelItem(i);
1081                 module_config_t *p_item = static_cast<module_config_t*>
1082                               (it->data( 0, Qt::UserRole ).value<void*>());
1083                 if( p_keyItem != p_item && p_item->value.i == d->keyValue )
1084                     p_item->value.i = 0;
1085                 shortcutValue->setText( VLCKeyToString( p_item->value.i ) );
1086             }
1087         }
1088         else
1089             shortcutValue->setText( VLCKeyToString( p_keyItem->value.i ) );
1090     }
1091     delete d;
1092 }
1093
1094 void KeySelectorControl::setTheKey()
1095 {
1096     table->currentItem()->setText( 1, shortcutValue->text() );
1097 }
1098
1099 void KeySelectorControl::doApply()
1100 {
1101     foreach( module_config_t *p_current, values )
1102     {
1103         config_PutInt( p_this, p_current->psz_name, p_current->value.i );
1104     }
1105 }
1106
1107 KeyInputDialog::KeyInputDialog( QList<module_config_t*>& _values,
1108                                 const char * _keyToChange,
1109                                 QWidget *_parent ) :
1110                                 QDialog( _parent ), keyValue(0)
1111 {
1112     setModal( true );
1113     values = _values;
1114     conflicts = false;
1115     keyToChange = _keyToChange;
1116
1117     setWindowTitle( qtr( "Hotkey for " ) + qfu( keyToChange)  );
1118
1119     vLayout = new QVBoxLayout( this );
1120     selected = new QLabel( qtr("Press the new keys for ") + qfu( keyToChange ) );
1121     vLayout->addWidget( selected , Qt::AlignCenter );
1122
1123     buttonBox = new QDialogButtonBox;
1124     QPushButton *ok = new QPushButton( qtr("OK") );
1125     QPushButton *cancel = new QPushButton( qtr("Cancel") );
1126     buttonBox->addButton( ok, QDialogButtonBox::AcceptRole );
1127     buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
1128
1129     vLayout->addWidget( buttonBox );
1130     buttonBox->hide();
1131
1132     CONNECT( buttonBox, accepted(), this, accept() );
1133     CONNECT( buttonBox, rejected(), this, reject() );
1134 }
1135
1136 void KeyInputDialog::checkForConflicts( int i_vlckey )
1137 {
1138     conflicts = false;
1139     module_config_t *p_current = NULL;
1140     /* Search for conflicts */
1141     foreach( p_current, values )
1142     {
1143         if( p_current->value.i == i_vlckey && strcmp( p_current->psz_text,
1144                                                     keyToChange ) )
1145         {
1146             conflicts = true;
1147             break;
1148         }
1149     }
1150
1151     if( conflicts )
1152     {
1153         QLabel *warning = new QLabel(
1154           qtr("Warning: the  key is already assigned to \"") +
1155           qfu( p_current->psz_text ) + "\"" );
1156         warning->setWordWrap( true );
1157         vLayout->insertWidget( 1, warning );
1158         buttonBox->show();
1159     }
1160     else accept();
1161 }
1162
1163 void KeyInputDialog::keyPressEvent( QKeyEvent *e )
1164 {
1165     if( e->key() == Qt::Key_Tab ) return;
1166     int i_vlck = qtEventToVLCKey( e );
1167     selected->setText( VLCKeyToString( i_vlck ) );
1168     checkForConflicts( i_vlck );
1169     keyValue = i_vlck;
1170 }
1171
1172 void KeyInputDialog::wheelEvent( QWheelEvent *e )
1173 {
1174     int i_vlck = qtWheelEventToVLCKey( e );
1175     selected->setText( VLCKeyToString( i_vlck ) );
1176     checkForConflicts( i_vlck );
1177     keyValue = i_vlck;
1178 }
1179
1180 void KeyShortcutEdit::mousePressEvent( QMouseEvent *)
1181 {
1182     emit pressed();
1183 }