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