63eb99cea36a9c9a9cc50105841e64767be1fd3e
[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
78     switch( p_item->i_type )
79     {
80     case CONFIG_ITEM_MODULE:
81         p_control = new ModuleConfigControl( p_this, p_item, parent, false,
82                                              l, line );
83         break;
84     case CONFIG_ITEM_MODULE_CAT:
85         p_control = new ModuleConfigControl( p_this, p_item, parent, true,
86                                              l, line );
87         break;
88     case CONFIG_ITEM_MODULE_LIST:
89         p_control = new ModuleListConfigControl( p_this, p_item, parent, false,
90                                              l, line );
91         break;
92     case CONFIG_ITEM_MODULE_LIST_CAT:
93         p_control = new ModuleListConfigControl( p_this, p_item, parent, true,
94                                              l, line );
95         break;
96     case CONFIG_ITEM_STRING:
97         if( !p_item->i_list )
98             p_control = new StringConfigControl( p_this, p_item, parent,
99                                                  l, line, false );
100         else
101             p_control = new StringListConfigControl( p_this, p_item,
102                                             parent, false, l, line );
103         break;
104     case CONFIG_ITEM_PASSWORD:
105         if( !p_item->i_list )
106             p_control = new StringConfigControl( p_this, p_item, parent,
107                                                  l, line, true );
108         else
109             p_control = new StringListConfigControl( p_this, p_item,
110                                             parent, true, l, line );
111         break;
112     case CONFIG_ITEM_INTEGER:
113         if( p_item->i_list )
114             p_control = new IntegerListConfigControl( p_this, p_item,
115                                             parent, false, l, line );
116         else if( p_item->min.i || p_item->max.i )
117             p_control = new IntegerRangeConfigControl( p_this, p_item, parent,
118                                                        l, line );
119         else
120             p_control = new IntegerConfigControl( p_this, p_item, parent,
121                                                   l, line );
122         break;
123     case CONFIG_ITEM_FILE:
124         p_control = new FileConfigControl( p_this, p_item, parent, l,
125                                                 line, false );
126         break;
127     case CONFIG_ITEM_DIRECTORY:
128         p_control = new DirectoryConfigControl( p_this, p_item, parent, l,
129                                                 line, false );
130         break;
131     case CONFIG_ITEM_FONT:
132         p_control = new FontConfigControl( p_this, p_item, parent, l,
133                                            line, false );
134         break;
135     case CONFIG_ITEM_KEY:
136         p_control = new KeySelectorControl( p_this, p_item, parent, l, line );
137         break;
138     case CONFIG_ITEM_BOOL:
139         p_control = new BoolConfigControl( p_this, p_item, parent, l, line );
140         break;
141     case CONFIG_ITEM_FLOAT:
142         if( p_item->min.f || p_item->max.f )
143             p_control = new FloatRangeConfigControl( p_this, p_item, parent,
144                                                      l, line );
145         else
146             p_control = new FloatConfigControl( p_this, p_item, parent,
147                                                   l, line );
148         break;
149     default:
150         break;
151     }
152     return p_control;
153 }
154
155 void ConfigControl::doApply( intf_thread_t *p_intf )
156 {
157     switch( getType() )
158     {
159         case CONFIG_ITEM_INTEGER:
160         case CONFIG_ITEM_BOOL:
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 CONFIG_ITEM_FLOAT:
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 CONFIG_ITEM_STRING:
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 CONFIG_ITEM_KEY:
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     combo->setMinimumWidth( 80 );
358     combo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
359     finish( bycat );
360     if( !l )
361     {
362         QHBoxLayout *layout = new QHBoxLayout();
363         layout->addWidget( label ); layout->addWidget( combo );
364         widget->setLayout( layout );
365     }
366     else
367     {
368         l->addWidget( label, line, 0 );
369         l->addWidget( combo, line, 1, Qt::AlignRight );
370     }
371
372     if( p_item->i_action )
373     {
374         QSignalMapper *signalMapper = new QSignalMapper(this);
375
376         /* Some stringLists like Capture listings have action associated */
377         for( int i = 0; i < p_item->i_action; i++ )
378         {
379             QPushButton *button =
380                 new QPushButton( qfu( p_item->ppsz_action_text[i] ));
381             CONNECT( button, clicked(), signalMapper, map() );
382             signalMapper->setMapping( button, i );
383             l->addWidget( button, line, 2 + i, Qt::AlignRight );
384         }
385         CONNECT( signalMapper, mapped( int ),
386                 this, actionRequested( int ) );
387     }
388 }
389
390 void StringListConfigControl::actionRequested( int i_action )
391 {
392     /* Supplementary check for boundaries */
393     if( i_action < 0 || i_action >= p_item->i_action ) return;
394
395     vlc_value_t val;
396     val.psz_string =
397         qtu( (combo->itemData( combo->currentIndex() ).toString() ) );
398
399     p_item->ppf_action[i_action]( p_this, getName(), val, val, 0 );
400
401     if( p_item->b_dirty )
402     {
403         combo->clear();
404         finish( true );
405         p_item->b_dirty = VLC_FALSE;
406     }
407 }
408 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
409                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
410                 bool bycat ) : VStringConfigControl( _p_this, _p_item )
411 {
412     combo = _combo;
413     label = _label;
414     finish( bycat );
415 }
416
417 void StringListConfigControl::finish( bool bycat )
418 {
419     combo->setEditable( false );
420
421     for( int i_index = 0; i_index < p_item->i_list; i_index++ )
422     {
423         combo->addItem( qfu(p_item->ppsz_list_text ?
424                             p_item->ppsz_list_text[i_index] :
425                             p_item->ppsz_list[i_index] ),
426                         QVariant( p_item->ppsz_list[i_index] ) );
427         if( p_item->value.psz && !strcmp( p_item->value.psz,
428                                           p_item->ppsz_list[i_index] ) )
429             combo->setCurrentIndex( combo->count() - 1 );
430     }
431     combo->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
432     if( label )
433         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
434 }
435
436 QString StringListConfigControl::getValue()
437 {
438     return combo->itemData( combo->currentIndex() ).toString();
439 }
440
441 void setfillVLCConfigCombo( const char *configname, intf_thread_t *p_intf,
442                         QComboBox *combo, QWidget *parent )
443 {
444     module_config_t *p_config =
445                       config_FindConfig( VLC_OBJECT(p_intf), configname );
446     if( p_config )
447     {
448         for ( int i_index = 0; i_index < p_config->i_list; i_index++ )
449         {
450             combo->addItem( qfu( p_config->ppsz_list_text[i_index] ),
451                     QVariant( p_config->pi_list[i_index] ) );
452             if( p_config->value.i == p_config->pi_list[i_index] )
453             {
454                 combo->setCurrentIndex( i_index );
455             }
456         }
457         combo->setToolTip( qfu( p_config->psz_longtext ) );
458     }
459 }
460
461 /********* Module **********/
462 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
463                module_config_t *_p_item, QWidget *_parent, bool bycat,
464                QGridLayout *l, int &line) :
465                VStringConfigControl( _p_this, _p_item, _parent )
466 {
467     label = new QLabel( qtr(p_item->psz_text) );
468     combo = new QComboBox();
469     combo->setMinimumWidth( 80 );
470     finish( bycat );
471     if( !l )
472     {
473         QHBoxLayout *layout = new QHBoxLayout();
474         layout->addWidget( label ); layout->addWidget( combo );
475         widget->setLayout( layout );
476     }
477     else
478     {
479         l->addWidget( label, line, 0 );
480         l->addWidget( combo, line, 1, Qt::AlignRight );
481     }
482 }
483
484 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
485                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
486                 bool bycat ) : VStringConfigControl( _p_this, _p_item )
487 {
488     combo = _combo;
489     label = _label;
490     finish( bycat );
491 }
492
493 void ModuleConfigControl::finish( bool bycat )
494 {
495     vlc_list_t *p_list;
496     module_t *p_parser;
497
498     combo->setEditable( false );
499
500     /* build a list of available modules */
501     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
502     combo->addItem( qtr("Default") );
503     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
504     {
505         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
506
507         if( bycat )
508         {
509             if( !strcmp( module_GetObjName( p_parser ), "main" ) ) continue;
510
511             unsigned confsize;
512             module_config_t *p_config;
513
514             p_config = module_GetConfig (p_parser, &confsize);
515              for (size_t i = 0; i < confsize; i++)
516             {
517                 /* Hack: required subcategory is stored in i_min */
518                 const module_config_t *p_cfg = p_config + i;
519                 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
520                     p_cfg->value.i == p_item->min.i )
521                     combo->addItem( qtr( module_GetLongName( p_parser )),
522                                     QVariant( module_GetObjName( p_parser ) ) );
523                 if( p_item->value.psz && !strcmp( p_item->value.psz,
524                                                   module_GetObjName( p_parser ) ) )
525                     combo->setCurrentIndex( combo->count() - 1 );
526             }
527             module_PutConfig (p_config);
528         }
529         else if( module_IsCapable( p_parser, p_item->psz_type ) )
530         {
531             combo->addItem( qtr(module_GetLongName( p_parser ) ),
532                             QVariant( module_GetObjName( p_parser ) ) );
533             if( p_item->value.psz && !strcmp( p_item->value.psz,
534                                               module_GetObjName( p_parser ) ) )
535                 combo->setCurrentIndex( combo->count() - 1 );
536         }
537     }
538     vlc_list_release( p_list );
539     combo->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
540     if( label )
541         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
542 }
543
544 QString ModuleConfigControl::getValue()
545 {
546     return combo->itemData( combo->currentIndex() ).toString();
547 }
548
549 /********* Module list **********/
550 ModuleListConfigControl::ModuleListConfigControl( vlc_object_t *_p_this,
551         module_config_t *_p_item, QWidget *_parent, bool bycat,
552         QGridLayout *l, int &line) :
553     VStringConfigControl( _p_this, _p_item, _parent )
554 {
555     groupBox = new QGroupBox ( qtr(p_item->psz_text) );
556     text = new QLineEdit();
557     QGridLayout *layoutGroupBox = new QGridLayout( groupBox );
558
559     finish( bycat );
560
561     int boxline = 0;
562     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
563             it != modules.end(); it++ )
564     {
565         layoutGroupBox->addWidget( (*it)->checkBox, boxline++, 0 );
566     }
567     layoutGroupBox->addWidget( text, boxline, 0 );
568
569     if( !l )
570     {
571         QVBoxLayout *layout = new QVBoxLayout();
572         layout->addWidget( groupBox, line, 0 );
573         widget->setLayout( layout );
574     }
575     else
576     {
577         l->addWidget( groupBox, line, 0, 1, -1 );
578     }
579
580     text->setToolTip( formatTooltip( qtr( p_item->psz_longtext) ) );
581 }
582
583 ModuleListConfigControl::~ModuleListConfigControl()
584 {
585     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
586             it != modules.end(); it++ )
587     {
588         delete *it;
589     }
590     delete groupBox;
591     delete text;
592 }
593
594 #define CHECKBOX_LISTS \
595 { \
596        QCheckBox *cb = new QCheckBox( qtr( module_GetLongName( p_parser ) ) );\
597        checkBoxListItem *cbl = new checkBoxListItem; \
598 \
599        CONNECT( cb, stateChanged( int ), this, onUpdate( int ) );\
600        cb->setToolTip( formatTooltip( qtr( module_GetLongName( p_parser ))));\
601        cbl->checkBox = cb; \
602 \
603        cbl->psz_module = strdup( module_GetObjName( p_parser ) ); \
604        modules.push_back( cbl ); \
605 }
606
607
608 void ModuleListConfigControl::finish( bool bycat )
609 {
610     vlc_list_t *p_list;
611     module_t *p_parser;
612
613     /* build a list of available modules */
614     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
615     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
616     {
617         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
618
619         if( bycat )
620         {
621             if( !strcmp( module_GetObjName( p_parser ), "main" ) ) continue;
622
623             unsigned confsize;
624             module_config_t *p_config = module_GetConfig (p_parser, &confsize);
625
626             for (size_t i = 0; i < confsize; i++)
627             {
628                 module_config_t *p_cfg = p_config + i;
629                 /* Hack: required subcategory is stored in i_min */
630                 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
631                         p_cfg->value.i == p_item->min.i )
632                 {
633                     CHECKBOX_LISTS;
634                 }
635             }
636             module_PutConfig (p_config);
637         }
638         else if( module_IsCapable( p_parser, p_item->psz_type ) )
639         {
640             CHECKBOX_LISTS;
641         }
642     }
643     vlc_list_release( p_list );
644     text->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
645     if( groupBox )
646         groupBox->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
647 }
648 #undef CHECKBOX_LISTS
649
650 QString ModuleListConfigControl::getValue()
651 {
652     return text->text();
653 }
654
655 void ModuleListConfigControl::hide()
656 {
657     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
658          it != modules.end(); it++ )
659     {
660         (*it)->checkBox->hide();
661     }
662     groupBox->hide();
663 }
664
665 void ModuleListConfigControl::show()
666 {
667     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
668          it != modules.end(); it++ )
669     {
670         (*it)->checkBox->show();
671     }
672     groupBox->show();
673 }
674
675
676 void ModuleListConfigControl::onUpdate( int value )
677 {
678     text->clear();
679     bool first = true;
680
681     for( QVector<checkBoxListItem*>::iterator it = modules.begin();
682          it != modules.end(); it++ )
683     {
684         if( (*it)->checkBox->isChecked() )
685         {
686             if( first )
687             {
688                 text->setText( text->text() + (*it)->psz_module );
689                 first = false;
690             }
691             else
692             {
693                 text->setText( text->text() + ":" + (*it)->psz_module );
694             }
695         }
696     }
697 }
698
699 /**************************************************************************
700  * Integer-based controls
701  *************************************************************************/
702
703 /*********** Integer **************/
704 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
705                                             module_config_t *_p_item,
706                                             QWidget *_parent, QGridLayout *l,
707                                             int &line ) :
708                            VIntConfigControl( _p_this, _p_item, _parent )
709 {
710     label = new QLabel( qtr(p_item->psz_text) );
711     spin = new QSpinBox; spin->setMinimumWidth( 80 );
712     spin->setAlignment( Qt::AlignRight );
713     spin->setMaximumWidth( 90 );
714     finish();
715
716     if( !l )
717     {
718         QHBoxLayout *layout = new QHBoxLayout();
719         layout->addWidget( label, 0 ); layout->addWidget( spin, 1 );
720         widget->setLayout( layout );
721     }
722     else
723     {
724         l->addWidget( label, line, 0 );
725         l->addWidget( spin, line, 1, Qt::AlignRight );
726     }
727 }
728 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
729                                             module_config_t *_p_item,
730                                             QLabel *_label, QSpinBox *_spin ) :
731                                       VIntConfigControl( _p_this, _p_item )
732 {
733     spin = _spin;
734     label = _label;
735     finish();
736 }
737
738 void IntegerConfigControl::finish()
739 {
740     spin->setMaximum( 2000000000 );
741     spin->setMinimum( -2000000000 );
742     spin->setValue( p_item->value.i );
743     spin->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
744     if( label )
745         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
746 }
747
748 int IntegerConfigControl::getValue()
749 {
750     return spin->value();
751 }
752
753 /********* Integer range **********/
754 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
755                                             module_config_t *_p_item,
756                                             QWidget *_parent, QGridLayout *l,
757                                             int &line ) :
758             IntegerConfigControl( _p_this, _p_item, _parent, l, line )
759 {
760     finish();
761 }
762
763 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
764                                             module_config_t *_p_item,
765                                             QLabel *_label, QSpinBox *_spin ) :
766             IntegerConfigControl( _p_this, _p_item, _label, _spin )
767 {
768     finish();
769 }
770
771 void IntegerRangeConfigControl::finish()
772 {
773     spin->setMaximum( p_item->max.i );
774     spin->setMinimum( p_item->min.i );
775 }
776
777 IntegerRangeSliderConfigControl::IntegerRangeSliderConfigControl(
778                                             vlc_object_t *_p_this,
779                                             module_config_t *_p_item,
780                                             QLabel *_label, QSlider *_slider ):
781                     VIntConfigControl( _p_this, _p_item )
782 {
783     slider = _slider;
784     label = _label;
785     slider->setMaximum( p_item->max.i );
786     slider->setMinimum( p_item->min.i );
787     slider->setValue( p_item->value.i );
788     slider->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
789     if( label )
790         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
791 }
792
793 int IntegerRangeSliderConfigControl::getValue()
794 {
795         return slider->value();
796 }
797
798
799 /********* Integer / choice list **********/
800 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
801                module_config_t *_p_item, QWidget *_parent, bool bycat,
802                QGridLayout *l, int &line) :
803                VIntConfigControl( _p_this, _p_item, _parent )
804 {
805     label = new QLabel( qtr(p_item->psz_text) );
806     combo = new QComboBox();
807     combo->setMinimumWidth( 80 );
808     finish( bycat );
809     if( !l )
810     {
811         QHBoxLayout *layout = new QHBoxLayout();
812         layout->addWidget( label ); layout->addWidget( combo );
813         widget->setLayout( layout );
814     }
815     else
816     {
817         l->addWidget( label, line, 0 );
818         l->addWidget( combo, line, 1, Qt::AlignRight );
819     }
820 }
821 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
822                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
823                 bool bycat ) : VIntConfigControl( _p_this, _p_item )
824 {
825     combo = _combo;
826     label = _label;
827     finish( bycat );
828 }
829
830 void IntegerListConfigControl::finish( bool bycat )
831 {
832     combo->setEditable( false );
833
834     for( int i_index = 0; i_index < p_item->i_list; i_index++ )
835     {
836         combo->addItem( qtr(p_item->ppsz_list_text[i_index] ),
837                         QVariant( p_item->pi_list[i_index] ) );
838         if( p_item->value.i == p_item->pi_list[i_index] )
839             combo->setCurrentIndex( combo->count() - 1 );
840     }
841     combo->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
842     if( label )
843         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
844 }
845
846 int IntegerListConfigControl::getValue()
847 {
848     return combo->itemData( combo->currentIndex() ).toInt();
849 }
850
851 /*********** Boolean **************/
852 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
853                                       module_config_t *_p_item,
854                                       QWidget *_parent, QGridLayout *l,
855                                       int &line ) :
856                     VIntConfigControl( _p_this, _p_item, _parent )
857 {
858     checkbox = new QCheckBox( qtr(p_item->psz_text) );
859     finish();
860
861     if( !l )
862     {
863         QHBoxLayout *layout = new QHBoxLayout();
864         layout->addWidget( checkbox, 0 );
865         widget->setLayout( layout );
866     }
867     else
868     {
869         l->addWidget( checkbox, line, 0 );
870     }
871 }
872 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
873                                       module_config_t *_p_item,
874                                       QLabel *_label,
875                                       QCheckBox *_checkbox,
876                                       bool bycat ) :
877                    VIntConfigControl( _p_this, _p_item )
878 {
879     checkbox = _checkbox;
880     finish();
881 }
882
883 void BoolConfigControl::finish()
884 {
885     checkbox->setCheckState( p_item->value.i == VLC_TRUE ? Qt::Checked
886                                                         : Qt::Unchecked );
887     checkbox->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
888 }
889
890 int BoolConfigControl::getValue()
891 {
892     return checkbox->checkState() == Qt::Checked ? VLC_TRUE : VLC_FALSE;
893 }
894
895 /**************************************************************************
896  * Float-based controls
897  *************************************************************************/
898
899 /*********** Float **************/
900 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
901                                         module_config_t *_p_item,
902                                         QWidget *_parent, QGridLayout *l,
903                                         int &line ) :
904                     VFloatConfigControl( _p_this, _p_item, _parent )
905 {
906     label = new QLabel( qtr(p_item->psz_text) );
907     spin = new QDoubleSpinBox; 
908     spin->setMinimumWidth( 80 );
909     spin->setMaximumWidth( 90 );
910     spin->setAlignment( Qt::AlignRight );
911     finish();
912
913     if( !l )
914     {
915         QHBoxLayout *layout = new QHBoxLayout();
916         layout->addWidget( label, 0 ); layout->addWidget( spin, 1 );
917         widget->setLayout( layout );
918     }
919     else
920     {
921         l->addWidget( label, line, 0 );
922         l->addWidget( spin, line, 1, Qt::AlignRight );
923     }
924 }
925
926 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
927                                         module_config_t *_p_item,
928                                         QLabel *_label,
929                                         QDoubleSpinBox *_spin ) :
930                     VFloatConfigControl( _p_this, _p_item )
931 {
932     spin = _spin;
933     label = _label;
934     finish();
935 }
936
937 void FloatConfigControl::finish()
938 {
939     spin->setMaximum( 2000000000. );
940     spin->setMinimum( -2000000000. );
941     spin->setSingleStep( 0.1 );
942     spin->setValue( (double)p_item->value.f );
943     spin->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
944     if( label )
945         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
946 }
947
948 float FloatConfigControl::getValue()
949 {
950     return (float)spin->value();
951 }
952
953 /*********** Float with range **************/
954 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
955                                         module_config_t *_p_item,
956                                         QWidget *_parent, QGridLayout *l,
957                                         int &line ) :
958                 FloatConfigControl( _p_this, _p_item, _parent, l, line )
959 {
960     finish();
961 }
962
963 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
964                                         module_config_t *_p_item,
965                                         QLabel *_label,
966                                         QDoubleSpinBox *_spin ) :
967                 FloatConfigControl( _p_this, _p_item, _label, _spin )
968 {
969     finish();
970 }
971
972 void FloatRangeConfigControl::finish()
973 {
974     spin->setMaximum( (double)p_item->max.f );
975     spin->setMinimum( (double)p_item->min.f );
976 }
977
978
979 /**********************************************************************
980  * Key selector widget
981  **********************************************************************/
982 KeySelectorControl::KeySelectorControl( vlc_object_t *_p_this,
983                                       module_config_t *_p_item,
984                                       QWidget *_parent, QGridLayout *l,
985                                       int &line ) :
986                                 ConfigControl( _p_this, _p_item, _parent )
987
988 {
989     QWidget *keyContainer = new QWidget;
990     QGridLayout *gLayout = new QGridLayout( keyContainer );
991
992     label = new QLabel(
993             qtr( "Select an action to change the associated hotkey") );
994
995     /* Deactivated for now
996     QLabel *searchLabel = new QLabel( qtr( "Search" ) );
997     QLineEdit *actionSearch = new QLineEdit;*/
998
999     table = new QTreeWidget;
1000     table->setColumnCount(2);
1001     table->headerItem()->setText( 0, qtr( "Action" ) );
1002     table->headerItem()->setText( 1, qtr( "Shortcut" ) );
1003
1004     shortcutValue = new KeyShortcutEdit;
1005     shortcutValue->setReadOnly(true);
1006
1007     QPushButton *clearButton = new QPushButton( qtr( "Clear" ) );
1008     QPushButton *setButton = new QPushButton( qtr( "Set" ) );
1009     finish();
1010
1011     gLayout->addWidget( label, 0, 0, 1, 4 );
1012   /* deactivated for now
1013     gLayout->addWidget( searchLabel, 1, 0, 1, 2 );
1014     gLayout->addWidget( actionSearch, 1, 2, 1, 2 ); */
1015     gLayout->addWidget( table, 2, 0, 1, 4 );
1016     gLayout->addWidget( clearButton, 3, 0, 1, 1 );
1017     gLayout->addWidget( shortcutValue, 3, 1, 1, 2 );
1018     gLayout->addWidget( setButton, 3, 3, 1, 1 );
1019
1020     l->addWidget( keyContainer, line, 0, 1, 2 );
1021
1022     CONNECT( clearButton, clicked(), shortcutValue, clear() );
1023     BUTTONACT( setButton, setTheKey() );
1024 }
1025
1026 void KeySelectorControl::finish()
1027 {
1028     if( label )
1029         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1030
1031     /* Fill the table */
1032     table->setColumnCount( 2 );
1033     table->setAlternatingRowColors( true );
1034
1035     module_t *p_main = module_Find( p_this, "main" );
1036     assert( p_main );
1037
1038     unsigned confsize;
1039     module_config_t *p_config;
1040
1041     p_config = module_GetConfig (p_main, &confsize);
1042
1043     for (size_t i = 0; i < confsize; i++)
1044     {
1045         module_config_t *p_item = p_config + i;
1046
1047         if( p_item->i_type & CONFIG_ITEM && p_item->psz_name &&
1048             strstr( p_item->psz_name , "key-" ) && !EMPTY_STR( p_item->psz_text ) )
1049         {
1050             QTreeWidgetItem *treeItem = new QTreeWidgetItem();
1051             treeItem->setText( 0, qtr( p_item->psz_text ) );
1052             treeItem->setText( 1, VLCKeyToString( p_item->value.i ) );
1053             treeItem->setData( 0, Qt::UserRole,
1054                                   QVariant::fromValue( (void*)p_item ) );
1055             values += p_item;
1056             table->addTopLevelItem( treeItem );
1057         }
1058     }
1059     module_PutConfig (p_config);
1060     module_Put (p_main);
1061
1062     table->resizeColumnToContents( 0 );
1063
1064     CONNECT( table, itemClicked( QTreeWidgetItem *, int ),
1065              this, select1Key( QTreeWidgetItem * ) );
1066     CONNECT( table, itemDoubleClicked( QTreeWidgetItem *, int ),
1067              this, selectKey( QTreeWidgetItem * ) );
1068     CONNECT( shortcutValue, pressed(), this, selectKey() );
1069 }
1070
1071 void KeySelectorControl::select1Key( QTreeWidgetItem *keyItem )
1072 {
1073     shortcutValue->setText( keyItem->text( 1 ) );
1074 }
1075
1076 void KeySelectorControl::selectKey( QTreeWidgetItem *keyItem )
1077 {
1078     /* This happens when triggered by ClickEater */
1079     if( keyItem == NULL ) keyItem = table->currentItem();
1080
1081     /* This can happen when nothing is selected on the treeView
1082        and the shortcutValue is clicked */
1083     if( !keyItem ) return;
1084
1085     module_config_t *p_keyItem = static_cast<module_config_t*>
1086                           (keyItem->data( 0, Qt::UserRole ).value<void*>());
1087
1088     KeyInputDialog *d = new KeyInputDialog( values, p_keyItem->psz_text, widget );
1089     d->exec();
1090     if( d->result() == QDialog::Accepted )
1091     {
1092         p_keyItem->value.i = d->keyValue;
1093         if( d->conflicts )
1094         {
1095             for( int i = 0; i < table->topLevelItemCount() ; i++ )
1096             {
1097                 QTreeWidgetItem *it = table->topLevelItem(i);
1098                 module_config_t *p_item = static_cast<module_config_t*>
1099                               (it->data( 0, Qt::UserRole ).value<void*>());
1100                 if( p_keyItem != p_item && p_item->value.i == d->keyValue )
1101                     p_item->value.i = 0;
1102                 shortcutValue->setText( VLCKeyToString( p_item->value.i ) );
1103             }
1104         }
1105         else
1106             shortcutValue->setText( VLCKeyToString( p_keyItem->value.i ) );
1107     }
1108     delete d;
1109 }
1110
1111 void KeySelectorControl::setTheKey()
1112 {
1113     table->currentItem()->setText( 1, shortcutValue->text() );
1114 }
1115
1116 void KeySelectorControl::doApply()
1117 {
1118     foreach( module_config_t *p_current, values )
1119     {
1120         config_PutInt( p_this, p_current->psz_name, p_current->value.i );
1121     }
1122 }
1123
1124 KeyInputDialog::KeyInputDialog( QList<module_config_t*>& _values,
1125                                 const char * _keyToChange,
1126                                 QWidget *_parent ) :
1127                                 QDialog( _parent ), keyValue(0)
1128 {
1129     setModal( true );
1130     values = _values;
1131     conflicts = false;
1132     keyToChange = _keyToChange;
1133
1134     setWindowTitle( qtr( "Hotkey for " ) + qfu( keyToChange)  );
1135
1136     vLayout = new QVBoxLayout( this );
1137     selected = new QLabel( qtr("Press the new keys for ") + qfu( keyToChange ) );
1138     vLayout->addWidget( selected , Qt::AlignCenter );
1139
1140     buttonBox = new QDialogButtonBox;
1141     QPushButton *ok = new QPushButton( qtr("OK") );
1142     QPushButton *cancel = new QPushButton( qtr("Cancel") );
1143     buttonBox->addButton( ok, QDialogButtonBox::AcceptRole );
1144     buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
1145
1146     vLayout->addWidget( buttonBox );
1147     buttonBox->hide();
1148
1149     CONNECT( buttonBox, accepted(), this, accept() );
1150     CONNECT( buttonBox, rejected(), this, reject() );
1151 }
1152
1153 void KeyInputDialog::checkForConflicts( int i_vlckey )
1154 {
1155     conflicts = false;
1156     module_config_t *p_current = NULL;
1157     /* Search for conflicts */
1158     foreach( p_current, values )
1159     {
1160         if( p_current->value.i == i_vlckey && strcmp( p_current->psz_text,
1161                                                     keyToChange ) )
1162         {
1163             conflicts = true;
1164             break;
1165         }
1166     }
1167
1168     if( conflicts )
1169     {
1170         QLabel *warning = new QLabel(
1171           qtr("Warning: the  key is already assigned to \"") +
1172           qfu( p_current->psz_text ) + "\"" );
1173         warning->setWordWrap( true );
1174         vLayout->insertWidget( 1, warning );
1175         buttonBox->show();
1176     }
1177     else accept();
1178 }
1179
1180 void KeyInputDialog::keyPressEvent( QKeyEvent *e )
1181 {
1182     if( e->key() == Qt::Key_Tab ) return;
1183     int i_vlck = qtEventToVLCKey( e );
1184     selected->setText( VLCKeyToString( i_vlck ) );
1185     checkForConflicts( i_vlck );
1186     keyValue = i_vlck;
1187 }
1188
1189 void KeyInputDialog::wheelEvent( QWheelEvent *e )
1190 {
1191     int i_vlck = qtWheelEventToVLCKey( e );
1192     selected->setText( VLCKeyToString( i_vlck ) );
1193     checkForConflicts( i_vlck );
1194     keyValue = i_vlck;
1195 }
1196
1197 void KeyShortcutEdit::mousePressEvent( QMouseEvent *)
1198 {
1199     emit pressed();
1200 }