1 /*****************************************************************************
2 * preferences_widgets.cpp : Widgets for preferences displays
3 ****************************************************************************
4 * Copyright (C) 2006-2007 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@videolan.org>
8 * Antoine Cellerier <dionoea@videolan.org>
9 * Jean-Baptiste Kempf <jb@videolan.org>
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.
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.
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 *****************************************************************************/
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
37 #include "components/preferences_widgets.hpp"
38 #include "util/customwidgets.hpp"
39 #include "util/qt_dirs.hpp"
44 #include <QGridLayout>
46 #include <QFileDialog>
48 #include <QTreeWidgetItem>
49 #include <QSignalMapper>
50 #include <QDialogButtonBox>
52 #define MINWIDTH_BOX 90
53 #define LAST_COLUMN 10
55 QString formatTooltip(const QString & tooltip)
58 "<html><head><meta name=\"qrichtext\" content=\"1\" />"
59 "<style type=\"text/css\"> p, li { white-space: pre-wrap; } </style></head>"
60 "<body style=\" font-family:'Sans Serif'; "
61 "font-style:normal; text-decoration:none;\">"
62 "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; "
63 "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" +
69 ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
70 module_config_t *p_item,
74 return createControl( p_this, p_item, parent, NULL, i );
77 ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
78 module_config_t *p_item,
80 QGridLayout *l, int &line )
82 ConfigControl *p_control = NULL;
84 switch( p_item->i_type )
86 case CONFIG_ITEM_MODULE:
87 p_control = new ModuleConfigControl( p_this, p_item, parent, false,
90 case CONFIG_ITEM_MODULE_CAT:
91 p_control = new ModuleConfigControl( p_this, p_item, parent, true,
94 case CONFIG_ITEM_MODULE_LIST:
95 p_control = new ModuleListConfigControl( p_this, p_item, parent, false,
98 case CONFIG_ITEM_MODULE_LIST_CAT:
99 p_control = new ModuleListConfigControl( p_this, p_item, parent, true,
101 /* Special Hack for a bug in video-filter */
102 if( qobject_cast<ModuleListConfigControl *>( p_control )->groupBox == NULL )
105 case CONFIG_ITEM_STRING:
106 if( !p_item->i_list )
107 p_control = new StringConfigControl( p_this, p_item, parent,
110 p_control = new StringListConfigControl( p_this, p_item,
111 parent, false, l, line );
113 case CONFIG_ITEM_PASSWORD:
114 if( !p_item->i_list )
115 p_control = new StringConfigControl( p_this, p_item, parent,
118 p_control = new StringListConfigControl( p_this, p_item,
119 parent, true, l, line );
121 case CONFIG_ITEM_INTEGER:
123 p_control = new IntegerListConfigControl( p_this, p_item,
124 parent, false, l, line );
125 else if( p_item->min.i || p_item->max.i )
126 p_control = new IntegerRangeConfigControl( p_this, p_item, parent,
129 p_control = new IntegerConfigControl( p_this, p_item, parent,
132 case CONFIG_ITEM_FILE:
133 p_control = new FileConfigControl( p_this, p_item, parent, l, line);
135 case CONFIG_ITEM_DIRECTORY:
136 p_control = new DirectoryConfigControl( p_this, p_item, parent, l,
140 case CONFIG_ITEM_FONT:
141 p_control = new FontConfigControl( p_this, p_item, parent, l,
145 case CONFIG_ITEM_KEY:
146 p_control = new KeySelectorControl( p_this, p_item, parent, l, line );
148 case CONFIG_ITEM_BOOL:
149 p_control = new BoolConfigControl( p_this, p_item, parent, l, line );
151 case CONFIG_ITEM_FLOAT:
152 if( p_item->min.f || p_item->max.f )
153 p_control = new FloatRangeConfigControl( p_this, p_item, parent,
156 p_control = new FloatConfigControl( p_this, p_item, parent,
165 void ConfigControl::doApply( intf_thread_t *p_intf )
169 case CONFIG_ITEM_INTEGER:
170 case CONFIG_ITEM_BOOL:
172 VIntConfigControl *vicc = qobject_cast<VIntConfigControl *>(this);
174 config_PutInt( p_intf, vicc->getName(), vicc->getValue() );
177 case CONFIG_ITEM_FLOAT:
179 VFloatConfigControl *vfcc =
180 qobject_cast<VFloatConfigControl *>(this);
182 config_PutFloat( p_intf, vfcc->getName(), vfcc->getValue() );
185 case CONFIG_ITEM_STRING:
187 VStringConfigControl *vscc =
188 qobject_cast<VStringConfigControl *>(this);
190 config_PutPsz( p_intf, vscc->getName(), qtu( vscc->getValue() ) );
193 case CONFIG_ITEM_KEY:
195 KeySelectorControl *ksc = qobject_cast<KeySelectorControl *>(this);
202 /*******************************************************
204 *******************************************************/
205 InterfacePreviewWidget::InterfacePreviewWidget
206 ( QWidget *parent ) : QLabel( parent, 0 )
208 setGeometry( 0, 0, 128, 100 );
209 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
212 void InterfacePreviewWidget::setPreview( int comboid )
214 /* Need to move resources references as soon as qt4.cpp
215 local defines has been moved somewhere else
217 char * pixmaps[] = { ":/prefsmenu/sample_classic",
218 ":/prefsmenu/sample_complete",
219 ":/prefsmenu/sample_minimal" };
220 setPixmap( QPixmap( pixmaps[ comboid ] ) );
225 /**************************************************************************
226 * String-based controls
227 *************************************************************************/
229 /*********** String **************/
230 StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
231 module_config_t *_p_item,
232 QWidget *_parent, QGridLayout *l,
233 int &line, bool pwd ) :
234 VStringConfigControl( _p_this, _p_item, _parent )
236 label = new QLabel( qtr(p_item->psz_text) );
237 text = new QLineEdit( qfu(p_item->value.psz) );
238 if( pwd ) text->setEchoMode( QLineEdit::Password );
243 QHBoxLayout *layout = new QHBoxLayout();
244 layout->addWidget( label, 0 ); layout->insertSpacing( 1, 10 );
245 layout->addWidget( text, LAST_COLUMN );
246 widget->setLayout( layout );
250 l->addWidget( label, line, 0 );
251 l->setColumnMinimumWidth( 1, 10 );
252 l->addWidget( text, line, LAST_COLUMN );
256 StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
257 module_config_t *_p_item,
258 QLabel *_label, QLineEdit *_text, bool pwd ):
259 VStringConfigControl( _p_this, _p_item )
262 if( pwd ) text->setEchoMode( QLineEdit::Password );
267 void StringConfigControl::finish()
269 text->setText( qfu(p_item->value.psz) );
270 text->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
273 label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
274 label->setBuddy( text );
278 /*********** File **************/
279 FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
280 module_config_t *_p_item,
281 QWidget *_parent, QGridLayout *l,
283 VStringConfigControl( _p_this, _p_item, _parent )
285 label = new QLabel( qtr(p_item->psz_text) );
286 text = new QLineEdit( qfu(p_item->value.psz) );
287 browse = new QPushButton( qtr( "Browse..." ) );
288 QHBoxLayout *textAndButton = new QHBoxLayout();
289 textAndButton->setMargin( 0 );
290 textAndButton->addWidget( text, 2 );
291 textAndButton->addWidget( browse, 0 );
293 BUTTONACT( browse, updateField() );
299 QHBoxLayout *layout = new QHBoxLayout();
300 layout->addWidget( label, 0 );
301 layout->insertSpacing( 1, 10 );
302 layout->addLayout( textAndButton, LAST_COLUMN );
303 widget->setLayout( layout );
307 l->addWidget( label, line, 0 );
308 l->setColumnMinimumWidth( 1, 10 );
309 l->addLayout( textAndButton, line, LAST_COLUMN );
314 FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
315 module_config_t *_p_item,
316 QLabel *_label, QLineEdit *_text,
317 QPushButton *_button ):
318 VStringConfigControl( _p_this, _p_item )
324 BUTTONACT( browse, updateField() );
329 void FileConfigControl::updateField()
331 QString file = QFileDialog::getOpenFileName( NULL,
332 qtr( "Select File" ), qfu( config_GetHomeDir() ) );
333 if( file.isNull() ) return;
334 text->setText( toNativeSeparators( file ) );
337 void FileConfigControl::finish()
339 text->setText( qfu(p_item->value.psz) );
340 text->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
343 label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
344 label->setBuddy( text );
348 /********* String / Directory **********/
349 DirectoryConfigControl::DirectoryConfigControl( vlc_object_t *_p_this,
350 module_config_t *_p_item, QWidget *_p_widget,
351 QGridLayout *_p_layout, int& _int ) :
352 FileConfigControl( _p_this, _p_item, _p_widget, _p_layout, _int )
355 DirectoryConfigControl::DirectoryConfigControl( vlc_object_t *_p_this,
356 module_config_t *_p_item, QLabel *_p_label,
357 QLineEdit *_p_line, QPushButton *_p_button ):
358 FileConfigControl( _p_this, _p_item, _p_label, _p_line, _p_button)
361 void DirectoryConfigControl::updateField()
363 QString dir = QFileDialog::getExistingDirectory( NULL,
364 qtr( "Select Directory" ),
365 text->text().isEmpty() ?
366 qfu( config_GetHomeDir() ) : text->text(),
367 QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks );
369 if( dir.isNull() ) return;
370 text->setText( toNativeSepNoSlash( dir ) );
374 #include <QFontDialog>
376 /********* String / Font **********/
377 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
378 module_config_t *_p_item, QWidget *_p_widget,
379 QGridLayout *_p_layout, int& _int, bool _pwd ) :
380 FileConfigControl( _p_this, _p_item, _p_widget, _p_layout, _int, _pwd)
383 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
384 module_config_t *_p_item, QLabel *_p_label,
385 QLineEdit *_p_line, QPushButton *_p_button, bool _pwd ):
386 FileConfigControl( _p_this, _p_item, _p_label, _p_line, _p_button, _pwd)
389 void FontConfigControl::updateField()
392 QFont font = QFontDialog::getFont( &ok, QFont( text->text() ), NULL );
394 text->setText( font.family() );
398 /********* String / choice list **********/
399 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
400 module_config_t *_p_item, QWidget *_parent, bool bycat,
401 QGridLayout *l, int &line) :
402 VStringConfigControl( _p_this, _p_item, _parent )
404 label = new QLabel( qtr(p_item->psz_text) );
405 combo = new QComboBox();
406 combo->setMinimumWidth( MINWIDTH_BOX );
407 combo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
409 module_config_t *p_module_config = config_FindConfig( p_this, p_item->psz_name );
410 if(p_module_config && p_module_config->pf_update_list)
413 val.psz_string = strdup(p_module_config->value.psz);
415 p_module_config->pf_update_list(p_this, p_item->psz_name, val, val, NULL);
417 // assume in any case that dirty was set to true
418 // because lazy programmes will use the same callback for
419 // this, like the one behind the refresh push button?
420 p_module_config->b_dirty = false;
422 free( val.psz_string );
425 finish( p_module_config, bycat );
428 l = new QGridLayout();
429 l->addWidget( label, 0, 0 ); l->addWidget( combo, 0, LAST_COLUMN );
430 widget->setLayout( l );
434 l->addWidget( label, line, 0 );
435 l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
438 if( p_item->i_action )
440 QSignalMapper *signalMapper = new QSignalMapper(this);
442 /* Some stringLists like Capture listings have action associated */
443 for( int i = 0; i < p_item->i_action; i++ )
445 QPushButton *button =
446 new QPushButton( qfu( p_item->ppsz_action_text[i] ));
447 CONNECT( button, clicked(), signalMapper, map() );
448 signalMapper->setMapping( button, i );
449 l->addWidget( button, line, LAST_COLUMN - p_item->i_action + i,
452 CONNECT( signalMapper, mapped( int ),
453 this, actionRequested( int ) );
457 void StringListConfigControl::actionRequested( int i_action )
459 /* Supplementary check for boundaries */
460 if( i_action < 0 || i_action >= p_item->i_action ) return;
462 module_config_t *p_module_config = config_FindConfig( p_this, getName() );
463 if(!p_module_config) return;
466 val.psz_string = const_cast<char *>
467 qtu( (combo->itemData( combo->currentIndex() ).toString() ) );
469 p_module_config->ppf_action[i_action]( p_this, getName(), val, val, 0 );
471 if( p_module_config->b_dirty )
474 finish( p_module_config, true );
475 p_module_config->b_dirty = false;
478 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
479 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
480 bool bycat ) : VStringConfigControl( _p_this, _p_item )
485 module_config_t *p_module_config = config_FindConfig( p_this, getName() );
487 finish( p_module_config, bycat );
490 void StringListConfigControl::finish(module_config_t *p_module_config, bool bycat )
492 combo->setEditable( false );
494 if(!p_module_config) return;
496 for( int i_index = 0; i_index < p_module_config->i_list; i_index++ )
498 combo->addItem( qfu((p_module_config->ppsz_list_text &&
499 p_module_config->ppsz_list_text[i_index])?
500 p_module_config->ppsz_list_text[i_index] :
501 p_module_config->ppsz_list[i_index] ),
502 QVariant( qfu(p_module_config->ppsz_list[i_index] )) );
503 if( p_item->value.psz && !strcmp( p_module_config->value.psz,
504 p_module_config->ppsz_list[i_index] ) )
505 combo->setCurrentIndex( combo->count() - 1 );
507 combo->setToolTip( formatTooltip(qtr(p_module_config->psz_longtext)) );
510 label->setToolTip( formatTooltip(qtr(p_module_config->psz_longtext)) );
511 label->setBuddy( combo );
515 QString StringListConfigControl::getValue()
517 return combo->itemData( combo->currentIndex() ).toString();
520 void setfillVLCConfigCombo( const char *configname, intf_thread_t *p_intf,
523 module_config_t *p_config =
524 config_FindConfig( VLC_OBJECT(p_intf), configname );
527 if(p_config->pf_update_list)
530 val.i_int = p_config->value.i;
531 p_config->pf_update_list(VLC_OBJECT(p_intf), configname, val, val, NULL);
532 // assume in any case that dirty was set to true
533 // because lazy programmes will use the same callback for
534 // this, like the one behind the refresh push button?
535 p_config->b_dirty = false;
538 for ( int i_index = 0; i_index < p_config->i_list; i_index++ )
540 combo->addItem( qfu( p_config->ppsz_list_text[i_index] ),
541 QVariant( p_config->pi_list[i_index] ) );
542 if( p_config->value.i == p_config->pi_list[i_index] )
544 combo->setCurrentIndex( i_index );
547 combo->setToolTip( qfu( p_config->psz_longtext ) );
551 /********* Module **********/
552 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
553 module_config_t *_p_item, QWidget *_parent, bool bycat,
554 QGridLayout *l, int &line) :
555 VStringConfigControl( _p_this, _p_item, _parent )
557 label = new QLabel( qtr(p_item->psz_text) );
558 combo = new QComboBox();
559 combo->setMinimumWidth( MINWIDTH_BOX );
563 QHBoxLayout *layout = new QHBoxLayout();
564 layout->addWidget( label ); layout->addWidget( combo, LAST_COLUMN );
565 widget->setLayout( layout );
569 l->addWidget( label, line, 0 );
570 l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
574 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
575 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
576 bool bycat ) : VStringConfigControl( _p_this, _p_item )
583 void ModuleConfigControl::finish( bool bycat )
587 combo->setEditable( false );
589 /* build a list of available modules */
590 module_t **p_list = module_list_get( NULL );
591 combo->addItem( qtr("Default") );
592 for( size_t i = 0; (p_parser = p_list[i]) != NULL; i++ )
596 if( !strcmp( module_get_object( p_parser ), "main" ) ) continue;
599 module_config_t *p_config;
601 p_config = module_config_get (p_parser, &confsize);
602 for (size_t i = 0; i < confsize; i++)
604 /* Hack: required subcategory is stored in i_min */
605 const module_config_t *p_cfg = p_config + i;
606 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
607 p_cfg->value.i == p_item->min.i )
608 combo->addItem( qtr( module_GetLongName( p_parser )),
609 QVariant( module_get_object( p_parser ) ) );
610 if( p_item->value.psz && !strcmp( p_item->value.psz,
611 module_get_object( p_parser ) ) )
612 combo->setCurrentIndex( combo->count() - 1 );
614 module_config_free (p_config);
616 else if( module_provides( p_parser, p_item->psz_type ) )
618 combo->addItem( qtr(module_GetLongName( p_parser ) ),
619 QVariant( module_get_object( p_parser ) ) );
620 if( p_item->value.psz && !strcmp( p_item->value.psz,
621 module_get_object( p_parser ) ) )
622 combo->setCurrentIndex( combo->count() - 1 );
625 module_list_free( p_list );
626 combo->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
629 label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
630 label->setBuddy( combo );
634 QString ModuleConfigControl::getValue()
636 return combo->itemData( combo->currentIndex() ).toString();
639 /********* Module list **********/
640 ModuleListConfigControl::ModuleListConfigControl( vlc_object_t *_p_this,
641 module_config_t *_p_item, QWidget *_parent, bool bycat,
642 QGridLayout *l, int &line) :
643 VStringConfigControl( _p_this, _p_item, _parent )
647 if( !p_item->psz_text ) return;
649 groupBox = new QGroupBox ( qtr(p_item->psz_text), _parent );
650 text = new QLineEdit;
651 QGridLayout *layoutGroupBox = new QGridLayout( groupBox );
656 for( QVector<checkBoxListItem*>::iterator it = modules.begin();
657 it != modules.end(); it++ )
659 layoutGroupBox->addWidget( (*it)->checkBox, boxline++, 0 );
661 layoutGroupBox->addWidget( text, boxline, 0 );
665 QVBoxLayout *layout = new QVBoxLayout();
666 layout->addWidget( groupBox, line, 0 );
667 widget->setLayout( layout );
671 l->addWidget( groupBox, line, 0, 1, -1 );
674 text->setToolTip( formatTooltip( qtr( p_item->psz_longtext) ) );
677 ModuleListConfigControl::~ModuleListConfigControl()
679 for( QVector<checkBoxListItem*>::iterator it = modules.begin();
680 it != modules.end(); it++ )
687 #define CHECKBOX_LISTS \
689 QCheckBox *cb = new QCheckBox( qtr( module_GetLongName( p_parser ) ) );\
690 checkBoxListItem *cbl = new checkBoxListItem; \
692 CONNECT( cb, stateChanged( int ), this, onUpdate() );\
693 cb->setToolTip( formatTooltip( qtr( module_get_help( p_parser ))));\
694 cbl->checkBox = cb; \
696 cbl->psz_module = strdup( module_get_object( p_parser ) ); \
697 modules.push_back( cbl ); \
699 if( p_item->value.psz && strstr( p_item->value.psz, cbl->psz_module ) ) \
700 cbl->checkBox->setChecked( true ); \
704 void ModuleListConfigControl::finish( bool bycat )
708 /* build a list of available modules */
709 module_t **p_list = module_list_get( NULL );
710 for( size_t i = 0; (p_parser = p_list[i]) != NULL; i++ )
714 if( !strcmp( module_get_object( p_parser ), "main" ) ) continue;
717 module_config_t *p_config = module_config_get (p_parser, &confsize);
719 for (size_t i = 0; i < confsize; i++)
721 module_config_t *p_cfg = p_config + i;
722 /* Hack: required subcategory is stored in i_min */
723 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
724 p_cfg->value.i == p_item->min.i )
729 module_config_free (p_config);
731 else if( module_provides( p_parser, p_item->psz_type ) )
736 module_list_free( p_list );
737 text->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
739 groupBox->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
741 #undef CHECKBOX_LISTS
743 QString ModuleListConfigControl::getValue()
749 void ModuleListConfigControl::hide()
751 for( QVector<checkBoxListItem*>::iterator it = modules.begin();
752 it != modules.end(); it++ )
754 (*it)->checkBox->hide();
759 void ModuleListConfigControl::show()
761 for( QVector<checkBoxListItem*>::iterator it = modules.begin();
762 it != modules.end(); it++ )
764 (*it)->checkBox->show();
770 void ModuleListConfigControl::onUpdate()
775 for( QVector<checkBoxListItem*>::iterator it = modules.begin();
776 it != modules.end(); it++ )
778 if( (*it)->checkBox->isChecked() )
782 text->setText( text->text() + (*it)->psz_module );
787 text->setText( text->text() + ":" + (*it)->psz_module );
793 /**************************************************************************
794 * Integer-based controls
795 *************************************************************************/
797 /*********** Integer **************/
798 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
799 module_config_t *_p_item,
800 QWidget *_parent, QGridLayout *l,
802 VIntConfigControl( _p_this, _p_item, _parent )
804 label = new QLabel( qtr(p_item->psz_text) );
805 spin = new QSpinBox; spin->setMinimumWidth( MINWIDTH_BOX );
806 spin->setAlignment( Qt::AlignRight );
807 spin->setMaximumWidth( MINWIDTH_BOX );
812 QHBoxLayout *layout = new QHBoxLayout();
813 layout->addWidget( label, 0 ); layout->addWidget( spin, LAST_COLUMN );
814 widget->setLayout( layout );
818 l->addWidget( label, line, 0 );
819 l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
822 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
823 module_config_t *_p_item,
824 QLabel *_label, QSpinBox *_spin ) :
825 VIntConfigControl( _p_this, _p_item )
832 void IntegerConfigControl::finish()
834 spin->setMaximum( 2000000000 );
835 spin->setMinimum( -2000000000 );
836 spin->setValue( p_item->value.i );
837 spin->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
840 label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
841 label->setBuddy( spin );
845 int IntegerConfigControl::getValue()
847 return spin->value();
850 /********* Integer range **********/
851 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
852 module_config_t *_p_item,
853 QWidget *_parent, QGridLayout *l,
855 IntegerConfigControl( _p_this, _p_item, _parent, l, line )
860 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
861 module_config_t *_p_item,
862 QLabel *_label, QSpinBox *_spin ) :
863 IntegerConfigControl( _p_this, _p_item, _label, _spin )
868 void IntegerRangeConfigControl::finish()
870 spin->setMaximum( p_item->max.i );
871 spin->setMinimum( p_item->min.i );
874 IntegerRangeSliderConfigControl::IntegerRangeSliderConfigControl(
875 vlc_object_t *_p_this,
876 module_config_t *_p_item,
877 QLabel *_label, QSlider *_slider ):
878 VIntConfigControl( _p_this, _p_item )
882 slider->setMaximum( p_item->max.i );
883 slider->setMinimum( p_item->min.i );
884 slider->setValue( p_item->value.i );
885 slider->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
888 label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
889 label->setBuddy( slider );
893 int IntegerRangeSliderConfigControl::getValue()
895 return slider->value();
899 /********* Integer / choice list **********/
900 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
901 module_config_t *_p_item, QWidget *_parent, bool bycat,
902 QGridLayout *l, int &line) :
903 VIntConfigControl( _p_this, _p_item, _parent )
905 label = new QLabel( qtr(p_item->psz_text) );
906 combo = new QComboBox();
907 combo->setMinimumWidth( MINWIDTH_BOX );
909 module_config_t *p_module_config = config_FindConfig( p_this, p_item->psz_name );
910 if(p_module_config && p_module_config->pf_update_list)
913 val.i_int = p_module_config->value.i;
915 p_module_config->pf_update_list(p_this, p_item->psz_name, val, val, NULL);
917 // assume in any case that dirty was set to true
918 // because lazy programmes will use the same callback for
919 // this, like the one behind the refresh push button?
920 p_module_config->b_dirty = false;
924 finish( p_module_config, bycat );
927 QHBoxLayout *layout = new QHBoxLayout();
928 layout->addWidget( label ); layout->addWidget( combo, LAST_COLUMN );
929 widget->setLayout( layout );
933 l->addWidget( label, line, 0 );
934 l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
937 if( p_item->i_action )
939 QSignalMapper *signalMapper = new QSignalMapper(this);
941 /* Some stringLists like Capture listings have action associated */
942 for( int i = 0; i < p_item->i_action; i++ )
944 QPushButton *button =
945 new QPushButton( qfu( p_item->ppsz_action_text[i] ));
946 CONNECT( button, clicked(), signalMapper, map() );
947 signalMapper->setMapping( button, i );
948 l->addWidget( button, line, LAST_COLUMN - p_item->i_action + i,
951 CONNECT( signalMapper, mapped( int ),
952 this, actionRequested( int ) );
956 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
957 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
958 bool bycat ) : VIntConfigControl( _p_this, _p_item )
963 module_config_t *p_module_config = config_FindConfig( p_this, getName() );
965 finish( p_module_config, bycat );
968 void IntegerListConfigControl::finish(module_config_t *p_module_config, bool bycat )
970 combo->setEditable( false );
972 if(!p_module_config) return;
974 for( int i_index = 0; i_index < p_module_config->i_list; i_index++ )
976 combo->addItem( qtr(p_module_config->ppsz_list_text[i_index] ),
977 QVariant( p_module_config->pi_list[i_index] ) );
978 if( p_module_config->value.i == p_module_config->pi_list[i_index] )
979 combo->setCurrentIndex( combo->count() - 1 );
981 combo->setToolTip( formatTooltip(qtr(p_module_config->psz_longtext)) );
984 label->setToolTip( formatTooltip(qtr(p_module_config->psz_longtext)) );
985 label->setBuddy( combo );
989 void IntegerListConfigControl::actionRequested( int i_action )
991 /* Supplementary check for boundaries */
992 if( i_action < 0 || i_action >= p_item->i_action ) return;
994 module_config_t *p_module_config = config_FindConfig( p_this, getName() );
995 if(!p_module_config) return;
999 val.i_int = combo->itemData( combo->currentIndex() ).toInt();
1001 p_module_config->ppf_action[i_action]( p_this, getName(), val, val, 0 );
1003 if( p_module_config->b_dirty )
1006 finish( p_module_config, true );
1007 p_module_config->b_dirty = false;
1011 int IntegerListConfigControl::getValue()
1013 return combo->itemData( combo->currentIndex() ).toInt();
1016 /*********** Boolean **************/
1017 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
1018 module_config_t *_p_item,
1019 QWidget *_parent, QGridLayout *l,
1021 VIntConfigControl( _p_this, _p_item, _parent )
1023 checkbox = new QCheckBox( qtr(p_item->psz_text) );
1028 QHBoxLayout *layout = new QHBoxLayout();
1029 layout->addWidget( checkbox, 0 );
1030 widget->setLayout( layout );
1034 l->addWidget( checkbox, line, 0 );
1037 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
1038 module_config_t *_p_item,
1040 QAbstractButton *_checkbox,
1042 VIntConfigControl( _p_this, _p_item )
1044 checkbox = _checkbox;
1045 VLC_UNUSED( _label );
1049 void BoolConfigControl::finish()
1051 checkbox->setChecked( p_item->value.i == true );
1052 checkbox->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1055 int BoolConfigControl::getValue()
1057 return checkbox->isChecked();
1060 /**************************************************************************
1061 * Float-based controls
1062 *************************************************************************/
1064 /*********** Float **************/
1065 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
1066 module_config_t *_p_item,
1067 QWidget *_parent, QGridLayout *l,
1069 VFloatConfigControl( _p_this, _p_item, _parent )
1071 label = new QLabel( qtr(p_item->psz_text) );
1072 spin = new QDoubleSpinBox;
1073 spin->setMinimumWidth( MINWIDTH_BOX );
1074 spin->setMaximumWidth( MINWIDTH_BOX );
1075 spin->setAlignment( Qt::AlignRight );
1080 QHBoxLayout *layout = new QHBoxLayout();
1081 layout->addWidget( label, 0 ); layout->addWidget( spin, LAST_COLUMN );
1082 widget->setLayout( layout );
1086 l->addWidget( label, line, 0 );
1087 l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
1091 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
1092 module_config_t *_p_item,
1094 QDoubleSpinBox *_spin ) :
1095 VFloatConfigControl( _p_this, _p_item )
1102 void FloatConfigControl::finish()
1104 spin->setMaximum( 2000000000. );
1105 spin->setMinimum( -2000000000. );
1106 spin->setSingleStep( 0.1 );
1107 spin->setValue( (double)p_item->value.f );
1108 spin->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1111 label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
1112 label->setBuddy( spin );
1116 float FloatConfigControl::getValue()
1118 return (float)spin->value();
1121 /*********** Float with range **************/
1122 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
1123 module_config_t *_p_item,
1124 QWidget *_parent, QGridLayout *l,
1126 FloatConfigControl( _p_this, _p_item, _parent, l, line )
1131 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
1132 module_config_t *_p_item,
1134 QDoubleSpinBox *_spin ) :
1135 FloatConfigControl( _p_this, _p_item, _label, _spin )
1140 void FloatRangeConfigControl::finish()
1142 spin->setMaximum( (double)p_item->max.f );
1143 spin->setMinimum( (double)p_item->min.f );
1147 /**********************************************************************
1148 * Key selector widget
1149 **********************************************************************/
1150 KeySelectorControl::KeySelectorControl( vlc_object_t *_p_this,
1151 module_config_t *_p_item,
1152 QWidget *_parent, QGridLayout *l,
1154 ConfigControl( _p_this, _p_item, _parent )
1157 QWidget *keyContainer = new QWidget;
1158 QGridLayout *gLayout = new QGridLayout( keyContainer );
1161 qtr( "Select an action to change the associated hotkey") );
1163 QLabel *searchLabel = new QLabel( qtr( "Search" ) );
1164 actionSearch = new SearchLineEdit( keyContainer );
1166 table = new QTreeWidget;
1167 table->setColumnCount(3);
1168 table->headerItem()->setText( 0, qtr( "Action" ) );
1169 table->headerItem()->setText( 1, qtr( "Hotkey" ) );
1170 table->headerItem()->setText( 2, qtr( "Global" ) );
1171 table->setAlternatingRowColors( true );
1173 shortcutValue = new KeyShortcutEdit;
1174 shortcutValue->setReadOnly(true);
1176 QPushButton *clearButton = new QPushButton( qtr( "Clear" ) );
1177 QPushButton *setButton = new QPushButton( qtr( "Set" ) );
1178 setButton->setDefault( true );
1181 gLayout->addWidget( label, 0, 0, 1, 4 );
1182 gLayout->addWidget( searchLabel, 1, 0, 1, 2 );
1183 gLayout->addWidget( actionSearch, 1, 2, 1, 2 );
1184 gLayout->addWidget( table, 2, 0, 1, 4 );
1185 gLayout->addWidget( clearButton, 3, 0, 1, 1 );
1186 gLayout->addWidget( shortcutValue, 3, 1, 1, 2 );
1187 gLayout->addWidget( setButton, 3, 3, 1, 1 );
1189 l->addWidget( keyContainer, line, 0, 1, -1 );
1191 CONNECT( clearButton, clicked(), shortcutValue, clear() );
1192 CONNECT( clearButton, clicked(), this, setTheKey() );
1193 BUTTONACT( setButton, setTheKey() );
1194 CONNECT( actionSearch, textChanged( const QString& ),
1195 this, filter( const QString& ) );
1198 void KeySelectorControl::finish()
1201 label->setToolTip( formatTooltip( qtr( p_item->psz_longtext ) ) );
1203 /* Fill the table */
1205 /* Get the main Module */
1206 module_t *p_main = module_get_main();
1209 /* Access to the module_config_t */
1211 module_config_t *p_config;
1213 p_config = module_config_get (p_main, &confsize);
1215 for (size_t i = 0; i < confsize; i++)
1217 module_config_t *p_item = p_config + i;
1219 /* If we are a key option not empty */
1220 if( p_item->i_type & CONFIG_ITEM && p_item->psz_name
1221 && strstr( p_item->psz_name , "key-" )
1222 && !strstr( p_item->psz_name , "global-key" )
1223 && !EMPTY_STR( p_item->psz_text ) )
1227 - QString text in column 0
1228 - QString name in data of column 0
1229 - KeyValue in String in column 1
1230 - KeyValue in int in column 1
1232 QTreeWidgetItem *treeItem = new QTreeWidgetItem();
1233 treeItem->setText( 0, qtr( p_item->psz_text ) );
1234 treeItem->setData( 0, Qt::UserRole,
1235 QVariant( qfu( p_item->psz_name ) ) );
1236 treeItem->setText( 1, VLCKeyToString( p_item->value.i ) );
1237 treeItem->setData( 1, Qt::UserRole, QVariant( p_item->value.i ) );
1238 table->addTopLevelItem( treeItem );
1242 if( p_item->i_type & CONFIG_ITEM && p_item->psz_name
1243 && strstr( p_item->psz_name , "global-key" )
1244 && !EMPTY_STR( p_item->psz_text ) )
1246 QList<QTreeWidgetItem *> list =
1247 table->findItems( qtr( p_item->psz_text ), Qt::MatchExactly );
1248 if( list.count() >= 1 )
1250 list[0]->setText( 2, VLCKeyToString( p_item->value.i ) );
1251 list[0]->setData( 2, Qt::UserRole,
1252 QVariant( p_item->value.i ) );
1254 if( list.count() >= 2 )
1255 msg_Dbg( p_this, "This is probably wrong, %s", p_item->psz_text );
1258 module_config_free (p_config);
1259 module_release (p_main);
1261 table->resizeColumnToContents( 0 );
1263 CONNECT( table, itemDoubleClicked( QTreeWidgetItem *, int ),
1264 this, selectKey( QTreeWidgetItem *, int ) );
1265 CONNECT( table, itemSelectionChanged(),
1266 this, select1Key() );
1268 CONNECT( shortcutValue, pressed(), this, selectKey() );
1271 void KeySelectorControl::filter( const QString &qs_search )
1273 QList<QTreeWidgetItem *> resultList =
1274 table->findItems( qs_search, Qt::MatchContains, 0 );
1275 for( int i = 0; i < table->topLevelItemCount(); i++ )
1277 table->topLevelItem( i )->setHidden(
1278 !resultList.contains( table->topLevelItem( i ) ) );
1282 /* Show the key selected from the table in the keySelector */
1283 void KeySelectorControl::select1Key()
1285 QTreeWidgetItem *keyItem = table->currentItem();
1286 shortcutValue->setText( keyItem->text( 1 ) );
1287 shortcutValue->setValue( keyItem->data( 1, Qt::UserRole ).toInt() );
1288 shortcutValue->setGlobal( false );
1291 void KeySelectorControl::selectKey( QTreeWidgetItem *keyItem, int column )
1293 /* This happens when triggered by ClickEater */
1294 if( keyItem == NULL ) keyItem = table->currentItem();
1296 /* This can happen when nothing is selected on the treeView
1297 and the shortcutValue is clicked */
1298 if( !keyItem ) return;
1300 /* If clicked on the first column, assuming user wants the normal hotkey */
1301 if( column == 0 ) column = 1;
1303 bool b_global = ( column == 2 );
1305 /* Launch a small dialog to ask for a new key */
1306 KeyInputDialog *d = new KeyInputDialog( table, keyItem->text( 0 ), widget, b_global );
1309 if( d->result() == QDialog::Accepted )
1311 int newValue = d->keyValue;
1312 shortcutValue->setText( VLCKeyToString( newValue ) );
1313 shortcutValue->setValue( newValue );
1314 shortcutValue->setGlobal( b_global );
1318 QTreeWidgetItem *it;
1319 for( int i = 0; i < table->topLevelItemCount() ; i++ )
1321 it = table->topLevelItem(i);
1322 if( ( keyItem != it ) &&
1323 ( it->data( b_global ? 2: 1, Qt::UserRole ).toInt() == newValue ) )
1325 it->setData( b_global ? 2 : 1, Qt::UserRole, QVariant( -1 ) );
1326 it->setText( b_global ? 2 : 1, qtr( "Unset" ) );
1329 /* We already made an OK once. */
1336 void KeySelectorControl::setTheKey()
1338 if( !table->currentItem() ) return;
1339 table->currentItem()->setText( shortcutValue->getGlobal() ? 2 : 1,
1340 shortcutValue->text() );
1341 table->currentItem()->setData( shortcutValue->getGlobal() ? 2 : 1,
1342 Qt::UserRole, shortcutValue->getValue() );
1345 void KeySelectorControl::doApply()
1347 QTreeWidgetItem *it;
1348 for( int i = 0; i < table->topLevelItemCount() ; i++ )
1350 it = table->topLevelItem(i);
1351 if( it->data( 1, Qt::UserRole ).toInt() >= 0 )
1352 config_PutInt( p_this,
1353 qtu( it->data( 0, Qt::UserRole ).toString() ),
1354 it->data( 1, Qt::UserRole ).toInt() );
1355 if( it->data( 2, Qt::UserRole ).toInt() >= 0 )
1356 config_PutInt( p_this,
1357 qtu( "global-" + it->data( 0, Qt::UserRole ).toString() ),
1358 it->data( 2, Qt::UserRole ).toInt() );
1364 * Class KeyInputDialog
1366 KeyInputDialog::KeyInputDialog( QTreeWidget *_table,
1367 const QString& keyToChange,
1370 QDialog( _parent ), keyValue(0), b_global( _b_global )
1376 setWindowTitle( b_global ? qtr( "Global" ): ""
1377 + qtr( "Hotkey for " ) + keyToChange );
1379 vLayout = new QVBoxLayout( this );
1380 selected = new QLabel( qtr( "Press the new keys for " ) + keyToChange );
1381 vLayout->addWidget( selected , Qt::AlignCenter );
1383 warning = new QLabel;
1385 vLayout->insertWidget( 1, warning );
1387 buttonBox = new QDialogButtonBox;
1388 QPushButton *ok = new QPushButton( qtr("OK") );
1389 QPushButton *cancel = new QPushButton( qtr("Cancel") );
1390 buttonBox->addButton( ok, QDialogButtonBox::AcceptRole );
1391 buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
1392 ok->setDefault( true );
1394 vLayout->addWidget( buttonBox );
1397 CONNECT( buttonBox, accepted(), this, accept() );
1398 CONNECT( buttonBox, rejected(), this, reject() );
1401 void KeyInputDialog::checkForConflicts( int i_vlckey )
1403 QList<QTreeWidgetItem *> conflictList =
1404 table->findItems( VLCKeyToString( i_vlckey ), Qt::MatchExactly,
1407 if( conflictList.size() &&
1408 conflictList[0]->data( b_global ? 2 : 1, Qt::UserRole ).toInt() > 1 )
1409 /* Avoid 0 or -1 that are the "Unset" states */
1411 warning->setText( qtr("Warning: the key is already assigned to \"") +
1412 conflictList[0]->text( 0 ) + "\"" );
1421 void KeyInputDialog::keyPressEvent( QKeyEvent *e )
1423 if( e->key() == Qt::Key_Tab ||
1424 e->key() == Qt::Key_Shift ||
1425 e->key() == Qt::Key_Control ||
1426 e->key() == Qt::Key_Meta ||
1427 e->key() == Qt::Key_Alt ||
1428 e->key() == Qt::Key_AltGr )
1430 int i_vlck = qtEventToVLCKey( e );
1431 selected->setText( qtr( "Key: " ) + VLCKeyToString( i_vlck ) );
1432 checkForConflicts( i_vlck );
1436 void KeyInputDialog::wheelEvent( QWheelEvent *e )
1438 int i_vlck = qtWheelEventToVLCKey( e );
1439 selected->setText( qtr( "Key: " ) + VLCKeyToString( i_vlck ) );
1440 checkForConflicts( i_vlck );
1444 void KeyShortcutEdit::mousePressEvent( QMouseEvent *)