]> git.sesse.net Git - vlc/blobdiff - modules/gui/qt4/components/preferences_widgets.cpp
Qt: ConfigControl: unify and fix visibility changes.
[vlc] / modules / gui / qt4 / components / preferences_widgets.cpp
index 84cc19a35fce7c509bc70957737ee312f872d863..32e6bdd5d5de8d4f44f198db491de8569714a3b3 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * preferences_widgets.cpp : Widgets for preferences displays
  ****************************************************************************
- * Copyright (C) 2006-2007 the VideoLAN team
+ * Copyright (C) 2006-2011 the VideoLAN team
  * $Id$
  *
  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
 
 /**
  * Todo:
- *  - Finish implementation (see WX, there might be missing a
- *    i_action handler for IntegerLists, but I don't see any module using it...
- *  - Improvements over WX
- *      - Validator for modulelist
+ *  - i_action handler for IntegerLists, but I don't see any module using it...
+ *  - Validator for modulelist
  */
 #ifdef HAVE_CONFIG_H
 # include "config.h"
@@ -41,6 +39,7 @@
 #include <vlc_keys.h>
 #include <vlc_intf_strings.h>
 #include <vlc_modules.h>
+#include <vlc_plugin.h>
 
 #include <QString>
 #include <QVariant>
 #include <QSignalMapper>
 #include <QDialogButtonBox>
 #include <QKeyEvent>
+#include <QColorDialog>
 
 #define MINWIDTH_BOX 90
 #define LAST_COLUMN 10
 
 QString formatTooltip(const QString & tooltip)
 {
+    QString text = tooltip;
+    text.replace("\n", "<br/>");
+
     QString formatted =
     "<html><head><meta name=\"qrichtext\" content=\"1\" />"
     "<style type=\"text/css\"> p, li { white-space: pre-wrap; } </style></head>"
@@ -65,23 +68,14 @@ QString formatTooltip(const QString & tooltip)
     "font-style:normal; text-decoration:none;\">"
     "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; "
     "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" +
-    tooltip +
-    "</p></body></html>";
+    text + "</p></body></html>";
     return formatted;
 }
 
-ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
-                                             module_config_t *p_item,
-                                             QWidget *parent )
-{
-    int i = 0;
-    return createControl( p_this, p_item, parent, NULL, i );
-}
-
 ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
                                              module_config_t *p_item,
                                              QWidget *parent,
-                                             QGridLayout *l, int &line )
+                                             QGridLayout *l, int line )
 {
     ConfigControl *p_control = NULL;
 
@@ -109,7 +103,7 @@ ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
                                                  l, line, false );
         else
             p_control = new StringListConfigControl( p_this, p_item,
-                                            parent, false, l, line );
+                                            parent, l, line );
         break;
     case CONFIG_ITEM_PASSWORD:
         if( !p_item->i_list )
@@ -117,7 +111,10 @@ ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
                                                  l, line, true );
         else
             p_control = new StringListConfigControl( p_this, p_item,
-                                            parent, true, l, line );
+                                            parent, l, line );
+        break;
+    case CONFIG_ITEM_RGB:
+        p_control = new ColorConfigControl( p_this, p_item, parent, l, line );
         break;
     case CONFIG_ITEM_INTEGER:
         if( p_item->i_list )
@@ -162,43 +159,6 @@ ConfigControl *ConfigControl::createControl( vlc_object_t *p_this,
     return p_control;
 }
 
-void ConfigControl::doApply( intf_thread_t *p_intf )
-{
-    switch( getType() )
-    {
-        case CONFIG_ITEM_INTEGER:
-        case CONFIG_ITEM_BOOL:
-        {
-            VIntConfigControl *vicc = qobject_cast<VIntConfigControl *>(this);
-            assert( vicc );
-            config_PutInt( p_intf, vicc->getName(), vicc->getValue() );
-            break;
-        }
-        case CONFIG_ITEM_FLOAT:
-        {
-            VFloatConfigControl *vfcc =
-                                    qobject_cast<VFloatConfigControl *>(this);
-            assert( vfcc );
-            config_PutFloat( p_intf, vfcc->getName(), vfcc->getValue() );
-            break;
-        }
-        case CONFIG_ITEM_STRING:
-        {
-            VStringConfigControl *vscc =
-                            qobject_cast<VStringConfigControl *>(this);
-            assert( vscc );
-            config_PutPsz( p_intf, vscc->getName(), qtu( vscc->getValue() ) );
-            break;
-        }
-        case CONFIG_ITEM_KEY:
-        {
-            KeySelectorControl *ksc = qobject_cast<KeySelectorControl *>(this);
-            assert( ksc );
-            ksc->doApply();
-        }
-    }
-}
-
 /*******************************************************
  * Simple widgets
  *******************************************************/
@@ -210,7 +170,7 @@ InterfacePreviewWidget::InterfacePreviewWidget ( QWidget *parent ) : QLabel( par
 
 void InterfacePreviewWidget::setNormalPreview( bool b_minimal )
 {
-    setPreview( ( b_minimal )?MINIMAL:COMPLETE );
+    setPreview( ( b_minimal ) ? MINIMAL : COMPLETE );
 }
 
 void InterfacePreviewWidget::setPreview( enum_style e_style )
@@ -236,16 +196,21 @@ void InterfacePreviewWidget::setPreview( enum_style e_style )
 }
 
 
-
 /**************************************************************************
  * String-based controls
  *************************************************************************/
 
