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