]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/preferences_widgets.cpp
Qt: simple prefs: explain hotkeys scope
[vlc] / modules / gui / qt4 / components / preferences_widgets.cpp
1 /*****************************************************************************
2  * preferences_widgets.cpp : Widgets for preferences displays
3  ****************************************************************************
4  * Copyright (C) 2006-2011 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  *  - i_action handler for IntegerLists, but I don't see any module using it...
29  *  - Validator for modulelist
30  */
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include "components/preferences_widgets.hpp"
36 #include "util/customwidgets.hpp"
37 #include "util/searchlineedit.hpp"
38 #include "util/qt_dirs.hpp"
39 #include <vlc_keys.h>
40 #include <vlc_intf_strings.h>
41 #include <vlc_modules.h>
42
43 #include <QString>
44 #include <QVariant>
45 #include <QGridLayout>
46 #include <QSlider>
47 #include <QFileDialog>
48 #include <QGroupBox>
49 #include <QTreeWidgetItem>
50 #include <QSignalMapper>
51 #include <QDialogButtonBox>
52 #include <QKeyEvent>
53 #include <QColorDialog>
54
55 #define MINWIDTH_BOX 90
56 #define LAST_COLUMN 10
57
58 QString formatTooltip(const QString & tooltip)
59 {
60     QString text = tooltip;
61     text.replace("\n", "<br/>");
62
63     QString formatted =
64     "<html><head><meta name=\"qrichtext\" content=\"1\" />"
65     "<style type=\"text/css\"> p, li { white-space: pre-wrap; } </style></head>"
66     "<body style=\" font-family:'Sans Serif'; "
67     "font-style:normal; text-decoration:none;\">"
68     "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; "
69     "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" +
70     text + "</p></body></html>";
71     return formatted;
72 }
73
74 ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
75                                              module_config_t *p_item,
76                                              QWidget *parent,
77                                              QGridLayout *l, int line )
78 {
79     ConfigControl *p_control = NULL;
80
81     switch( p_item->i_type )
82     {
83     case CONFIG_ITEM_MODULE:
84         p_control = new ModuleConfigControl( p_this, p_item, parent, false,
85                                              l, line );
86         break;
87     case CONFIG_ITEM_MODULE_CAT:
88         p_control = new ModuleConfigControl( p_this, p_item, parent, true,
89                                              l, line );
90         break;
91     case CONFIG_ITEM_MODULE_LIST:
92         p_control = new ModuleListConfigControl( p_this, p_item, parent, false,
93                                              l, line );
94         break;
95     case CONFIG_ITEM_MODULE_LIST_CAT:
96         p_control = new ModuleListConfigControl( p_this, p_item, parent, true,
97                                              l, line );
98         break;
99     case CONFIG_ITEM_STRING:
100         if( !p_item->i_list )
101             p_control = new StringConfigControl( p_this, p_item, parent,
102                                                  l, line, false );
103         else
104             p_control = new StringListConfigControl( p_this, p_item,
105                                             parent, l, line );
106         break;
107     case CONFIG_ITEM_PASSWORD:
108         if( !p_item->i_list )
109             p_control = new StringConfigControl( p_this, p_item, parent,
110                                                  l, line, true );
111         else
112             p_control = new StringListConfigControl( p_this, p_item,
113                                             parent, l, line );
114         break;
115     case CONFIG_ITEM_RGB:
116         p_control = new ColorConfigControl( p_this, p_item, parent, 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_LOADFILE:
130     case CONFIG_ITEM_SAVEFILE:
131         p_control = new FileConfigControl( p_this, p_item, parent, l, line);
132         break;
133     case CONFIG_ITEM_DIRECTORY:
134         p_control = new DirectoryConfigControl( p_this, p_item, parent, l,
135                                                 line );
136         break;
137     case CONFIG_ITEM_FONT:
138         p_control = new FontConfigControl( p_this, p_item, parent, l,
139                                            line);
140         break;
141     case CONFIG_ITEM_KEY:
142         p_control = new KeySelectorControl( p_this, p_item, parent, l, line );
143         break;
144     case CONFIG_ITEM_BOOL:
145         p_control = new BoolConfigControl( p_this, p_item, parent, l, line );
146         break;
147     case CONFIG_ITEM_FLOAT:
148         if( p_item->min.f || p_item->max.f )
149             p_control = new FloatRangeConfigControl( p_this, p_item, parent,
150                                                      l, line );
151         else
152             p_control = new FloatConfigControl( p_this, p_item, parent,
153                                                   l, line );
154         break;
155     default:
156         break;
157     }
158     return p_control;
159 }
160
161 /*******************************************************
162  * Simple widgets
163  *******************************************************/
164 InterfacePreviewWidget::InterfacePreviewWidget ( QWidget *parent ) : QLabel( parent )
165 {
166     setGeometry( 0, 0, 128, 100 );
167     setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
168 }
169
170 void InterfacePreviewWidget::setNormalPreview( bool b_minimal )
171 {
172     setPreview( ( b_minimal ) ? MINIMAL : COMPLETE );
173 }
174
175 void InterfacePreviewWidget::setPreview( enum_style e_style )
176 {
177     QString pixmapLocationString(":/prefsmenu/");
178
179     switch( e_style )
180     {
181     default:
182     case COMPLETE:
183         pixmapLocationString += "sample_complete";
184         break;
185     case MINIMAL:
186         pixmapLocationString += "sample_minimal";
187         break;
188     case SKINS:
189         pixmapLocationString += "sample_skins";
190         break;
191     }
192
193     setPixmap( QPixmap( pixmapLocationString ) );
194     update();
195 }
196
197
198 /**************************************************************************
199  * String-based controls
200  *************************************************************************/
201
202 void
203 VStringConfigControl::doApply()
204 {
205     config_PutPsz( p_this, getName(), qtu( getValue() ) );
206 }
207
208 /*********** String **************/
209 StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
210                                           module_config_t *_p_item,
211                                           QWidget *_parent, QGridLayout *l,
212                                           int line, bool pwd ) :
213                            VStringConfigControl( _p_this, _p_item, _parent )
214 {
215     label = new QLabel( qtr(p_item->psz_text) );
216     text = new QLineEdit( qfu(p_item->value.psz) );
217     if( pwd ) text->setEchoMode( QLineEdit::Password );
218     finish();
219
220     if( !l )
221     {
222         QHBoxLayout *layout = new QHBoxLayout();
223         layout->addWidget( label, 0 ); layout->insertSpacing( 1, 10 );
224         layout->addWidget( text, LAST_COLUMN );
225         widget->setLayout( layout );
226     }
227     else
228     {
229         l->addWidget( label, line, 0 );
230         l->setColumnMinimumWidth( 1, 10 );
231         l->addWidget( text, line, LAST_COLUMN );
232     }
233 }
234
235 StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
236                                    module_config_t *_p_item,
237                                    QLabel *_label, QLineEdit *_text, bool pwd ):
238                            VStringConfigControl( _p_this, _p_item )
239 {
240     text = _text;
241     if( pwd ) text->setEchoMode( QLineEdit::Password );
242     label = _label;
243     finish( );
244 }
245
246 void StringConfigControl::finish()
247 {
248     text->setText( qfu(p_item->value.psz) );
249     if( p_item->psz_longtext )
250     {
251         QString tipText = qtr(p_item->psz_longtext);
252         text->setToolTip( formatTooltip(tipText) );
253         if( label )
254             label->setToolTip( formatTooltip(tipText) );
255     }
256     if( label )
257         label->setBuddy( text );
258 }
259
260 /*********** File **************/
261 FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
262                                           module_config_t *_p_item,
263                                           QWidget *_parent, QGridLayout *l,
264                                           int line ) :
265                            VStringConfigControl( _p_this, _p_item, _parent )
266 {
267     label = new QLabel( qtr(p_item->psz_text) );
268     text = new QLineEdit( qfu(p_item->value.psz) );
269     browse = new QPushButton( qtr( "Browse..." ) );
270     QHBoxLayout *textAndButton = new QHBoxLayout();
271     textAndButton->setMargin( 0 );
272     textAndButton->addWidget( text, 2 );
273     textAndButton->addWidget( browse, 0 );
274
275     BUTTONACT( browse, updateField() );
276
277     finish();
278
279     if( !l )
280     {
281         QHBoxLayout *layout = new QHBoxLayout();
282         layout->addWidget( label, 0 );
283         layout->insertSpacing( 1, 10 );
284         layout->addLayout( textAndButton, LAST_COLUMN );
285         widget->setLayout( layout );
286     }
287     else
288     {
289         l->addWidget( label, line, 0 );
290         l->setColumnMinimumWidth( 1, 10 );
291         l->addLayout( textAndButton, line, LAST_COLUMN );
292     }
293 }
294
295
296 FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
297                                    module_config_t *_p_item,
298                                    QLabel *_label, QLineEdit *_text,
299                                    QPushButton *_button ):
300                            VStringConfigControl( _p_this, _p_item )
301 {
302     browse = _button;
303     text = _text;
304     label = _label;
305
306     BUTTONACT( browse, updateField() );
307
308     finish( );
309 }
310
311 void FileConfigControl::updateField()
312 {
313     QString file;
314
315     if (p_item->i_type == CONFIG_ITEM_SAVEFILE)
316         file = QFileDialog::getSaveFileName( NULL, qtr( "Save File" ),
317                                              QVLCUserDir( VLC_HOME_DIR ) );
318     else
319         file = QFileDialog::getOpenFileName( NULL, qtr( "Select File" ),
320                                              QVLCUserDir( VLC_HOME_DIR ) );
321
322     if( file.isNull() ) return;
323     text->setText( toNativeSeparators( file ) );
324 }
325
326 void FileConfigControl::finish()
327 {
328     text->setText( qfu(p_item->value.psz) );
329     if( p_item->psz_longtext )
330     {
331         QString tipText = qtr(p_item->psz_longtext);
332         text->setToolTip( formatTooltip(tipText) );
333         if( label )
334             label->setToolTip( formatTooltip(tipText) );
335     }
336     if( label )
337         label->setBuddy( text );
338 }
339
340 /********* String / Directory **********/
341 DirectoryConfigControl::DirectoryConfigControl( vlc_object_t *_p_this,
342                         module_config_t *_p_item, QWidget *_p_widget,
343                         QGridLayout *_p_layout, int _int ) :
344      FileConfigControl( _p_this, _p_item, _p_widget, _p_layout, _int )
345 {}
346
347 DirectoryConfigControl::DirectoryConfigControl( vlc_object_t *_p_this,
348                         module_config_t *_p_item, QLabel *_p_label,
349                         QLineEdit *_p_line, QPushButton *_p_button ):
350      FileConfigControl( _p_this, _p_item, _p_label, _p_line, _p_button)
351 {}
352
353 void DirectoryConfigControl::updateField()
354 {
355     QString dir = QFileDialog::getExistingDirectory( NULL,
356                       qtr( I_OP_SEL_DIR ),
357                       text->text().isEmpty() ?
358                         QVLCUserDir( VLC_HOME_DIR ) : text->text(),
359                   QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks );
360
361     if( dir.isNull() ) return;
362     text->setText( toNativeSepNoSlash( dir ) );
363 }
364
365 /********* String / Font **********/
366 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
367                         module_config_t *_p_item, QWidget *_parent,
368                         QGridLayout *_p_layout, int line) :
369      VStringConfigControl( _p_this, _p_item, _parent )
370 {
371     label = new QLabel( qtr(p_item->psz_text) );
372     font = new QFontComboBox( _parent );
373     font->setCurrentFont( QFont( qfu( p_item->value.psz) ) );
374     if( !_p_layout )
375     {
376         QHBoxLayout *layout = new QHBoxLayout();
377         layout->addWidget( label, 0 );
378         layout->addWidget( font, 1 );
379         widget->setLayout( layout );
380     }
381     else
382     {
383         _p_layout->addWidget( label, line, 0 );
384         _p_layout->addWidget( font, line, 1, 1, -1 );
385     }
386
387     if( p_item->psz_longtext )
388     {
389         label->setToolTip( formatTooltip( qtr(p_item->psz_longtext) ) );
390     }
391 }
392
393 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
394                         module_config_t *_p_item, QLabel *_p_label,
395                         QFontComboBox *_p_font):
396      VStringConfigControl( _p_this, _p_item)
397 {
398     label = _p_label;
399     font = _p_font;
400     font->setCurrentFont( QFont( qfu( p_item->value.psz) ) );
401
402     if( p_item->psz_longtext )
403     {
404         label->setToolTip( formatTooltip( qtr(p_item->psz_longtext) ) );
405     }
406 }
407
408 /********* String / choice list **********/
409 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
410                module_config_t *_p_item, QWidget *_parent,
411                QGridLayout *l, int line) :
412                VStringConfigControl( _p_this, _p_item, _parent )
413 {
414     label = new QLabel( qtr(p_item->psz_text) );
415     combo = new QComboBox();
416     combo->setMinimumWidth( MINWIDTH_BOX );
417     combo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
418
419     module_config_t *p_module_config = config_FindConfig( p_this, p_item->psz_name );
420
421     finish( p_module_config );
422     if( !l )
423     {
424         l = new QGridLayout();
425         l->addWidget( label, 0, 0 ); l->addWidget( combo, 0, LAST_COLUMN );
426         widget->setLayout( l );
427     }
428     else
429     {
430         l->addWidget( label, line, 0 );
431         l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
432     }
433
434     if( p_item->i_action )
435     {
436         QSignalMapper *signalMapper = new QSignalMapper(this);
437
438         /* Some stringLists like Capture listings have action associated */
439         for( int i = 0; i < p_item->i_action; i++ )
440         {
441             QPushButton *button =
442                 new QPushButton( qtr( p_item->ppsz_action_text[i] ));
443             CONNECT( button, clicked(), signalMapper, map() );
444             signalMapper->setMapping( button, i );
445             l->addWidget( button, line, LAST_COLUMN - p_item->i_action + i,
446                     Qt::AlignRight );
447         }
448         CONNECT( signalMapper, mapped( int ),
449                 this, actionRequested( int ) );
450     }
451 }
452
453 void StringListConfigControl::actionRequested( int i_action )
454 {
455     /* Supplementary check for boundaries */
456     if( i_action < 0 || i_action >= p_item->i_action ) return;
457
458     module_config_t *p_module_config = config_FindConfig( p_this, getName() );
459     if(!p_module_config) return;
460
461     vlc_value_t val;
462     val.psz_string = const_cast<char *>
463         qtu( (combo->itemData( combo->currentIndex() ).toString() ) );
464
465     p_module_config->ppf_action[i_action]( p_this, getName(), val, val, 0 );
466
467     if( p_module_config->b_dirty )
468     {
469         combo->clear();
470         finish( p_module_config );
471         p_module_config->b_dirty = false;
472     }
473 }
474 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
475                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
476                 bool ) : VStringConfigControl( _p_this, _p_item )
477 {
478     combo = _combo;
479     label = _label;
480
481     module_config_t *p_module_config = config_FindConfig( p_this, getName() );
482
483     finish( p_module_config );
484 }
485
486 void StringListConfigControl::finish(module_config_t *p_module_config )
487 {
488     combo->setEditable( false );
489
490     if(!p_module_config) return;
491
492     if( p_module_config->pf_update_list )
493     {
494         vlc_value_t val;
495         val.psz_string = strdup(p_module_config->value.psz);
496
497         p_module_config->pf_update_list(p_this, p_item->psz_name, val, val, NULL);
498
499         // assume in any case that dirty was set to true
500         // because lazy programmes will use the same callback for
501         // this, like the one behind the refresh push button?
502         p_module_config->b_dirty = false;
503
504         free( val.psz_string );
505     }
506
507     for( int i_index = 0; i_index < p_module_config->i_list; i_index++ )
508     {
509         if( !p_module_config->ppsz_list[i_index] )
510         {
511               combo->addItem( "", QVariant(""));
512               if( !p_item->value.psz )
513                  combo->setCurrentIndex( combo->count() - 1 );
514               continue;
515         }
516         combo->addItem( qfu((p_module_config->ppsz_list_text &&
517                             p_module_config->ppsz_list_text[i_index])?
518                             _(p_module_config->ppsz_list_text[i_index]) :
519                             p_module_config->ppsz_list[i_index] ),
520                    QVariant( qfu(p_module_config->ppsz_list[i_index] )) );
521         if( p_item->value.psz && !strcmp( p_module_config->value.psz,
522                                           p_module_config->ppsz_list[i_index] ) )
523             combo->setCurrentIndex( combo->count() - 1 );
524     }
525
526     if( p_module_config->psz_longtext  )
527     {
528         QString tipText = qtr(p_module_config->psz_longtext);
529         combo->setToolTip( formatTooltip(tipText) );
530         if( label )
531             label->setToolTip( formatTooltip(tipText) );
532     }
533     if( label )
534         label->setBuddy( combo );
535 }
536
537 QString StringListConfigControl::getValue() const
538 {
539     return combo->itemData( combo->currentIndex() ).toString();
540 }
541
542 void setfillVLCConfigCombo( const char *configname, intf_thread_t *p_intf,
543                             QComboBox *combo )
544 {
545     module_config_t *p_config =
546                       config_FindConfig( VLC_OBJECT(p_intf), configname );
547     if( p_config )
548     {
549         QVariant def;
550         bool string = (p_config->i_type & 0xF0) == CONFIG_ITEM_STRING;
551
552         if( string )
553             def = QVariant( qfu(p_config->value.psz) );
554         else
555             def = QVariant( qlonglong( p_config->value.i ) );
556
557         if(p_config->pf_update_list)
558         {
559             vlc_value_t val;
560             val.i_int = p_config->value.i;
561             p_config->pf_update_list(VLC_OBJECT(p_intf), configname, val, val, NULL);
562             // assume in any case that dirty was set to true
563             // because lazy programmes will use the same callback for
564             // this, like the one behind the refresh push button?
565             p_config->b_dirty = false;
566         }
567
568         for ( int i_index = 0; i_index < p_config->i_list; i_index++ )
569         {
570             QVariant value;
571
572             if( string )
573                 value = QVariant( qfu(p_config->ppsz_list[i_index]) );
574             else
575                 value =QVariant( p_config->pi_list[i_index] );
576             combo->addItem( qtr(p_config->ppsz_list_text[i_index]), value );
577             if( def == value )
578                 combo->setCurrentIndex( i_index );
579         }
580
581         if( p_config->psz_longtext )
582             combo->setToolTip( qfu( p_config->psz_longtext ) );
583     }
584 }
585
586 /********* Module **********/
587 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
588                module_config_t *_p_item, QWidget *_parent, bool bycat,
589                QGridLayout *l, int line) :
590                VStringConfigControl( _p_this, _p_item, _parent )
591 {
592     label = new QLabel( qtr(p_item->psz_text) );
593     combo = new QComboBox();
594     combo->setMinimumWidth( MINWIDTH_BOX );
595     finish( bycat );
596     if( !l )
597     {
598         QHBoxLayout *layout = new QHBoxLayout();
599         layout->addWidget( label ); layout->addWidget( combo, LAST_COLUMN );
600         widget->setLayout( layout );
601     }
602     else
603     {
604         l->addWidget( label, line, 0 );
605         l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
606     }
607 }
608
609 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
610                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
611                 bool bycat ) : VStringConfigControl( _p_this, _p_item )
612 {
613     combo = _combo;
614     label = _label;
615     finish( bycat );
616 }
617
618 void ModuleConfigControl::finish( bool bycat )
619 {
620     module_t *p_parser;
621
622     combo->setEditable( false );
623
624     /* build a list of available modules */
625     module_t **p_list = module_list_get( NULL );
626     combo->addItem( qtr("Default") );
627     for( size_t i = 0; (p_parser = p_list[i]) != NULL; i++ )
628     {
629         if( bycat )
630         {
631             if( !strcmp( module_get_object( p_parser ), "main" ) ) continue;
632
633             unsigned confsize;
634             module_config_t *p_config;
635
636             p_config = module_config_get (p_parser, &confsize);
637             for (size_t i = 0; i < confsize; i++)
638             {
639                 /* Hack: required subcategory is stored in i_min */
640                 const module_config_t *p_cfg = p_config + i;
641                 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
642                     p_cfg->value.i == p_item->min.i )
643                     combo->addItem( qtr( module_GetLongName( p_parser )),
644                                     QVariant( module_get_object( p_parser ) ) );
645                 if( p_item->value.psz && !strcmp( p_item->value.psz,
646                                                   module_get_object( p_parser ) ) )
647                     combo->setCurrentIndex( combo->count() - 1 );
648             }
649             module_config_free (p_config);
650         }
651         else if( module_provides( p_parser, p_item->psz_type ) )
652         {
653             combo->addItem( qtr(module_GetLongName( p_parser ) ),
654                             QVariant( module_get_object( p_parser ) ) );
655             if( p_item->value.psz && !strcmp( p_item->value.psz,
656                                               module_get_object( p_parser ) ) )
657                 combo->setCurrentIndex( combo->count() - 1 );
658         }
659     }
660     module_list_free( p_list );
661
662     if( p_item->psz_longtext )
663     {
664         QString tipText = qtr(p_item->psz_longtext);
665         combo->setToolTip( formatTooltip(tipText) );
666         if( label )
667             label->setToolTip( formatTooltip(tipText) );
668     }
669     if( label )
670         label->setBuddy( combo );
671 }
672
673 QString ModuleConfigControl::getValue() const
674 {
675     return combo->itemData( combo->currentIndex() ).toString();
676 }
677
678 /********* Module list **********/
679 ModuleListConfigControl::ModuleListConfigControl( vlc_object_t *_p_this,
680         module_config_t *_p_item, QWidget *_parent, bool bycat,
681         QGridLayout *l, int line) :
682     VStringConfigControl( _p_this, _p_item, _parent )
683 {
684     groupBox = NULL;
685
686     /* Special Hack */
687     if( !p_item->psz_text ) return;
688
689     groupBox = new QGroupBox ( qtr(p_item->psz_text), _parent );
690     text = new QLineEdit;
691     QGridLayout *layoutGroupBox = new QGridLayout( groupBox );
692
693     finish( bycat );
694
695     int boxline = 0;
696     foreach ( checkBoxListItem *it, modules )
697     {
698         layoutGroupBox->addWidget( it->checkBox, boxline / 2, boxline % 2 );
699         boxline++;
700     }
701
702     layoutGroupBox->addWidget( text, boxline, 0, 1, 2 );
703
704     if( !l )
705     {
706         QVBoxLayout *layout = new QVBoxLayout();
707         layout->addWidget( groupBox, line, 0 );
708         widget->setLayout( layout );
709     }
710     else
711     {
712         l->addWidget( groupBox, line, 0, 1, -1 );
713     }
714
715     if( p_item->psz_longtext )
716         text->setToolTip( formatTooltip( qtr( p_item->psz_longtext) ) );
717 }
718
719 ModuleListConfigControl::~ModuleListConfigControl()
720 {
721     qDeleteAll( modules );
722     modules.clear();
723     delete groupBox;
724 }
725
726 void ModuleListConfigControl::checkbox_lists( module_t *p_parser )
727 {
728     const char *help = module_get_help( p_parser );
729     checkbox_lists( qtr( module_GetLongName( p_parser ) ),
730                     help != NULL ? qtr( help ): "",
731                     module_get_object( p_parser ) );
732 }
733
734 void ModuleListConfigControl::checkbox_lists( QString label, QString help, const char* psz_module )
735 {
736     QCheckBox *cb = new QCheckBox( label );
737     checkBoxListItem *cbl = new checkBoxListItem;
738
739     CONNECT( cb, stateChanged( int ), this, onUpdate() );
740     if( !help.isEmpty() )
741         cb->setToolTip( formatTooltip( help ) );
742     cbl->checkBox = cb;
743
744     cbl->psz_module = strdup( psz_module );
745     modules.append( cbl );
746
747     if( p_item->value.psz && strstr( p_item->value.psz, cbl->psz_module ) )
748         cbl->checkBox->setChecked( true );
749 }
750
751 void ModuleListConfigControl::finish( bool bycat )
752 {
753     module_t *p_parser;
754
755     /* build a list of available modules */
756     module_t **p_list = module_list_get( NULL );
757     for( size_t i = 0; (p_parser = p_list[i]) != NULL; i++ )
758     {
759         if( bycat )
760         {
761             if( !strcmp( module_get_object( p_parser ), "main" ) ) continue;
762
763             unsigned confsize;
764             module_config_t *p_config = module_config_get (p_parser, &confsize);
765
766             for (size_t i = 0; i < confsize; i++)
767             {
768                 module_config_t *p_cfg = p_config + i;
769                 /* Hack: required subcategory is stored in i_min */
770                 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
771                         p_cfg->value.i == p_item->min.i )
772                 {
773                     checkbox_lists( p_parser );
774                 }
775
776                 /* Parental Advisory HACK:
777                  * Selecting HTTP, RC and Telnet interfaces is difficult now
778                  * since they are just the lua interface module */
779                 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
780                     !strcmp( module_get_object( p_parser ), "lua" ) &&
781                     !strcmp( p_item->psz_name, "extraintf" ) &&
782                     p_cfg->value.i == p_item->min.i )
783                 {
784                     checkbox_lists( "Web", "Lua HTTP", "http" );
785                     checkbox_lists( "Telnet", "Lua Telnet", "telnet" );
786 #ifndef WIN32
787                     checkbox_lists( "Console", "Lua CLI", "cli" );
788 #endif
789                 }
790             }
791             module_config_free (p_config);
792         }
793         else if( module_provides( p_parser, p_item->psz_type ) )
794         {
795             checkbox_lists(p_parser);
796         }
797     }
798     module_list_free( p_list );
799
800     if( p_item->psz_longtext )
801     {
802         QString tipText = qtr(p_item->psz_longtext);
803
804         text->setToolTip( formatTooltip(tipText) );
805         assert( groupBox );
806         groupBox->setToolTip( formatTooltip(tipText) );
807    }
808 }
809
810 QString ModuleListConfigControl::getValue() const
811 {
812     assert( text );
813     return text->text();
814 }
815
816 void ModuleListConfigControl::hide()
817 {
818     foreach ( checkBoxListItem *it, modules )
819         it->checkBox->hide();
820     groupBox->hide();
821 }
822
823 void ModuleListConfigControl::show()
824 {
825     foreach ( checkBoxListItem *it, modules )
826         it->checkBox->show();
827     groupBox->show();
828 }
829
830
831 void ModuleListConfigControl::onUpdate()
832 {
833     text->clear();
834     bool first = true;
835
836     foreach ( checkBoxListItem *it, modules )
837     {
838         if( it->checkBox->isChecked() )
839         {
840             if( first )
841             {
842                 text->setText( text->text() + it->psz_module );
843                 first = false;
844             }
845             else
846             {
847                 text->setText( text->text() + ":" + it->psz_module );
848             }
849         }
850     }
851 }
852
853 /**************************************************************************
854  * Integer-based controls
855  *************************************************************************/
856
857 void
858 VIntConfigControl::doApply()
859 {
860     config_PutInt( p_this, getName(), getValue() );
861 }
862
863 /*********** Integer **************/
864 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
865                                             module_config_t *_p_item,
866                                             QWidget *_parent, QGridLayout *l,
867                                             int line ) :
868                            VIntConfigControl( _p_this, _p_item, _parent )
869 {
870     label = new QLabel( qtr(p_item->psz_text) );
871     spin = new QSpinBox; spin->setMinimumWidth( MINWIDTH_BOX );
872     spin->setAlignment( Qt::AlignRight );
873     spin->setMaximumWidth( MINWIDTH_BOX );
874     finish();
875
876     if( !l )
877     {
878         QHBoxLayout *layout = new QHBoxLayout();
879         layout->addWidget( label, 0 ); layout->addWidget( spin, LAST_COLUMN );
880         widget->setLayout( layout );
881     }
882     else
883     {
884         l->addWidget( label, line, 0 );
885         l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
886     }
887 }
888 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
889                                             module_config_t *_p_item,
890                                             QLabel *_label, QSpinBox *_spin ) :
891                                       VIntConfigControl( _p_this, _p_item )
892 {
893     spin = _spin;
894     label = _label;
895     finish();
896 }
897
898 void IntegerConfigControl::finish()
899 {
900     spin->setMaximum( 2000000000 );
901     spin->setMinimum( -2000000000 );
902     spin->setValue( p_item->value.i );
903
904     if( p_item->psz_longtext )
905     {
906         QString tipText = qtr(p_item->psz_longtext);
907         spin->setToolTip( formatTooltip(tipText) );
908         if( label )
909             label->setToolTip( formatTooltip(tipText) );
910     }
911     if( label )
912         label->setBuddy( spin );
913 }
914
915 int IntegerConfigControl::getValue() const
916 {
917     return spin->value();
918 }
919
920 /********* Integer range **********/
921 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
922                                             module_config_t *_p_item,
923                                             QWidget *_parent, QGridLayout *l,
924                                             int line ) :
925             IntegerConfigControl( _p_this, _p_item, _parent, l, line )
926 {
927     finish();
928 }
929
930 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
931                                             module_config_t *_p_item,
932                                             QLabel *_label, QSpinBox *_spin ) :
933             IntegerConfigControl( _p_this, _p_item, _label, _spin )
934 {
935     finish();
936 }
937
938 void IntegerRangeConfigControl::finish()
939 {
940     spin->setMaximum( p_item->max.i );
941     spin->setMinimum( p_item->min.i );
942 }
943
944 IntegerRangeSliderConfigControl::IntegerRangeSliderConfigControl(
945                                             vlc_object_t *_p_this,
946                                             module_config_t *_p_item,
947                                             QLabel *_label, QSlider *_slider ):
948                     VIntConfigControl( _p_this, _p_item )
949 {
950     slider = _slider;
951     label = _label;
952     slider->setMaximum( p_item->max.i );
953     slider->setMinimum( p_item->min.i );
954     slider->setValue( p_item->value.i );
955     if( p_item->psz_longtext )
956     {
957         QString tipText = qtr(p_item->psz_longtext);
958         slider->setToolTip( formatTooltip(tipText) );
959         if( label )
960             label->setToolTip( formatTooltip(tipText) );
961     }
962     if( label )
963         label->setBuddy( slider );
964 }
965
966 int IntegerRangeSliderConfigControl::getValue() const
967 {
968         return slider->value();
969 }
970
971
972 /********* Integer / choice list **********/
973 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
974                module_config_t *_p_item, QWidget *_parent, bool,
975                QGridLayout *l, int line) :
976                VIntConfigControl( _p_this, _p_item, _parent )
977 {
978     label = new QLabel( qtr(p_item->psz_text) );
979     combo = new QComboBox();
980     combo->setMinimumWidth( MINWIDTH_BOX );
981
982     module_config_t *p_module_config = config_FindConfig( p_this, p_item->psz_name );
983
984     finish( p_module_config );
985     if( !l )
986     {
987         QHBoxLayout *layout = new QHBoxLayout();
988         layout->addWidget( label ); layout->addWidget( combo, LAST_COLUMN );
989         widget->setLayout( layout );
990     }
991     else
992     {
993         l->addWidget( label, line, 0 );
994         l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
995     }
996
997     if( p_item->i_action )
998     {
999         QSignalMapper *signalMapper = new QSignalMapper(this);
1000
1001         /* Some stringLists like Capture listings have action associated */
1002         for( int i = 0; i < p_item->i_action; i++ )
1003         {
1004             QPushButton *button =
1005                 new QPushButton( qfu( p_item->ppsz_action_text[i] ));
1006             CONNECT( button, clicked(), signalMapper, map() );
1007             signalMapper->setMapping( button, i );
1008             l->addWidget( button, line, LAST_COLUMN - p_item->i_action + i,
1009                     Qt::AlignRight );
1010         }
1011         CONNECT( signalMapper, mapped( int ),
1012                 this, actionRequested( int ) );
1013     }
1014
1015 }
1016 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
1017                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
1018                 bool ) : VIntConfigControl( _p_this, _p_item )
1019 {
1020     combo = _combo;
1021     label = _label;
1022
1023     module_config_t *p_module_config = config_FindConfig( p_this, getName() );
1024
1025     finish( p_module_config );
1026 }
1027
1028 void IntegerListConfigControl::finish(module_config_t *p_module_config )
1029 {
1030     combo->setEditable( false );
1031
1032     if(!p_module_config) return;
1033
1034     if( p_module_config->pf_update_list )
1035     {
1036        vlc_value_t val;
1037        val.i_int = p_module_config->value.i;
1038
1039        p_module_config->pf_update_list(p_this, p_item->psz_name, val, val, NULL);
1040
1041        // assume in any case that dirty was set to true
1042        // because lazy programmes will use the same callback for
1043        // this, like the one behind the refresh push button?
1044        p_module_config->b_dirty = false;
1045     }
1046
1047     for( int i_index = 0; i_index < p_module_config->i_list; i_index++ )
1048     {
1049         combo->addItem( qtr(p_module_config->ppsz_list_text[i_index] ),
1050                         QVariant( p_module_config->pi_list[i_index] ) );
1051         if( p_module_config->value.i == p_module_config->pi_list[i_index] )
1052             combo->setCurrentIndex( combo->count() - 1 );
1053     }
1054     if( p_item->psz_longtext )
1055     {
1056         QString tipText = qtr(p_item->psz_longtext );
1057         combo->setToolTip( formatTooltip(tipText) );
1058         if( label )
1059             label->setToolTip( formatTooltip(tipText) );
1060     }
1061     if( label )
1062         label->setBuddy( combo );
1063 }
1064
1065 void IntegerListConfigControl::actionRequested( int i_action )
1066 {
1067     /* Supplementary check for boundaries */
1068     if( i_action < 0 || i_action >= p_item->i_action ) return;
1069
1070     module_config_t *p_module_config = config_FindConfig( p_this, getName() );
1071     if(!p_module_config) return;
1072
1073
1074     vlc_value_t val;
1075     val.i_int = combo->itemData( combo->currentIndex() ).toInt();
1076
1077     p_module_config->ppf_action[i_action]( p_this, getName(), val, val, 0 );
1078
1079     if( p_module_config->b_dirty )
1080     {
1081         combo->clear();
1082         finish( p_module_config );
1083         p_module_config->b_dirty = false;
1084     }
1085 }
1086
1087 int IntegerListConfigControl::getValue() const
1088 {
1089     return combo->itemData( combo->currentIndex() ).toInt();
1090 }
1091
1092 /*********** Boolean **************/
1093 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
1094                                       module_config_t *_p_item,
1095                                       QWidget *_parent, QGridLayout *l,
1096                                       int line ) :
1097                     VIntConfigControl( _p_this, _p_item, _parent )
1098 {
1099     checkbox = new QCheckBox( qtr(p_item->psz_text) );
1100     finish();
1101
1102     if( !l )
1103     {
1104         QHBoxLayout *layout = new QHBoxLayout();
1105         layout->addWidget( checkbox, 0 );
1106         widget->setLayout( layout );
1107     }
1108     else
1109     {
1110         l->addWidget( checkbox, line, 0 );
1111     }
1112 }
1113
1114 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
1115                                       module_config_t *_p_item,
1116                                       QLabel *_label,
1117                                       QAbstractButton *_checkbox ) :
1118                    VIntConfigControl( _p_this, _p_item )
1119 {
1120     checkbox = _checkbox;
1121     VLC_UNUSED( _label );
1122     finish();
1123 }
1124
1125 void BoolConfigControl::finish()
1126 {
1127     checkbox->setChecked( p_item->value.i );
1128     if( p_item->psz_longtext )
1129         checkbox->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1130 }
1131
1132 int BoolConfigControl::getValue() const
1133 {
1134     return checkbox->isChecked();
1135 }
1136
1137 /************* Color *************/
1138 ColorConfigControl::ColorConfigControl( vlc_object_t *_p_this,
1139                                             module_config_t *_p_item,
1140                                             QWidget *_parent, QGridLayout *l,
1141                                             int line ) :
1142                            VIntConfigControl( _p_this, _p_item, _parent )
1143 {
1144     label = new QLabel;
1145     color_but = new QToolButton;
1146     finish();
1147
1148     if( !l )
1149     {
1150         QHBoxLayout *layout = new QHBoxLayout();
1151         layout->addWidget( label, 0 ); layout->addWidget( color_but, LAST_COLUMN );
1152         widget->setLayout( layout );
1153     }
1154     else
1155     {
1156         l->addWidget( label, line, 0 );
1157         l->addWidget( color_but, line, LAST_COLUMN, Qt::AlignRight );
1158     }
1159 }
1160
1161 ColorConfigControl::ColorConfigControl( vlc_object_t *_p_this,
1162                                             module_config_t *_p_item,
1163                                             QLabel *_label, QAbstractButton *_color ):
1164                                       VIntConfigControl( _p_this, _p_item )
1165 {
1166     label = _label;
1167     color_but = _color;
1168     finish();
1169 }
1170
1171 void ColorConfigControl::finish()
1172 {
1173     i_color = p_item->value.i;
1174
1175     color_px = new QPixmap( 34, 20 );
1176     color_px->fill( QColor( i_color ) );
1177     color_but->setIcon( QIcon( *color_px ) );
1178     color_but->setMinimumWidth( 40 );
1179
1180     label->setText( qtr(p_item->psz_text) );
1181     if( p_item->psz_longtext )
1182     {
1183         label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1184         color_but->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1185     }
1186
1187     BUTTONACT( color_but, selectColor() );
1188 }
1189
1190 int ColorConfigControl::getValue() const
1191 {
1192     return i_color;
1193 }
1194
1195 void ColorConfigControl::selectColor()
1196 {
1197     QColor color = QColorDialog::getColor( QColor( i_color ) );
1198     if( color.isValid() )
1199     {
1200         i_color = (color.red() << 16) + (color.green() << 8) + color.blue();
1201
1202         color_px->fill( QColor( i_color ) );
1203         color_but->setIcon( QIcon( *color_px ) );
1204     }
1205 }
1206
1207
1208 /**************************************************************************
1209  * Float-based controls
1210  *************************************************************************/
1211
1212 void
1213 VFloatConfigControl::doApply()
1214 {
1215     config_PutFloat( p_this, getName(), getValue() );
1216 }
1217
1218 /*********** Float **************/
1219 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
1220                                         module_config_t *_p_item,
1221                                         QWidget *_parent, QGridLayout *l,
1222                                         int line ) :
1223                     VFloatConfigControl( _p_this, _p_item, _parent )
1224 {
1225     label = new QLabel( qtr(p_item->psz_text) );
1226     spin = new QDoubleSpinBox;
1227     spin->setMinimumWidth( MINWIDTH_BOX );
1228     spin->setMaximumWidth( MINWIDTH_BOX );
1229     spin->setAlignment( Qt::AlignRight );
1230     finish();
1231
1232     if( !l )
1233     {
1234         QHBoxLayout *layout = new QHBoxLayout();
1235         layout->addWidget( label, 0 ); layout->addWidget( spin, LAST_COLUMN );
1236         widget->setLayout( layout );
1237     }
1238     else
1239     {
1240         l->addWidget( label, line, 0 );
1241         l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
1242     }
1243 }
1244
1245 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
1246                                         module_config_t *_p_item,
1247                                         QLabel *_label,
1248                                         QDoubleSpinBox *_spin ) :
1249                     VFloatConfigControl( _p_this, _p_item )
1250 {
1251     spin = _spin;
1252     label = _label;
1253     finish();
1254 }
1255
1256 void FloatConfigControl::finish()
1257 {
1258     spin->setMaximum( 2000000000. );
1259     spin->setMinimum( -2000000000. );
1260     spin->setSingleStep( 0.1 );
1261     spin->setValue( (double)p_item->value.f );
1262     if( p_item->psz_longtext )
1263     {
1264         QString tipText = qtr(p_item->psz_longtext);
1265         spin->setToolTip( formatTooltip(tipText) );
1266         if( label )
1267             label->setToolTip( formatTooltip(tipText) );
1268     }
1269     if( label )
1270         label->setBuddy( spin );
1271 }
1272
1273 float FloatConfigControl::getValue() const
1274 {
1275     return (float)spin->value();
1276 }
1277
1278 /*********** Float with range **************/
1279 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
1280                                         module_config_t *_p_item,
1281                                         QWidget *_parent, QGridLayout *l,
1282                                         int line ) :
1283                 FloatConfigControl( _p_this, _p_item, _parent, l, line )
1284 {
1285     finish();
1286 }
1287
1288 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
1289                                         module_config_t *_p_item,
1290                                         QLabel *_label,
1291                                         QDoubleSpinBox *_spin ) :
1292                 FloatConfigControl( _p_this, _p_item, _label, _spin )
1293 {
1294     finish();
1295 }
1296
1297 void FloatRangeConfigControl::finish()
1298 {
1299     spin->setMaximum( (double)p_item->max.f );
1300     spin->setMinimum( (double)p_item->min.f );
1301 }
1302
1303
1304 /**********************************************************************
1305  * Key selector widget
1306  **********************************************************************/
1307 KeySelectorControl::KeySelectorControl( vlc_object_t *_p_this,
1308                                       module_config_t *_p_item,
1309                                       QWidget *_parent, QGridLayout *l,
1310                                       int line ) :
1311                                 ConfigControl( _p_this, _p_item, _parent )
1312
1313 {
1314     QWidget *keyContainer = new QWidget;
1315     QGridLayout *gLayout = new QGridLayout( keyContainer );
1316
1317     label = new QLabel(
1318             qtr( "Select an action to change the associated hotkey") );
1319
1320     QLabel *searchLabel = new QLabel( qtr( "Search" ) );
1321     SearchLineEdit *actionSearch = new SearchLineEdit( keyContainer );
1322
1323     table = new QTreeWidget;
1324     table->setColumnCount(3);
1325     table->headerItem()->setText( 0, qtr( "Action" ) );
1326     table->headerItem()->setText( 1, qtr( "Hotkey" ) );
1327     table->headerItem()->setToolTip( 1, qtr( "Application level hotkey" ) );
1328     table->headerItem()->setText( 2, qtr( "Global" ) );
1329     table->headerItem()->setToolTip( 2, qtr( "Desktop level hotkey" ) );
1330     table->setAlternatingRowColors( true );
1331     table->setSelectionBehavior( QAbstractItemView::SelectItems );
1332
1333     table->installEventFilter( this );
1334
1335     finish();
1336
1337     gLayout->addWidget( label, 0, 0, 1, 4 );
1338     gLayout->addWidget( searchLabel, 1, 0, 1, 2 );
1339     gLayout->addWidget( actionSearch, 1, 2, 1, 2 );
1340     gLayout->addWidget( table, 2, 0, 1, 4 );
1341
1342     l->addWidget( keyContainer, line, 0, 1, -1 );
1343
1344     CONNECT( actionSearch, textChanged( const QString& ),
1345              this, filter( const QString& ) );
1346 }
1347
1348 void KeySelectorControl::finish()
1349 {
1350     if( label && p_item->psz_longtext )
1351         label->setToolTip( formatTooltip( qtr( p_item->psz_longtext ) ) );
1352
1353     /* Fill the table */
1354
1355     /* Get the main Module */
1356     module_t *p_main = module_get_main();
1357     assert( p_main );
1358
1359     /* Access to the module_config_t */
1360     unsigned confsize;
1361     module_config_t *p_config;
1362
1363     p_config = module_config_get (p_main, &confsize);
1364
1365     QMap<QString, QString> global_keys;
1366     for (size_t i = 0; i < confsize; i++)
1367     {
1368         module_config_t *p_item = p_config + i;
1369
1370         /* If we are a (non-global) key option not empty */
1371         if( CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL
1372          && !strncmp( p_item->psz_name , "key-", 4 )
1373          && !EMPTY_STR( p_item->psz_text ) )
1374         {
1375             /*
1376                Each tree item has:
1377                 - QString text in column 0
1378                 - QString name in data of column 0
1379                 - KeyValue in String in column 1
1380              */
1381             QTreeWidgetItem *treeItem = new QTreeWidgetItem();
1382             treeItem->setText( 0, qtr( p_item->psz_text ) );
1383             treeItem->setData( 0, Qt::UserRole,
1384                                QVariant( qfu( p_item->psz_name ) ) );
1385
1386             QString keys = qfu( p_item->value.psz );
1387             treeItem->setText( 1, keys );
1388             treeItem->setData( 1, Qt::UserRole, QVariant( keys ) );
1389             table->addTopLevelItem( treeItem );
1390             continue;
1391         }
1392
1393         if( CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL
1394          && !strncmp( p_item->psz_name , "global-key", 10 )
1395          && !EMPTY_STR( p_item->psz_text )
1396          && !EMPTY_STR( p_item->value.psz ) )
1397         {
1398             global_keys.insertMulti( qtr( p_item->psz_text ), qfu( p_item->value.psz ) );
1399         }
1400     }
1401
1402     QMap<QString, QString>::const_iterator i = global_keys.constBegin();
1403     while (i != global_keys.constEnd())
1404     {
1405         QList<QTreeWidgetItem *> list = table->findItems( i.key(), Qt::MatchExactly|Qt::MatchWrap, 0 );
1406         if( list.count() >= 1 )
1407         {
1408             QString keys = i.value();
1409             list[0]->setText( 2, keys );
1410             list[0]->setData( 2, Qt::UserRole, keys );
1411         }
1412         if( list.count() >= 2 )
1413             msg_Dbg( p_this, "This is probably wrong, %s", qtu(i.key()) );
1414
1415         i++;
1416     }
1417
1418     module_config_free (p_config);
1419
1420     table->resizeColumnToContents( 0 );
1421
1422     CONNECT( table, itemActivated( QTreeWidgetItem *, int ),
1423              this, selectKey( QTreeWidgetItem *, int ) );
1424 }
1425
1426 void KeySelectorControl::filter( const QString &qs_search )
1427 {
1428     QList<QTreeWidgetItem *> resultList =
1429             table->findItems( qs_search, Qt::MatchContains, 0 );
1430     for( int i = 0; i < table->topLevelItemCount(); i++ )
1431     {
1432         table->topLevelItem( i )->setHidden(
1433                 !resultList.contains( table->topLevelItem( i ) ) );
1434     }
1435 }
1436
1437 void KeySelectorControl::selectKey( QTreeWidgetItem *keyItem, int column )
1438 {
1439     /* This happens when triggered by ClickEater */
1440     if( keyItem == NULL ) keyItem = table->currentItem();
1441
1442     /* This can happen when nothing is selected on the treeView
1443        and the shortcutValue is clicked */
1444     if( !keyItem ) return;
1445
1446     /* If clicked on the first column, assuming user wants the normal hotkey */
1447     if( column == 0 ) column = 1;
1448
1449     bool b_global = ( column == 2 );
1450
1451     /* Launch a small dialog to ask for a new key */
1452     KeyInputDialog *d = new KeyInputDialog( table, keyItem->text( 0 ), widget, b_global );
1453     d->exec();
1454
1455     if( d->result() == QDialog::Accepted )
1456     {
1457         QString newKey = VLCKeyToString( d->keyValue );
1458
1459         /* In case of conflict, reset other keys*/
1460         if( d->conflicts )
1461         {
1462             QTreeWidgetItem *it;
1463             for( int i = 0; i < table->topLevelItemCount() ; i++ )
1464             {
1465                 it = table->topLevelItem(i);
1466                 if( ( keyItem != it ) &&
1467                     ( it->data( 1 + b_global, Qt::UserRole ).toString() == newKey ) )
1468                 {
1469                     it->setData( 1 + b_global, Qt::UserRole,
1470                                  QVariant( qfu( "Unset" ) ) );
1471                     it->setText( 1 + b_global, qtr( "Unset" ) );
1472                 }
1473             }
1474         }
1475
1476         keyItem->setText( column, newKey );
1477         keyItem->setData( column, Qt::UserRole, newKey );
1478     }
1479     delete d;
1480 }
1481
1482 void KeySelectorControl::doApply()
1483 {
1484     QTreeWidgetItem *it;
1485     for( int i = 0; i < table->topLevelItemCount() ; i++ )
1486     {
1487         it = table->topLevelItem(i);
1488         if( it->data( 1, Qt::UserRole ).toInt() >= 0 )
1489             config_PutPsz( p_this,
1490                            qtu( it->data( 0, Qt::UserRole ).toString() ),
1491                            qtu( it->data( 1, Qt::UserRole ).toString() ) );
1492         if( !it->data( 2, Qt::UserRole ).toString().isEmpty() )
1493         {
1494             config_PutPsz( p_this,
1495                            qtu( "global-" + it->data( 0, Qt::UserRole ).toString() ),
1496                            qtu( it->data( 2, Qt::UserRole ).toString() ) );
1497         }
1498
1499     }
1500 }
1501
1502 bool KeySelectorControl::eventFilter( QObject *obj, QEvent *e )
1503 {
1504     if( obj != table || e->type() != QEvent::KeyPress )
1505         return ConfigControl::eventFilter(obj, e);
1506
1507     QKeyEvent *keyEv = static_cast<QKeyEvent*>(e);
1508     QTreeWidget *aTable = static_cast<QTreeWidget *>(obj);
1509     if( keyEv->key() == Qt::Key_Escape )
1510     {
1511         aTable->clearFocus();
1512         return true;
1513     }
1514     else if( keyEv->key() == Qt::Key_Return ||
1515              keyEv->key() == Qt::Key_Enter )
1516     {
1517         selectKey( aTable->currentItem(), aTable->currentColumn() );
1518         return true;
1519     }
1520     else if( keyEv->key() == Qt::Key_Delete )
1521     {
1522         aTable->currentItem()->setText( aTable->currentColumn(), NULL );
1523         aTable->currentItem()->setData( aTable->currentColumn(), Qt::UserRole, QVariant() );
1524         return true;
1525     }
1526     else
1527         return false;
1528 }
1529
1530
1531 /**
1532  * Class KeyInputDialog
1533  **/
1534 KeyInputDialog::KeyInputDialog( QTreeWidget *_table,
1535                                 const QString& keyToChange,
1536                                 QWidget *_parent,
1537                                 bool _b_global ) :
1538                                 QDialog( _parent ), keyValue(0), b_global( _b_global )
1539 {
1540     setModal( true );
1541     conflicts = false;
1542
1543     table = _table;
1544     setWindowTitle( b_global ? qtr( "Global" ): ""
1545                     + qtr( "Hotkey for " ) + keyToChange );
1546     setWindowRole( "vlc-key-input" );
1547
1548     QVBoxLayout *vLayout = new QVBoxLayout( this );
1549     selected = new QLabel( qtr( "Press the new keys for " ) + keyToChange );
1550     vLayout->addWidget( selected , Qt::AlignCenter );
1551
1552     warning = new QLabel;
1553     warning->hide();
1554     vLayout->insertWidget( 1, warning );
1555
1556     buttonBox = new QDialogButtonBox;
1557     QPushButton *ok = new QPushButton( qtr("OK") );
1558     QPushButton *cancel = new QPushButton( qtr("Cancel") );
1559     buttonBox->addButton( ok, QDialogButtonBox::AcceptRole );
1560     buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
1561     ok->setDefault( true );
1562
1563     vLayout->addWidget( buttonBox );
1564     buttonBox->hide();
1565
1566     CONNECT( buttonBox, accepted(), this, accept() );
1567     CONNECT( buttonBox, rejected(), this, reject() );
1568 }
1569
1570 void KeyInputDialog::checkForConflicts( int i_vlckey )
1571 {
1572     QList<QTreeWidgetItem *> conflictList =
1573         table->findItems( VLCKeyToString( i_vlckey ), Qt::MatchExactly,
1574                           b_global ? 2 : 1 );
1575
1576     if( conflictList.count() &&
1577         !conflictList[0]->data( b_global ? 2 : 1, Qt::UserRole ).toString().isEmpty() &&
1578          conflictList[0]->data( b_global ? 2 : 1, Qt::UserRole ).toString() != "Unset" )
1579     {
1580         warning->setText( qtr("Warning: the key is already assigned to \"") +
1581                 conflictList[0]->text( 0 ) + "\"" );
1582         warning->show();
1583         buttonBox->show();
1584
1585         conflicts = true;
1586     }
1587     else accept();
1588 }
1589
1590 void KeyInputDialog::keyPressEvent( QKeyEvent *e )
1591 {
1592     if( e->key() == Qt::Key_Tab ||
1593         e->key() == Qt::Key_Shift ||
1594         e->key() == Qt::Key_Control ||
1595         e->key() == Qt::Key_Meta ||
1596         e->key() == Qt::Key_Alt ||
1597         e->key() == Qt::Key_AltGr )
1598         return;
1599     int i_vlck = qtEventToVLCKey( e );
1600     selected->setText( qtr( "Key: " ) + VLCKeyToString( i_vlck ) );
1601     checkForConflicts( i_vlck );
1602     keyValue = i_vlck;
1603 }
1604
1605 void KeyInputDialog::wheelEvent( QWheelEvent *e )
1606 {
1607     int i_vlck = qtWheelEventToVLCKey( e );
1608     selected->setText( qtr( "Key: " ) + VLCKeyToString( i_vlck ) );
1609     checkForConflicts( i_vlck );
1610     keyValue = i_vlck;
1611 }
1612