+void
+VStringConfigControl::doApply()
+{
+    config_PutPsz( p_this, getName(), qtu( getValue() ) );
+}
+
 /*********** String **************/
 StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
                                           module_config_t *_p_item,
                                           QWidget *_parent, QGridLayout *l,
-                                          int &line, bool pwd ) :
+                                          int line, bool pwd ) :
                            VStringConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -255,6 +220,7 @@ StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
 
     if( !l )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( label, 0 ); layout->insertSpacing( 1, 10 );
         layout->addWidget( text, LAST_COLUMN );
@@ -279,6 +245,8 @@ StringConfigControl::StringConfigControl( vlc_object_t *_p_this,
     finish( );
 }
 
+int VStringConfigControl::getType() const { return CONFIG_ITEM_STRING; }
+
 void StringConfigControl::finish()
 {
     text->setText( qfu(p_item->value.psz) );
@@ -297,7 +265,7 @@ void StringConfigControl::finish()
 FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
                                           module_config_t *_p_item,
                                           QWidget *_parent, QGridLayout *l,
-                                          int &line ) :
+                                          int line ) :
                            VStringConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -314,6 +282,7 @@ FileConfigControl::FileConfigControl( vlc_object_t *_p_this,
 
     if( !l )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( label, 0 );
         layout->insertSpacing( 1, 10 );
@@ -376,7 +345,7 @@ void FileConfigControl::finish()
 /********* String / Directory **********/
 DirectoryConfigControl::DirectoryConfigControl( vlc_object_t *_p_this,
                         module_config_t *_p_item, QWidget *_p_widget,
-                        QGridLayout *_p_layout, int& _int ) :
+                        QGridLayout *_p_layout, int _int ) :
      FileConfigControl( _p_this, _p_item, _p_widget, _p_layout, _int )
 {}
 
@@ -401,7 +370,7 @@ void DirectoryConfigControl::updateField()
 /********* String / Font **********/
 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
                         module_config_t *_p_item, QWidget *_parent,
-                        QGridLayout *_p_layout, int& line) :
+                        QGridLayout *_p_layout, int line) :
      VStringConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -409,6 +378,7 @@ FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
     font->setCurrentFont( QFont( qfu( p_item->value.psz) ) );
     if( !_p_layout )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( label, 0 );
         layout->addWidget( font, 1 );
@@ -419,6 +389,11 @@ FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
         _p_layout->addWidget( label, line, 0 );
         _p_layout->addWidget( font, line, 1, 1, -1 );
     }
+
+    if( p_item->psz_longtext )
+    {
+        label->setToolTip( formatTooltip( qtr(p_item->psz_longtext) ) );
+    }
 }
 
 FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
@@ -429,12 +404,17 @@ FontConfigControl::FontConfigControl( vlc_object_t *_p_this,
     label = _p_label;
     font = _p_font;
     font->setCurrentFont( QFont( qfu( p_item->value.psz) ) );
+
+    if( p_item->psz_longtext )
+    {
+        label->setToolTip( formatTooltip( qtr(p_item->psz_longtext) ) );
+    }
 }
 
 /********* String / choice list **********/
 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
-               module_config_t *_p_item, QWidget *_parent, bool bycat,
-               QGridLayout *l, int &line) :
+               module_config_t *_p_item, QWidget *_parent,
+               QGridLayout *l, int line) :
                VStringConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -444,9 +424,10 @@ StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
 
     module_config_t *p_module_config = config_FindConfig( p_this, p_item->psz_name );
 
-    finish( p_module_config, bycat );
+    finish( p_module_config );
     if( !l )
     {
+        widget = new QWidget( _parent );
         l = new QGridLayout();
         l->addWidget( label, 0, 0 ); l->addWidget( combo, 0, LAST_COLUMN );
         widget->setLayout( l );
@@ -493,23 +474,23 @@ void StringListConfigControl::actionRequested( int i_action )
     if( p_module_config->b_dirty )
     {
         combo->clear();
-        finish( p_module_config, true );
+        finish( p_module_config );
         p_module_config->b_dirty = false;
     }
 }
 StringListConfigControl::StringListConfigControl( vlc_object_t *_p_this,
                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
-                bool bycat ) : VStringConfigControl( _p_this, _p_item )
+                bool ) : VStringConfigControl( _p_this, _p_item )
 {
     combo = _combo;
     label = _label;
 
     module_config_t *p_module_config = config_FindConfig( p_this, getName() );
 
-    finish( p_module_config, bycat );
+    finish( p_module_config );
 }
 
