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