-void StringListConfigControl::finish(module_config_t *p_module_config, bool bycat )
+void StringListConfigControl::finish(module_config_t *p_module_config )
 {
     combo->setEditable( false );
 
@@ -517,17 +498,17 @@ void StringListConfigControl::finish(module_config_t *p_module_config, bool byca
 
     if( p_module_config->pf_update_list )
     {
-       vlc_value_t val;
-       val.psz_string = strdup(p_module_config->value.psz);
+        vlc_value_t val;
+        val.psz_string = strdup(p_module_config->value.psz);
 
-       p_module_config->pf_update_list(p_this, p_item->psz_name, val, val, NULL);
+        p_module_config->pf_update_list(p_this, p_item->psz_name, val, val, NULL);
 
-       // assume in any case that dirty was set to true
-       // because lazy programmes will use the same callback for
-       // this, like the one behind the refresh push button?
-       p_module_config->b_dirty = false;
+        // assume in any case that dirty was set to true
+        // because lazy programmes will use the same callback for
+        // this, like the one behind the refresh push button?
+        p_module_config->b_dirty = false;
 
-       free( val.psz_string );
+        free( val.psz_string );
     }
 
     for( int i_index = 0; i_index < p_module_config->i_list; i_index++ )
@@ -566,13 +547,21 @@ QString StringListConfigControl::getValue() const
 }
 
 void setfillVLCConfigCombo( const char *configname, intf_thread_t *p_intf,
-                        QComboBox *combo )
+                            QComboBox *combo )
 {
     module_config_t *p_config =
                       config_FindConfig( VLC_OBJECT(p_intf), configname );
     if( p_config )
     {
-       if(p_config->pf_update_list)
+        QVariant def;
+        bool string = (p_config->i_type & 0xF0) == CONFIG_ITEM_STRING;
+
+        if( string )
+            def = QVariant( qfu(p_config->value.psz) );
+        else
+            def = QVariant( qlonglong( p_config->value.i ) );
+
+        if(p_config->pf_update_list)
         {
             vlc_value_t val;
             val.i_int = p_config->value.i;
@@ -585,12 +574,15 @@ void setfillVLCConfigCombo( const char *configname, intf_thread_t *p_intf,
 
         for ( int i_index = 0; i_index < p_config->i_list; i_index++ )
         {
-            combo->addItem( qtr(p_config->ppsz_list_text[i_index]),
-                    QVariant( p_config->pi_list[i_index] ) );
-            if( p_config->value.i == p_config->pi_list[i_index] )
-            {
+            QVariant value;
+
+            if( string )
+                value = QVariant( qfu(p_config->ppsz_list[i_index]) );
+            else
+                value =QVariant( p_config->pi_list[i_index] );
+            combo->addItem( qtr(p_config->ppsz_list_text[i_index]), value );
+            if( def == value )
                 combo->setCurrentIndex( i_index );
-            }
         }
 
         if( p_config->psz_longtext )
@@ -601,7 +593,7 @@ void setfillVLCConfigCombo( const char *configname, intf_thread_t *p_intf,
 /********* Module **********/
 ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
                module_config_t *_p_item, QWidget *_parent, bool bycat,
-               QGridLayout *l, int &line) :
+               QGridLayout *l, int line) :
                VStringConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -610,6 +602,7 @@ ModuleConfigControl::ModuleConfigControl( vlc_object_t *_p_this,
     finish( bycat );
     if( !l )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( label ); layout->addWidget( combo, LAST_COLUMN );
         widget->setLayout( layout );
@@ -649,7 +642,7 @@ void ModuleConfigControl::finish( bool bycat )
             module_config_t *p_config;
 
             p_config = module_config_get (p_parser, &confsize);
-             for (size_t i = 0; i < confsize; i++)
+            for (size_t i = 0; i < confsize; i++)
             {
                 /* Hack: required subcategory is stored in i_min */
                 const module_config_t *p_cfg = p_config + i;
@@ -693,10 +686,11 @@ QString ModuleConfigControl::getValue() const
 /********* Module list **********/
 ModuleListConfigControl::ModuleListConfigControl( vlc_object_t *_p_this,
         module_config_t *_p_item, QWidget *_parent, bool bycat,
-        QGridLayout *l, int &line) :
+        QGridLayout *l, int line) :
     VStringConfigControl( _p_this, _p_item, _parent )
 {
     groupBox = NULL;
+
     /* Special Hack */
     if( !p_item->psz_text ) return;
 
@@ -707,15 +701,17 @@ ModuleListConfigControl::ModuleListConfigControl( vlc_object_t *_p_this,
     finish( bycat );
 
     int boxline = 0;
-    for( QVector<checkBoxListItem*>::iterator it = modules.begin();
-            it != modules.end(); ++it )
+    foreach ( checkBoxListItem *it, modules )
     {
-        layoutGroupBox->addWidget( (*it)->checkBox, boxline++, 0 );
+        layoutGroupBox->addWidget( it->checkBox, boxline / 2, boxline % 2 );
+        boxline++;
     }
-    layoutGroupBox->addWidget( text, boxline, 0 );
+
+    layoutGroupBox->addWidget( text, boxline, 0, 1, 2 );
 
     if( !l )
     {
+        widget = new QWidget( _parent );
         QVBoxLayout *layout = new QVBoxLayout();
         layout->addWidget( groupBox, line, 0 );
         widget->setLayout( layout );
@@ -731,32 +727,35 @@ ModuleListConfigControl::ModuleListConfigControl( vlc_object_t *_p_this,
 
 ModuleListConfigControl::~ModuleListConfigControl()
 {
-    for( QVector<checkBoxListItem*>::iterator it = modules.begin();
-            it != modules.end(); ++it )
-    {
-        delete *it;
-    }
+    qDeleteAll( modules );
+    modules.clear();
     delete groupBox;
 }
 
-#define CHECKBOX_LISTS \
-{ \
-       QCheckBox *cb = new QCheckBox( qtr( module_GetLongName( p_parser ) ) );\
-       checkBoxListItem *cbl = new checkBoxListItem; \
-\
-       CONNECT( cb, stateChanged( int ), this, onUpdate() );\
-       const char *help = module_get_help( p_parser ); \
-       if( help != NULL ) \
-           cb->setToolTip( formatTooltip( qtr( help ) ) ); \
-       cbl->checkBox = cb; \
-\
-       cbl->psz_module = strdup( module_get_object( p_parser ) ); \
-       modules.push_back( cbl ); \
-\
-       if( p_item->value.psz && strstr( p_item->value.psz, cbl->psz_module ) ) \
-            cbl->checkBox->setChecked( true ); \
+void ModuleListConfigControl::checkbox_lists( module_t *p_parser )
+{
+    const char *help = module_get_help( p_parser );
+    checkbox_lists( qtr( module_GetLongName( p_parser ) ),
+                    help != NULL ? qtr( help ): "",
+                    module_get_object( p_parser ) );
 }
 
+void ModuleListConfigControl::checkbox_lists( QString label, QString help, const char* psz_module )
+{
+    QCheckBox *cb = new QCheckBox( label );
+    checkBoxListItem *cbl = new checkBoxListItem;
+
+    CONNECT( cb, stateChanged( int ), this, onUpdate() );
+    if( !help.isEmpty() )
+        cb->setToolTip( formatTooltip( help ) );
+    cbl->checkBox = cb;
+
+    cbl->psz_module = strdup( psz_module );
+    modules.append( cbl );
+
+    if( p_item->value.psz && strstr( p_item->value.psz, cbl->psz_module ) )
+        cbl->checkBox->setChecked( true );
+}
 
 void ModuleListConfigControl::finish( bool bycat )
 {
@@ -780,14 +779,29 @@ void ModuleListConfigControl::finish( bool bycat )
                 if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
                         p_cfg->value.i == p_item->min.i )
                 {
-                    CHECKBOX_LISTS;
+                    checkbox_lists( p_parser );
+                }
+
+                /* Parental Advisory HACK:
+                 * Selecting HTTP, RC and Telnet interfaces is difficult now
+                 * since they are just the lua interface module */
+                if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
+                    !strcmp( module_get_object( p_parser ), "lua" ) &&
+                    !strcmp( p_item->psz_name, "extraintf" ) &&
+                    p_cfg->value.i == p_item->min.i )
+                {
+                    checkbox_lists( "Web", "Lua HTTP", "http" );
+                    checkbox_lists( "Telnet", "Lua Telnet", "telnet" );
+#ifndef WIN32
+                    checkbox_lists( "Console", "Lua CLI", "cli" );
+#endif
                 }
             }
             module_config_free (p_config);
         }
         else if( module_provides( p_parser, p_item->psz_type ) )
         {
-            CHECKBOX_LISTS;
+            checkbox_lists(p_parser);
         }
     }
     module_list_free( p_list );
@@ -801,7 +815,6 @@ void ModuleListConfigControl::finish( bool bycat )
         groupBox->setToolTip( formatTooltip(tipText) );
    }
 }
-#undef CHECKBOX_LISTS
 
 QString ModuleListConfigControl::getValue() const
 {
@@ -809,45 +822,31 @@ QString ModuleListConfigControl::getValue() const
     return text->text();
 }
 
-void ModuleListConfigControl::hide()
+void ModuleListConfigControl::changeVisibility( bool b )
 {
-    for( QVector<checkBoxListItem*>::iterator it = modules.begin();
-         it != modules.end(); ++it )
-    {
-        (*it)->checkBox->hide();
-    }
-    groupBox->hide();
+    foreach ( checkBoxListItem *it, modules )
+        it->checkBox->setVisible( b );
+    groupBox->setVisible( b );
+    ConfigControl::changeVisibility( b );
 }
 
-void ModuleListConfigControl::show()
-{
-    for( QVector<checkBoxListItem*>::iterator it = modules.begin();
-         it != modules.end(); ++it )
-    {
-        (*it)->checkBox->show();
-    }
-    groupBox->show();
-}
-
-
 void ModuleListConfigControl::onUpdate()
 {
     text->clear();
     bool first = true;
 
-    for( QVector<checkBoxListItem*>::iterator it = modules.begin();
-         it != modules.end(); ++it )
+    foreach ( checkBoxListItem *it, modules )
     {
-        if( (*it)->checkBox->isChecked() )
+        if( it->checkBox->isChecked() )
         {
             if( first )
             {
-                text->setText( text->text() + (*it)->psz_module );
+                text->setText( text->text() + it->psz_module );
                 first = false;
             }
             else
             {
-                text->setText( text->text() + ":" + (*it)->psz_module );
+                text->setText( text->text() + ":" + it->psz_module );
             }
         }
     }
@@ -857,11 +856,17 @@ void ModuleListConfigControl::onUpdate()
  * Integer-based controls
  *************************************************************************/
 
+void
+VIntConfigControl::doApply()
+{
+    config_PutInt( p_this, getName(), getValue() );
+}
+
 /*********** Integer **************/
 IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
                                             module_config_t *_p_item,
                                             QWidget *_parent, QGridLayout *l,
-                                            int &line ) :
+                                            int line ) :
                            VIntConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -872,6 +877,7 @@ IntegerConfigControl::IntegerConfigControl( vlc_object_t *_p_this,
 
     if( !l )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( label, 0 ); layout->addWidget( spin, LAST_COLUMN );
         widget->setLayout( layout );
@@ -914,11 +920,13 @@ int IntegerConfigControl::getValue() const
     return spin->value();
 }
 
+int VIntConfigControl::getType() const { return CONFIG_ITEM_INTEGER; }
+
 /********* Integer range **********/
 IntegerRangeConfigControl::IntegerRangeConfigControl( vlc_object_t *_p_this,
                                             module_config_t *_p_item,
                                             QWidget *_parent, QGridLayout *l,
-                                            int &line ) :
+                                            int line ) :
             IntegerConfigControl( _p_this, _p_item, _parent, l, line )
 {
     finish();
@@ -968,8 +976,8 @@ int IntegerRangeSliderConfigControl::getValue() const
 
 /********* Integer / choice list **********/
 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
-               module_config_t *_p_item, QWidget *_parent, bool bycat,
-               QGridLayout *l, int &line) :
+               module_config_t *_p_item, QWidget *_parent, bool,
+               QGridLayout *l, int line) :
                VIntConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -978,9 +986,10 @@ IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
 
     module_config_t *p_module_config = config_FindConfig( p_this, p_item->psz_name );
 
-    finish( p_module_config, bycat );
+    finish( p_module_config );
     if( !l )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( label ); layout->addWidget( combo, LAST_COLUMN );
         widget->setLayout( layout );
@@ -1012,17 +1021,17 @@ IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
 }
 IntegerListConfigControl::IntegerListConfigControl( vlc_object_t *_p_this,
                 module_config_t *_p_item, QLabel *_label, QComboBox *_combo,
-                bool bycat ) : VIntConfigControl( _p_this, _p_item )
+                bool ) : VIntConfigControl( _p_this, _p_item )
 {
     combo = _combo;
     label = _label;
 
     module_config_t *p_module_config = config_FindConfig( p_this, getName() );
 
-    finish( p_module_config, bycat );
+    finish( p_module_config );
 }
 
-void IntegerListConfigControl::finish(module_config_t *p_module_config, bool bycat )
+void IntegerListConfigControl::finish(module_config_t *p_module_config )
 {
     combo->setEditable( false );
 
@@ -1076,7 +1085,7 @@ void IntegerListConfigControl::actionRequested( int i_action )
     if( p_module_config->b_dirty )
     {
         combo->clear();
-        finish( p_module_config, true );
+        finish( p_module_config );
         p_module_config->b_dirty = false;
     }
 }
@@ -1090,7 +1099,7 @@ int IntegerListConfigControl::getValue() const
 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
                                       module_config_t *_p_item,
                                       QWidget *_parent, QGridLayout *l,
-                                      int &line ) :
+                                      int line ) :
                     VIntConfigControl( _p_this, _p_item, _parent )
 {
     checkbox = new QCheckBox( qtr(p_item->psz_text) );
@@ -1098,6 +1107,7 @@ BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
 
     if( !l )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( checkbox, 0 );
         widget->setLayout( layout );
@@ -1111,8 +1121,7 @@ BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
 BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
                                       module_config_t *_p_item,
                                       QLabel *_label,
-                                      QAbstractButton *_checkbox,
-                                      bool bycat ) :
+                                      QAbstractButton *_checkbox ) :
                    VIntConfigControl( _p_this, _p_item )
 {
     checkbox = _checkbox;
@@ -1120,6 +1129,8 @@ BoolConfigControl::BoolConfigControl( vlc_object_t *_p_this,
     finish();
 }
 
+int BoolConfigControl::getType() const { return CONFIG_ITEM_BOOL; }
+
 void BoolConfigControl::finish()
 {
     checkbox->setChecked( p_item->value.i );
@@ -1132,15 +1143,93 @@ int BoolConfigControl::getValue() const
     return checkbox->isChecked();
 }
 
+/************* Color *************/
+ColorConfigControl::ColorConfigControl( vlc_object_t *_p_this,
+                                            module_config_t *_p_item,
+                                            QWidget *_parent, QGridLayout *l,
+                                            int line ) :
+                           VIntConfigControl( _p_this, _p_item, _parent )
+{
+    label = new QLabel;
+    color_but = new QToolButton;
+    finish();
+
+    if( !l )
+    {
+        widget = new QWidget( _parent );
+        QHBoxLayout *layout = new QHBoxLayout();
+        layout->addWidget( label, 0 ); layout->addWidget( color_but, LAST_COLUMN );
+        widget->setLayout( layout );
+    }
+    else
+    {
+        l->addWidget( label, line, 0 );
+        l->addWidget( color_but, line, LAST_COLUMN, Qt::AlignRight );
+    }
+}
+
+ColorConfigControl::ColorConfigControl( vlc_object_t *_p_this,
+                                            module_config_t *_p_item,
+                                            QLabel *_label, QAbstractButton *_color ):
+                                      VIntConfigControl( _p_this, _p_item )
+{
+    label = _label;
+    color_but = _color;
+    finish();
+}
+
+void ColorConfigControl::finish()
+{
+    i_color = p_item->value.i;
+
+    color_px = new QPixmap( 34, 20 );
+    color_px->fill( QColor( i_color ) );
+    color_but->setIcon( QIcon( *color_px ) );
+    color_but->setMinimumWidth( 40 );
+
+    label->setText( qtr(p_item->psz_text) );
+    if( p_item->psz_longtext )
+    {
+        label->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
+        color_but->setToolTip( formatTooltip(qtr(p_item->psz_longtext)) );
+    }
+
+    BUTTONACT( color_but, selectColor() );
+}
+
+int ColorConfigControl::getValue() const
+{
+    return i_color;
+}
+
+void ColorConfigControl::selectColor()
+{
+    QColor color = QColorDialog::getColor( QColor( i_color ) );
+    if( color.isValid() )
+    {
+        i_color = (color.red() << 16) + (color.green() << 8) + color.blue();
+
+        color_px->fill( QColor( i_color ) );
+        color_but->setIcon( QIcon( *color_px ) );
+    }
+}
+
+
 /**************************************************************************
  * Float-based controls
  *************************************************************************/
 
+void
+VFloatConfigControl::doApply()
+{
+    config_PutFloat( p_this, getName(), getValue() );
+}
+
 /*********** Float **************/
 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
                                         module_config_t *_p_item,
                                         QWidget *_parent, QGridLayout *l,
-                                        int &line ) :
+                                        int line ) :
                     VFloatConfigControl( _p_this, _p_item, _parent )
 {
     label = new QLabel( qtr(p_item->psz_text) );
@@ -1152,6 +1241,7 @@ FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
 
     if( !l )
     {
+        widget = new QWidget( _parent );
         QHBoxLayout *layout = new QHBoxLayout();
         layout->addWidget( label, 0 ); layout->addWidget( spin, LAST_COLUMN );
         widget->setLayout( layout );
@@ -1163,6 +1253,8 @@ FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
     }
 }
 
+int VFloatConfigControl::getType() const { return CONFIG_ITEM_FLOAT; }
+
 FloatConfigControl::FloatConfigControl( vlc_object_t *_p_this,
                                         module_config_t *_p_item,
                                         QLabel *_label,
@@ -1200,7 +1292,7 @@ float FloatConfigControl::getValue() const
 FloatRangeConfigControl::FloatRangeConfigControl( vlc_object_t *_p_this,
                                         module_config_t *_p_item,
                                         QWidget *_parent, QGridLayout *l,
-                                        int &line ) :
+                                        int line ) :
                 FloatConfigControl( _p_this, _p_item, _parent, l, line )
 {
     finish();
@@ -1228,7 +1320,7 @@ void FloatRangeConfigControl::finish()
 KeySelectorControl::KeySelectorControl( vlc_object_t *_p_this,
                                       module_config_t *_p_item,
                                       QWidget *_parent, QGridLayout *l,
-                                      int &line ) :
+                                      int line ) :
                                 ConfigControl( _p_this, _p_item, _parent )
 
 {
@@ -1236,44 +1328,39 @@ KeySelectorControl::KeySelectorControl( vlc_object_t *_p_this,
     QGridLayout *gLayout = new QGridLayout( keyContainer );
 
     label = new QLabel(
-            qtr( "Select an action to change the associated hotkey") );
+        qtr( "Select or double click an action to change the associated "
+             "hotkey. Use delete key to remove hotkeys") );
 
     QLabel *searchLabel = new QLabel( qtr( "Search" ) );
-    actionSearch = new SearchLineEdit( keyContainer );
+    SearchLineEdit *actionSearch = new SearchLineEdit( keyContainer );
 
     table = new QTreeWidget;
     table->setColumnCount(3);
     table->headerItem()->setText( 0, qtr( "Action" ) );
     table->headerItem()->setText( 1, qtr( "Hotkey" ) );
+    table->headerItem()->setToolTip( 1, qtr( "Application level hotkey" ) );
     table->headerItem()->setText( 2, qtr( "Global" ) );
+    table->headerItem()->setToolTip( 2, qtr( "Desktop level hotkey" ) );
     table->setAlternatingRowColors( true );
     table->setSelectionBehavior( QAbstractItemView::SelectItems );
 
-    shortcutValue = new KeyShortcutEdit;
-    shortcutValue->setReadOnly(true);
+    table->installEventFilter( this );
 
-    QPushButton *clearButton = new QPushButton( qtr( "Clear" ) );
-    QPushButton *setButton = new QPushButton( qtr( "Apply" ) );
-    setButton->setDefault( true );
     finish();
 
     gLayout->addWidget( label, 0, 0, 1, 4 );
     gLayout->addWidget( searchLabel, 1, 0, 1, 2 );
     gLayout->addWidget( actionSearch, 1, 2, 1, 2 );
     gLayout->addWidget( table, 2, 0, 1, 4 );
-    gLayout->addWidget( clearButton, 3, 0, 1, 1 );
-    gLayout->addWidget( shortcutValue, 3, 1, 1, 2 );
-    gLayout->addWidget( setButton, 3, 3, 1, 1 );
 
     l->addWidget( keyContainer, line, 0, 1, -1 );
 
-    CONNECT( clearButton, clicked(), shortcutValue, clear() );
-    CONNECT( clearButton, clicked(), this, setTheKey() );
-    BUTTONACT( setButton, setTheKey() );
     CONNECT( actionSearch, textChanged( const QString& ),
              this, filter( const QString& ) );
 }
 
+int KeySelectorControl::getType() const { return CONFIG_ITEM_KEY; }
+
 void KeySelectorControl::finish()
 {
     if( label && p_item->psz_longtext )
@@ -1291,14 +1378,15 @@ void KeySelectorControl::finish()
 
     p_config = module_config_get (p_main, &confsize);
 
+    QMap<QString, QString> global_keys;
     for (size_t i = 0; i < confsize; i++)
     {
-        module_config_t *p_item = p_config + i;
+        module_config_t *p_config_item = p_config + i;
 
         /* If we are a (non-global) key option not empty */
-        if( (p_item->i_type & CONFIG_ITEM) && p_item->psz_name != NULL
-         && !strncmp( p_item->psz_name , "key-", 4 )
-         && !EMPTY_STR( p_item->psz_text ) )
+        if( CONFIG_ITEM(p_config_item->i_type) && p_config_item->psz_name != NULL
+         && !strncmp( p_config_item->psz_name , "key-", 4 )
+         && !EMPTY_STR( p_config_item->psz_text ) )
         {
             /*
                Each tree item has:
@@ -1307,46 +1395,50 @@ void KeySelectorControl::finish()
                 - KeyValue in String in column 1
              */
             QTreeWidgetItem *treeItem = new QTreeWidgetItem();
-            treeItem->setText( 0, qtr( p_item->psz_text ) );
+            treeItem->setText( 0, qtr( p_config_item->psz_text ) );
             treeItem->setData( 0, Qt::UserRole,
-                               QVariant( qfu( p_item->psz_name ) ) );
+                               QVariant( qfu( p_config_item->psz_name ) ) );
 
-            QString keys = qfu( p_item->value.psz );
+            QString keys = qfu( p_config_item->value.psz );
             treeItem->setText( 1, keys );
+            treeItem->setToolTip( 1, qtr("Double click to change") );
+            treeItem->setToolTip( 2, qtr("Double click to change") );
             treeItem->setData( 1, Qt::UserRole, QVariant( keys ) );
             table->addTopLevelItem( treeItem );
             continue;
         }
 
-        if( (p_item->i_type & CONFIG_ITEM) && p_item->psz_name != NULL
-         && !strncmp( p_item->psz_name , "global-key", 10 )
-         && !EMPTY_STR( p_item->psz_text ) )
+        if( CONFIG_ITEM(p_config_item->i_type) && p_config_item->psz_name != NULL
+         && !strncmp( p_config_item->psz_name , "global-key", 10 )
+         && !EMPTY_STR( p_config_item->psz_text )
+         && !EMPTY_STR( p_config_item->value.psz ) )
         {
-            QList<QTreeWidgetItem *> list =
-                table->findItems( qtr( p_item->psz_text ), Qt::MatchExactly );
-            if( list.count() >= 1 )
-            {
-                QString keys = qfu( p_item->value.psz );
-                list[0]->setText( 2, keys );
-                list[0]->setData( 2, Qt::UserRole, keys );
-            }
-            if( list.count() >= 2 )
-                msg_Dbg( p_this, "This is probably wrong, %s", p_item->psz_text );
+            global_keys.insertMulti( qtr( p_config_item->psz_text ), qfu( p_config_item->value.psz ) );
         }
     }
+
+    QMap<QString, QString>::const_iterator i = global_keys.constBegin();
+    while (i != global_keys.constEnd())
+    {
+        QList<QTreeWidgetItem *> list = table->findItems( i.key(), Qt::MatchExactly|Qt::MatchWrap, 0 );
+        if( list.count() >= 1 )
+        {
+            QString keys = i.value();
+            list[0]->setText( 2, keys );
+            list[0]->setData( 2, Qt::UserRole, keys );
+        }
+        if( list.count() >= 2 )
+            msg_Dbg( p_this, "This is probably wrong, %s", qtu(i.key()) );
+
+        i++;
+    }
+
     module_config_free (p_config);
-    module_release (p_main);
 
     table->resizeColumnToContents( 0 );
 
-    CONNECT( table, itemDoubleClicked( QTreeWidgetItem *, int ),
+    CONNECT( table, itemActivated( QTreeWidgetItem *, int ),
              this, selectKey( QTreeWidgetItem *, int ) );
-    CONNECT( table, itemClicked( QTreeWidgetItem *, int ),
-             this, select( QTreeWidgetItem *, int) );
-    CONNECT( table, itemSelectionChanged(),
-             this, select1Key() );
-
-    CONNECT( shortcutValue, pressed(), this, selectKey() );
 }
 
 void KeySelectorControl::filter( const QString &qs_search )
@@ -1360,20 +1452,6 @@ void KeySelectorControl::filter( const QString &qs_search )
     }
 }
 
-void KeySelectorControl::select( QTreeWidgetItem *keyItem, int column )
-{
-    shortcutValue->setGlobal( column == 2 );
-}
-
-/* Show the key selected from the table in the keySelector */
-void KeySelectorControl::select1Key()
-{
-    QTreeWidgetItem *keyItem = table->currentItem();
-    shortcutValue->setText( keyItem->text( 1 ) );
-    shortcutValue->setValue( keyItem->data( 1, Qt::UserRole ).toString() );
-    shortcutValue->setGlobal( false );
-}
-
 void KeySelectorControl::selectKey( QTreeWidgetItem *keyItem, int column )
 {
     /* This happens when triggered by ClickEater */
@@ -1395,10 +1473,8 @@ void KeySelectorControl::selectKey( QTreeWidgetItem *keyItem, int column )
     if( d->result() == QDialog::Accepted )
     {
         QString newKey = VLCKeyToString( d->keyValue );
-        shortcutValue->setText( newKey );
-        shortcutValue->setValue( newKey );
-        shortcutValue->setGlobal( b_global );
 
+        /* In case of conflict, reset other keys*/
         if( d->conflicts )
         {
             QTreeWidgetItem *it;
@@ -1413,22 +1489,14 @@ void KeySelectorControl::selectKey( QTreeWidgetItem *keyItem, int column )
                     it->setText( 1 + b_global, qtr( "Unset" ) );
                 }
             }
-            /* We already made an OK once. */
-            setTheKey();
         }
+
+        keyItem->setText( column, newKey );
+        keyItem->setData( column, Qt::UserRole, newKey );
     }
     delete d;
 }
 
-void KeySelectorControl::setTheKey()
-{
-    if( !table->currentItem() ) return;
-    table->currentItem()->setText( shortcutValue->getGlobal() ? 2 : 1,
-                                   shortcutValue->text() );
-    table->currentItem()->setData( shortcutValue->getGlobal() ? 2 : 1,
-                                   Qt::UserRole, shortcutValue->getValue() );
-}
-
 void KeySelectorControl::doApply()
 {
     QTreeWidgetItem *it;
@@ -1439,14 +1507,48 @@ void KeySelectorControl::doApply()
             config_PutPsz( p_this,
                            qtu( it->data( 0, Qt::UserRole ).toString() ),
                            qtu( it->data( 1, Qt::UserRole ).toString() ) );
-        if( it->data( 2, Qt::UserRole ).toInt() >= 0 )
+        if( !it->data( 2, Qt::UserRole ).toString().isEmpty() )
+        {
             config_PutPsz( p_this,
                            qtu( "global-" + it->data( 0, Qt::UserRole ).toString() ),
                            qtu( it->data( 2, Qt::UserRole ).toString() ) );
+        }
 
     }
 }
 
+bool KeySelectorControl::eventFilter( QObject *obj, QEvent *e )
+{
+    if( obj != table || e->type() != QEvent::KeyPress )
+        return ConfigControl::eventFilter(obj, e);
+
+    QKeyEvent *keyEv = static_cast<QKeyEvent*>(e);
+    QTreeWidget *aTable = static_cast<QTreeWidget *>(obj);
+    if( keyEv->key() == Qt::Key_Escape )
+    {
+        aTable->clearFocus();
+        return true;
+    }
+    else if( keyEv->key() == Qt::Key_Return ||
+             keyEv->key() == Qt::Key_Enter )
+    {
+        selectKey( aTable->currentItem(), aTable->currentColumn() );
+        return true;
+    }
+    else if( keyEv->key() == Qt::Key_Delete )
+    {
+        if( aTable->currentColumn() != 0 )
+        {
+            aTable->currentItem()->setText( aTable->currentColumn(), NULL );
+            aTable->currentItem()->setData( aTable->currentColumn(), Qt::UserRole, QVariant() );
+        }
+        return true;
+    }
+    else
+        return false;
+}
+
+
 /**
  * Class KeyInputDialog
  **/
@@ -1460,12 +1562,13 @@ KeyInputDialog::KeyInputDialog( QTreeWidget *_table,
     conflicts = false;
 
     table = _table;
-    setWindowTitle( b_global ? qtr( "Global" ): ""
-                    + qtr( "Hotkey for " ) + keyToChange );
+    setWindowTitle( ( b_global ? qtr( "Global" ) + QString(" ") : "" )
+                    + qtr( "Hotkey change" ) );
     setWindowRole( "vlc-key-input" );
 
-    vLayout = new QVBoxLayout( this );
-    selected = new QLabel( qtr( "Press the new keys for " ) + keyToChange );
+    QVBoxLayout *vLayout = new QVBoxLayout( this );
+    selected = new QLabel( qtr( "Press the new key or combination for " )
+                           + QString("<b>%1</b>").arg( keyToChange ) );
     vLayout->addWidget( selected , Qt::AlignCenter );
 
     warning = new QLabel;
@@ -1473,7 +1576,7 @@ KeyInputDialog::KeyInputDialog( QTreeWidget *_table,
     vLayout->insertWidget( 1, warning );
 
     buttonBox = new QDialogButtonBox;
-    QPushButton *ok = new QPushButton( qtr("OK") );
+    QPushButton *ok = new QPushButton( qtr("Assign") );
     QPushButton *cancel = new QPushButton( qtr("Cancel") );
     buttonBox->addButton( ok, QDialogButtonBox::AcceptRole );
     buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
@@ -1488,16 +1591,16 @@ KeyInputDialog::KeyInputDialog( QTreeWidget *_table,
 
 void KeyInputDialog::checkForConflicts( int i_vlckey )
 {
-     QList<QTreeWidgetItem *> conflictList =
-         table->findItems( VLCKeyToString( i_vlckey ), Qt::MatchExactly,
-                           b_global ? 2 : 1 );
+    QList<QTreeWidgetItem *> conflictList =
+        table->findItems( VLCKeyToString( i_vlckey ), Qt::MatchExactly,
+                          b_global ? 2 : 1 );
 
-    if( conflictList.size() &&
-        conflictList[0]->data( b_global ? 2 : 1, Qt::UserRole ).toInt() > 1 )
-        /* Avoid 0 or -1 that are the "Unset" states */
+    if( conflictList.count() &&
+        !conflictList[0]->data( b_global ? 2 : 1, Qt::UserRole ).toString().isEmpty() &&
+         conflictList[0]->data( b_global ? 2 : 1, Qt::UserRole ).toString() != "Unset" )
     {
-        warning->setText( qtr("Warning: the key is already assigned to \"") +
-                          conflictList[0]->text( 0 ) + "\"" );
+        warning->setText( qtr("Warning: this key or combination is already assigned to ") +
+                QString( "\"<b>%1</b>\"" ).arg( conflictList[0]->text( 0 ) ) );
         warning->show();
         buttonBox->show();
 
@@ -1516,7 +1619,8 @@ void KeyInputDialog::keyPressEvent( QKeyEvent *e )
         e->key() == Qt::Key_AltGr )
         return;
     int i_vlck = qtEventToVLCKey( e );
-    selected->setText( qtr( "Key: " ) + VLCKeyToString( i_vlck ) );
+    selected->setText( qtr( "Key or combination: " )
+                + QString("<b>%1</b>").arg( VLCKeyToString( i_vlck ) ) );
     checkForConflicts( i_vlck );
     keyValue = i_vlck;
 }
@@ -1528,9 +1632,3 @@ void KeyInputDialog::wheelEvent( QWheelEvent *e )
     checkForConflicts( i_vlck );
     keyValue = i_vlck;
 }
-
-void KeyShortcutEdit::mousePressEvent( QMouseEvent *)
-{
-    emit pressed();
-}
-