/*****************************************************************************
* preferences_widgets.cpp : Widgets for preferences displays
****************************************************************************
* Copyright (C) 2006-2011 the VideoLAN team
*
* Authors: Clément Stenac <zorglub@videolan.org>
* Antoine Cellerier <dionoea@videolan.org>
* Jean-Baptiste Kempf <jb@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/**
* Todo:
* - Validator for modulelist
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "dialogs/preferences/preferences_widgets.hpp"
#include "widgets/native/searchlineedit.hpp"
#include "util/vlchotkeyconverter.hpp"
#include "util/qt_dirs.hpp"
#include <vlc_intf_strings.h>
#include <vlc_modules.h>
#include <vlc_plugin.h>
#include <QWidget>
#include <QString>
#include <QStringList>
#include <QVariant>
#include <QGridLayout>
#include <QSlider>
#include <QFileDialog>
#include <QGroupBox>
#include <QTreeWidget>
#include <QTreeWidgetItemIterator>
#include <QDialogButtonBox>
#include <QKeyEvent>
#include <QColorDialog>
#include <QAction>
#include <QKeySequence>
#include <QDoubleSpinBox>
#include <QCheckBox>
#include <QComboBox>
#include <QLineEdit>
#include <QSpinBox>
#include <QPushButton>
#include <QFontComboBox>
#include <QMenu>
#include <QGuiApplication>
#include <QClipboard>
#include <QFont>
#include <QToolButton>
#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>"
"<body style=\" font-family:'Sans Serif'; "
"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;\">" +
text + "</p></body></html>";
return formatted;
}
ConfigControl *ConfigControl::createControl( module_config_t *p_item,
QWidget *parent )
{
ConfigControl *p_control = NULL;
switch( p_item->i_type )
{
case CONFIG_ITEM_MODULE:
p_control = new StringListConfigControl( p_item, parent );
break;
case CONFIG_ITEM_MODULE_CAT:
p_control = new ModuleConfigControl( p_item, parent );
break;
case CONFIG_ITEM_MODULE_LIST:
p_control = new ModuleListConfigControl( p_item, parent, false );
break;
case CONFIG_ITEM_MODULE_LIST_CAT:
p_control = new ModuleListConfigControl( p_item, parent, true );
break;
case CONFIG_ITEM_STRING:
if( p_item->list_count )
p_control = new StringListConfigControl( p_item, parent );
else
p_control = new StringConfigControl( p_item, parent );
break;
case CONFIG_ITEM_PASSWORD:
p_control = new PasswordConfigControl( p_item, parent );
break;
case CONFIG_ITEM_RGB:
p_control = new ColorConfigControl( p_item, parent );
break;
case CONFIG_ITEM_INTEGER:
if( p_item->list_count )
p_control = new IntegerListConfigControl( p_item, parent );
else
p_control = new IntegerRangeConfigControl( p_item, parent );
break;
case CONFIG_ITEM_LOADFILE:
case CONFIG_ITEM_SAVEFILE:
p_control = new FileConfigControl( p_item, parent );
break;
case CONFIG_ITEM_DIRECTORY:
p_control = new DirectoryConfigControl( p_item, parent );
break;
case CONFIG_ITEM_FONT:
p_control = new FontConfigControl( p_item, parent );
break;
case CONFIG_ITEM_KEY:
p_control = new KeySelectorControl( parent );
break;
case CONFIG_ITEM_BOOL:
p_control = new BoolConfigControl( p_item, parent );
break;
case CONFIG_ITEM_FLOAT:
p_control = new FloatRangeConfigControl( p_item, parent );
break;
default:
break;
}
return p_control;
}
ConfigControl *ConfigControl::createControl( module_config_t *item,
QWidget *parent,
QGridLayout *l, int line )
{
ConfigControl *control = createControl( item, parent );
if ( control )
control->insertInto( l, line );
return control;
}
ConfigControl *ConfigControl::createControl( module_config_t *item,
QWidget *parent,
QBoxLayout *l, int index )
{
ConfigControl *control = createControl( item, parent );
if ( control )
control->insertInto( l, index );
return control;
}
/*******************************************************
* Simple widgets
*******************************************************/
InterfacePreviewWidget::InterfacePreviewWidget ( QWidget *parent ) : QLabel( parent )
{
setGeometry( 0, 0, 128, 100 );
setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
}
void InterfacePreviewWidget::setNormalPreview( bool b_minimal )
{
setPreview( ( b_minimal ) ? MINIMAL : COMPLETE );
}
void InterfacePreviewWidget::setPreview( enum_style e_style )
{
QString pixmapLocationString;
switch( e_style )
{
default:
case COMPLETE:
pixmapLocationString = ":/prefsmenu/sample_complete.png";
break;
case MINIMAL:
pixmapLocationString = ":/prefsmenu/sample_minimal.png";
break;
case SKINS:
pixmapLocationString = ":/prefsmenu/sample_skins.png";
break;
}
setPixmap( QPixmap( pixmapLocationString ).
scaledToWidth( width(), Qt::SmoothTransformation ) );
update();
}
/**************************************************************************
* String-based controls
*************************************************************************/
void
VStringConfigControl::doApply()
{
config_PutPsz( getName(), qtu( getValue() ) );
}
void VStringConfigControl::storeValue()
{
/* Note, this modifies our local copy of the item only */
free( p_item->value.psz );
p_item->value.psz = strdup( qtu( getValue() ) );
}
/*********** String **************/
StringConfigControl::StringConfigControl( module_config_t *_p_item,
QWidget *_parent ) :
VStringConfigControl( _p_item )
{
label = new QLabel( p_item->psz_text ? qfut(p_item->psz_text) : "", _parent );
text = new QLineEdit( p_item->value.psz ? qfu(p_item->value.psz) : "", _parent );
finish();
}
StringConfigControl::StringConfigControl( module_config_t *_p_item,
QLabel *_label, QLineEdit *_text ) :
VStringConfigControl( _p_item )
{
text = _text;
label = _label;
finish( );
}
void StringConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->setColumnMinimumWidth( 1, 10 );
l->addWidget( text, line, LAST_COLUMN, Qt::AlignRight );
}
void StringConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, text );
}
void StringConfigControl::finish()
{
text->setText( qfu(p_item->value.psz) );
if( p_item->psz_longtext )
{
QString tipText = qfut(p_item->psz_longtext);
text->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( text );
}
void StringConfigControl::changeVisibility( bool visible )
{
text->setVisible( visible );
if ( label ) label->setVisible( visible );
}
QString StringConfigControl::getValue() const
{
return text->text();
}
/********* String / Password **********/
PasswordConfigControl::PasswordConfigControl( module_config_t *_p_item,
QWidget *_parent ) :
StringConfigControl( _p_item, _parent )
{
finish();
}
PasswordConfigControl::PasswordConfigControl( module_config_t *_p_item,
QLabel *_label, QLineEdit *_text ) :
StringConfigControl( _p_item, _label, _text )
{
finish();
}
void PasswordConfigControl::finish()
{
text->setEchoMode( QLineEdit::Password );
}
/*********** File **************/
FileConfigControl::FileConfigControl( module_config_t *_p_item, QWidget *p ) :
VStringConfigControl( _p_item )
{
label = new QLabel( qfut(p_item->psz_text), p );
text = new QLineEdit( qfu(p_item->value.psz), p );
browse = new QPushButton( qtr( "Browse..." ), p );
BUTTONACT( browse, &FileConfigControl::updateField );
finish();
}
FileConfigControl::FileConfigControl( module_config_t *_p_item,
QLabel *_label, QLineEdit *_text,
QPushButton *_button ) :
VStringConfigControl( _p_item )
{
browse = _button;
text = _text;
label = _label;
BUTTONACT( browse, &FileConfigControl::updateField );
finish( );
}
void FileConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->setColumnMinimumWidth( 1, 10 );
QHBoxLayout *textAndButton = new QHBoxLayout();
textAndButton->setContentsMargins(0, 0, 0, 0);
textAndButton->addWidget( text, 2 );
textAndButton->addWidget( browse, 0 );
l->addLayout( textAndButton, line, LAST_COLUMN );
}
void FileConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
QHBoxLayout *textAndButton = new QHBoxLayout();
textAndButton->setContentsMargins(0, 0, 0, 0);
textAndButton->addWidget( text, 2 );
textAndButton->addWidget( browse, 0 );
l->insertLayout( index + 1, textAndButton );
}
void FileConfigControl::updateField()
{
QString file;
if (p_item->i_type == CONFIG_ITEM_SAVEFILE)
file = QFileDialog::getSaveFileName( NULL, qtr( "Save File" ),
QVLCUserDir( VLC_HOME_DIR ) );
else
file = QFileDialog::getOpenFileName( NULL, qtr( "Select File" ),
QVLCUserDir( VLC_HOME_DIR ) );
if( file.isNull() ) return;
text->setText( toNativeSeparators( file ) );
}
void FileConfigControl::finish()
{
text->setText( qfu(p_item->value.psz) );
if( p_item->psz_longtext )
{
QString tipText = qfut(p_item->psz_longtext);
text->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( text );
}
void FileConfigControl::changeVisibility( bool visible )
{
text->setVisible( visible );
browse->setVisible( visible );
if ( label ) label->setVisible( visible );
}
QString FileConfigControl::getValue() const
{
return text->text();
}
/********* String / Directory **********/
DirectoryConfigControl::DirectoryConfigControl( module_config_t *_p_item,
QWidget *p ) :
FileConfigControl( _p_item, p )
{}
DirectoryConfigControl::DirectoryConfigControl( module_config_t *_p_item,
QLabel *_p_label,
QLineEdit *_p_line,
QPushButton *_p_button ) :
FileConfigControl( _p_item, _p_label, _p_line, _p_button)
{}
void DirectoryConfigControl::updateField()
{
QString dir = QFileDialog::getExistingDirectory( NULL,
qfut( I_OP_SEL_DIR ),
text->text().isEmpty() ?
QVLCUserDir( VLC_HOME_DIR ) : text->text(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks );
if( dir.isNull() ) return;
text->setText( toNativeSepNoSlash( std::move(dir) ) );
}
/********* String / Font **********/
FontConfigControl::FontConfigControl( module_config_t *_p_item, QWidget *p ) :
VStringConfigControl( _p_item )
{
label = new QLabel( qfut(p_item->psz_text), p );
font = new QFontComboBox( p );
font->setCurrentFont( QFont( qfu( p_item->value.psz) ) );
if( p_item->psz_longtext )
{
label->setToolTip( formatTooltip( qfut(p_item->psz_longtext) ) );
}
}
FontConfigControl::FontConfigControl( module_config_t *_p_item,
QLabel *_p_label,
QFontComboBox *_p_font) :
VStringConfigControl( _p_item)
{
label = _p_label;
font = _p_font;
font->setCurrentFont( QFont( qfu( p_item->value.psz) ) );
if( p_item->psz_longtext )
{
label->setToolTip( formatTooltip( qfut(p_item->psz_longtext) ) );
}
}
void FontConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->addWidget( font, line, 1, 1, -1 );
}
void FontConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, font );
}
void FontConfigControl::changeVisibility( bool visible )
{
font->setVisible( visible );
if ( label ) label->setVisible( visible );
}
QString FontConfigControl::getValue() const
{
return font->currentFont().family();
}
/********* String / choice list **********/
StringListConfigControl::StringListConfigControl( module_config_t *_p_item,
QWidget *p ) :
VStringConfigControl( _p_item )
{
label = new QLabel( qfut(p_item->psz_text), p );
combo = new QComboBox( p );
combo->setMinimumWidth( MINWIDTH_BOX );
combo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
/* needed to see update from getting choice list where callback used */
module_config_t *p_module_config = config_FindConfig( p_item->psz_name );
finish( p_module_config );
}
StringListConfigControl::StringListConfigControl( module_config_t *_p_item,
QLabel *_label,
QComboBox *_combo ) :
VStringConfigControl( _p_item )
{
combo = _combo;
label = _label;
/* needed to see update from getting choice list where callback used */
module_config_t *p_module_config = config_FindConfig( getName() );
finish( p_module_config );
}
void StringListConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
}
void StringListConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, combo );
}
void StringListConfigControl::comboIndexChanged( int i_index )
{
Q_UNUSED( i_index );
emit changed();
}
void StringListConfigControl::finish(module_config_t *p_module_config )
{
combo->setEditable( false );
connect( combo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &StringListConfigControl::comboIndexChanged );
if(!p_module_config) return;
char **values, **texts;
ssize_t count = config_GetPszChoices( p_item->psz_name, &values, &texts );
for( ssize_t i = 0; i < count && texts; i++ )
{
if( texts[i] == NULL || values[i] == NULL )
continue;
combo->addItem( qfu(texts[i]), QVariant( qfu(values[i])) );
if( !strcmp( p_item->value.psz ? p_item->value.psz : "", values[i] ) )
combo->setCurrentIndex( combo->count() - 1 );
free( texts[i] );
free( values[i] );
}
free( texts );
free( values );
if( p_module_config->psz_longtext )
{
QString tipText = qfut(p_module_config->psz_longtext);
combo->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( combo );
}
void StringListConfigControl::changeVisibility( bool visible )
{
combo->setVisible( visible );
if ( label ) label->setVisible( visible );
}
QString StringListConfigControl::getValue() const
{
return combo->itemData( combo->currentIndex() ).toString();
}
void setfillVLCConfigCombo( const char *configname, QComboBox *combo )
{
module_config_t *p_config = config_FindConfig( configname );
if( p_config == NULL )
return;
if( (p_config->i_type & 0xF0) == CONFIG_ITEM_STRING )
{
char **values, **texts;
ssize_t count = config_GetPszChoices(configname, &values, &texts);
for( ssize_t i = 0; i < count; i++ )
{
combo->addItem( qfut(texts[i]), QVariant(qfu(values[i])) );
if( p_config->value.psz && !strcmp(p_config->value.psz, values[i]) )
combo->setCurrentIndex( i );
free( texts[i] );
free( values[i] );
}
free( texts );
free( values );
}
else
{
int64_t *values;
char **texts;
ssize_t count = config_GetIntChoices(configname, &values, &texts);
for( ssize_t i = 0; i < count; i++ )
{
combo->addItem( qfut(texts[i]), QVariant(qlonglong(values[i])) );
if( p_config->value.i == values[i] )
combo->setCurrentIndex( i );
free( texts[i] );
}
free( texts );
free( values );
}
if( p_config->psz_longtext != NULL )
combo->setToolTip( qfu( p_config->psz_longtext ) );
}
/********* Module **********/
ModuleConfigControl::ModuleConfigControl( module_config_t *_p_item,
QWidget *p ) :
VStringConfigControl( _p_item )
{
label = new QLabel( qfut(p_item->psz_text), p );
combo = new QComboBox( p );
combo->setMinimumWidth( MINWIDTH_BOX );
finish( );
}
ModuleConfigControl::ModuleConfigControl( module_config_t *_p_item,
QLabel *_label, QComboBox *_combo ) :
VStringConfigControl( _p_item )
{
combo = _combo;
label = _label;
finish( );
}
void ModuleConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->addWidget( combo, line, LAST_COLUMN );
}
void ModuleConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, combo );
}
void ModuleConfigControl::finish( )
{
combo->setEditable( false );
/* build a list of available modules */
size_t count;
module_t **p_list = module_list_get( &count );
combo->addItem( qtr("Default") );
for( size_t i = 0; i < count; i++ )
{
module_t *p_parser = p_list[i];
if( !strcmp( module_get_object( p_parser ), "core" ) ) continue;
unsigned confsize;
module_config_t *p_config;
p_config = module_config_get (p_parser, &confsize);
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;
if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
p_cfg->value.i == p_item->min.i )
{
combo->addItem( qfut( module_GetLongName( p_parser )),
QVariant( module_get_object( p_parser ) ) );
if( p_item->value.psz && !strcmp( p_item->value.psz,
module_get_object( p_parser ) ) )
combo->setCurrentIndex( combo->count() - 1 );
break;
}
}
module_config_free (p_config);
}
module_list_free( p_list );
if( p_item->psz_longtext )
{
QString tipText = qfut(p_item->psz_longtext);
combo->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( combo );
}
void ModuleConfigControl::changeVisibility( bool visible )
{
combo->setVisible( visible );
if ( label ) label->setVisible( visible );
}
QString ModuleConfigControl::getValue() const
{
return combo->itemData( combo->currentIndex() ).toString();
}
/********* Module list **********/
ModuleListConfigControl::ModuleListConfigControl( module_config_t *_p_item,
QWidget *p, bool bycat ) :
VStringConfigControl( _p_item )
{
groupBox = NULL;
/* Special Hack */
if( !p_item->psz_text ) return;
groupBox = new QGroupBox( qfut(p_item->psz_text), p );
text = new QLineEdit( p );
QGridLayout *layoutGroupBox = new QGridLayout( groupBox );
finish( bycat );
int boxline = 0;
foreach ( checkBoxListItem *it, modules )
{
layoutGroupBox->addWidget( it->checkBox, boxline / 2, boxline % 2 );
boxline++;
}
layoutGroupBox->addWidget( text, boxline, 0, 1, 2 );
if( p_item->psz_longtext )
text->setToolTip( formatTooltip( qfut( p_item->psz_longtext) ) );
}
void ModuleListConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( groupBox, line, 0, 1, -1 );
}
void ModuleListConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, groupBox );
}
ModuleListConfigControl::~ModuleListConfigControl()
{
qDeleteAll( modules );
modules.clear();
}
void ModuleListConfigControl::checkbox_lists( module_t *p_parser )
{
const char *help = module_get_help( p_parser );
checkbox_lists( qfut( module_GetLongName( p_parser ) ),
help != NULL ? qfut( 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, &QtCheckboxChanged, this, &ModuleListConfigControl::onUpdate );
if( !help.isEmpty() )
cb->setToolTip( formatTooltip( help ) );
cbl->checkBox = cb;
cbl->psz_module = qfu( psz_module );
modules.append( cbl );
if( p_item->value.psz && strstr( p_item->value.psz, psz_module ) )
cbl->checkBox->setChecked( true );
}
void ModuleListConfigControl::finish( bool bycat )
{
/* build a list of available modules */
size_t count;
module_t **p_list = module_list_get( &count );
for( size_t i = 0; i < count; i++ )
{
module_t *p_parser = p_list[i];
if( bycat )
{
if( !strcmp( module_get_object( p_parser ), "core" ) ) continue;
unsigned confsize;
module_config_t *p_config = module_config_get (p_parser, &confsize);
for (size_t i = 0; i < confsize; i++)
{
module_config_t *p_cfg = p_config + i;
/* Hack: required subcategory is stored in i_min */
if( p_cfg->i_type == CONFIG_SUBCATEGORY &&
p_cfg->value.i == p_item->min.i )
{
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(p_parser);
}
}
module_list_free( p_list );
}
QString ModuleListConfigControl::getValue() const
{
assert( text );
return text->text();
}
void ModuleListConfigControl::changeVisibility( bool visible )
{
foreach ( checkBoxListItem *it, modules )
it->checkBox->setVisible( visible );
groupBox->setVisible( visible );
}
void ModuleListConfigControl::onUpdate()
{
text->clear();
bool first = true;
foreach ( checkBoxListItem *it, modules )
{
if( it->checkBox->isChecked() )
{
if( first )
{
text->setText( text->text() + it->psz_module );
first = false;
}
else
{
text->setText( text->text() + ":" + it->psz_module );
}
}
}
}
/**************************************************************************
* Integer-based controls
*************************************************************************/
void
VIntConfigControl::doApply()
{
config_PutInt( getName(), getValue() );
}
void VIntConfigControl::storeValue()
{
/* Note, this modifies our local copy of the item only */
p_item->value.i = getValue();
}
/*********** Integer **************/
IntegerConfigControl::IntegerConfigControl( module_config_t *_p_item,
QWidget *p ) :
VIntConfigControl( _p_item )
{
label = new QLabel( qfut(p_item->psz_text), p );
spin = new QSpinBox( p );
spin->setMinimumWidth( MINWIDTH_BOX );
spin->setAlignment( Qt::AlignRight );
spin->setMaximumWidth( MINWIDTH_BOX );
finish();
}
IntegerConfigControl::IntegerConfigControl( module_config_t *_p_item,
QLabel *_label, QSpinBox *_spin ) :
VIntConfigControl( _p_item )
{
spin = _spin;
label = _label;
finish();
}
void IntegerConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
}
void IntegerConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, spin );
}
void IntegerConfigControl::finish()
{
spin->setMaximum( 2000000000 );
spin->setMinimum( -2000000000 );
spin->setValue( p_item->value.i );
if( p_item->psz_longtext )
{
QString tipText = qfut(p_item->psz_longtext);
spin->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( spin );
}
void IntegerConfigControl::changeVisibility( bool visible )
{
spin->setVisible( visible );
if ( label ) label->setVisible( visible );
}
int IntegerConfigControl::getValue() const
{
return spin->value();
}
/********* Integer range **********/
IntegerRangeConfigControl::IntegerRangeConfigControl( module_config_t *_p_item,
QWidget *p ) :
IntegerConfigControl( _p_item, p )
{
finish();
}
IntegerRangeConfigControl::IntegerRangeConfigControl( module_config_t *_p_item,
QLabel *_label,
QSpinBox *_spin ) :
IntegerConfigControl( _p_item, _label, _spin )
{
finish();
}
void IntegerRangeConfigControl::finish()
{
spin->setMaximum( p_item->max.i > INT_MAX ? INT_MAX : p_item->max.i );
spin->setMinimum( p_item->min.i < INT_MIN ? INT_MIN : p_item->min.i );
}
IntegerRangeSliderConfigControl::IntegerRangeSliderConfigControl(
module_config_t *_p_item,
QLabel *_label, QSlider *_slider ) :
VIntConfigControl( _p_item )
{
slider = _slider;
label = _label;
slider->setMaximum( p_item->max.i > INT_MAX ? INT_MAX : p_item->max.i );
slider->setMinimum( p_item->min.i < INT_MIN ? INT_MIN : p_item->min.i );
slider->setValue( p_item->value.i );
if( p_item->psz_longtext )
{
QString tipText = qfut(p_item->psz_longtext);
slider->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( slider );
}
void IntegerRangeSliderConfigControl::changeVisibility( bool visible )
{
slider->setVisible( visible );
if ( label ) label->setVisible( visible );
}
int IntegerRangeSliderConfigControl::getValue() const
{
return slider->value();
}
/********* Integer / choice list **********/
IntegerListConfigControl::IntegerListConfigControl( module_config_t *_p_item,
QWidget *p ) :
VIntConfigControl( _p_item )
{
label = new QLabel( qfut(p_item->psz_text), p );
combo = new QComboBox( p );
combo->setMinimumWidth( MINWIDTH_BOX );
/* needed to see update from getting choice list where callback used */
module_config_t *p_module_config = config_FindConfig( p_item->psz_name );
finish( p_module_config );
}
IntegerListConfigControl::IntegerListConfigControl( module_config_t *_p_item,
QLabel *_label,
QComboBox *_combo ) :
VIntConfigControl( _p_item )
{
combo = _combo;
label = _label;
/* needed to see update from getting choice list where callback used */
module_config_t *p_module_config = config_FindConfig( getName() );
finish( p_module_config );
}
void IntegerListConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
}
void IntegerListConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, combo );
}
void IntegerListConfigControl::finish( module_config_t *p_module_config )
{
combo->setEditable( false );
if(!p_module_config) return;
int64_t *values;
char **texts;
ssize_t count = config_GetIntChoices( p_module_config->psz_name,
&values, &texts );
for( ssize_t i = 0; i < count; i++ )
{
combo->addItem( qfut(texts[i]), qlonglong(values[i]) );
if( p_module_config->value.i == values[i] )
combo->setCurrentIndex( combo->count() - 1 );
free( texts[i] );
}
free( texts );
free( values );
if( p_item->psz_longtext )
{
QString tipText = qfut(p_item->psz_longtext );
combo->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( combo );
}
void IntegerListConfigControl::changeVisibility( bool visible )
{
combo->setVisible( visible );
if ( label ) label->setVisible( visible );
}
int IntegerListConfigControl::getValue() const
{
return combo->itemData( combo->currentIndex() ).toInt();
}
/*********** Boolean **************/
BoolConfigControl::BoolConfigControl( module_config_t *_p_item, QWidget *p ) :
VIntConfigControl( _p_item )
{
checkbox = new QCheckBox( qfut(p_item->psz_text), p );
finish();
}
BoolConfigControl::BoolConfigControl( module_config_t *_p_item,
QLabel *_label,
QAbstractButton *_checkbox ) :
VIntConfigControl( _p_item )
{
checkbox = _checkbox;
VLC_UNUSED( _label );
finish();
}
void BoolConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( checkbox, line, 0, 1, -1 );
}
void BoolConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, checkbox );
}
void BoolConfigControl::finish()
{
checkbox->setChecked( p_item->value.i );
if( p_item->psz_longtext )
checkbox->setToolTip( formatTooltip(qfut(p_item->psz_longtext)) );
}
void BoolConfigControl::changeVisibility( bool visible )
{
checkbox->setVisible( visible );
}
int BoolConfigControl::getValue() const
{
return checkbox->isChecked();
}
/************* Color *************/
ColorConfigControl::ColorConfigControl( module_config_t *_p_item,
QWidget *p ) :
VIntConfigControl( _p_item )
{
label = new QLabel( p );
color_but = new QToolButton( p );
finish();
}
ColorConfigControl::ColorConfigControl( module_config_t *_p_item,
QLabel *_label,
QAbstractButton *_color ) :
VIntConfigControl( _p_item )
{
label = _label;
color_but = _color;
finish();
}
void ColorConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->addWidget( color_but, line, LAST_COLUMN, Qt::AlignRight );
}
void ColorConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, color_but );
}
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( qfut(p_item->psz_text) );
if( p_item->psz_longtext )
{
label->setToolTip( formatTooltip(qfut(p_item->psz_longtext)) );
color_but->setToolTip( formatTooltip(qfut(p_item->psz_longtext)) );
}
BUTTONACT( color_but, &ColorConfigControl::selectColor );
}
void ColorConfigControl::changeVisibility( bool visible )
{
color_but->setVisible( visible );
if ( label ) label->setVisible( visible );
}
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( getName(), getValue() );
}
void VFloatConfigControl::storeValue()
{
/* Note, this modifies our local copy of the item only */
p_item->value.f = getValue();
}
/*********** Float **************/
FloatConfigControl::FloatConfigControl( module_config_t *_p_item,
QWidget *p ) :
VFloatConfigControl( _p_item )
{
label = new QLabel( qfut(p_item->psz_text), p );
spin = new QDoubleSpinBox( p );
spin->setMinimumWidth( MINWIDTH_BOX );
spin->setMaximumWidth( MINWIDTH_BOX );
spin->setAlignment( Qt::AlignRight );
finish();
}
FloatConfigControl::FloatConfigControl( module_config_t *_p_item,
QLabel *_label,
QDoubleSpinBox *_spin ) :
VFloatConfigControl( _p_item )
{
spin = _spin;
label = _label;
finish();
}
void FloatConfigControl::insertInto( QGridLayout *l, int line )
{
l->addWidget( label, line, 0 );
l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
}
void FloatConfigControl::insertInto( QBoxLayout *l, int index )
{
l->insertWidget( index, label );
l->insertWidget( index + 1, spin );
}
void FloatConfigControl::finish()
{
spin->setMaximum( 2000000000. );
spin->setMinimum( -2000000000. );
spin->setSingleStep( 0.1 );
spin->setValue( (double)p_item->value.f );
if( p_item->psz_longtext )
{
QString tipText = qfut(p_item->psz_longtext);
spin->setToolTip( formatTooltip(tipText) );
if( label )
label->setToolTip( formatTooltip(tipText) );
}
if( label )
label->setBuddy( spin );
}
void FloatConfigControl::changeVisibility( bool visible )
{
spin->setVisible( visible );
if ( label ) label->setVisible( visible );
}
float FloatConfigControl::getValue() const
{
return (float)spin->value();
}
/*********** Float with range **************/
FloatRangeConfigControl::FloatRangeConfigControl( module_config_t *_p_item,
QWidget *p ) :
FloatConfigControl( _p_item, p )
{
finish();
}
FloatRangeConfigControl::FloatRangeConfigControl( module_config_t *_p_item,
QLabel *_label,
QDoubleSpinBox *_spin ) :
FloatConfigControl( _p_item, _label, _spin )
{
finish();
}
void FloatRangeConfigControl::finish()
{
spin->setMaximum( (double)p_item->max.f );
spin->setMinimum( (double)p_item->min.f );
}
/**********************************************************************
* Key selector widget
**********************************************************************/
KeySelectorControl::KeySelectorControl( QWidget *p ) : ConfigControl( nullptr )
{
label = new QLabel( qtr( "Action hotkey mappings." ), p );
label->setWordWrap( true );
searchLabel = new QLabel( qtr( "Search" ), p );
actionSearch = new SearchLineEdit();
searchOptionLabel = new QLabel( qtr("in") );
searchOption = new QComboBox();
searchOption->addItem( qtr("Any field"), ANY_COL );
searchOption->addItem( qtr("Actions"), ACTION_COL );
searchOption->addItem( qtr("Hotkeys"), HOTKEY_COL );
searchOption->addItem( qtr("Global Hotkeys"), GLOBAL_HOTKEY_COL );
table = new QTreeWidget( p );
table->setColumnCount( ANY_COL );
table->headerItem()->setText( ACTION_COL, qtr( "Action" ) );
table->headerItem()->setText( HOTKEY_COL, qtr( "Hotkey" ) );
table->headerItem()->setToolTip( HOTKEY_COL, qtr( "Application level hotkey" ) );
table->headerItem()->setText( GLOBAL_HOTKEY_COL, qtr( "Global" ) );
table->headerItem()->setToolTip( GLOBAL_HOTKEY_COL, qtr( "Desktop level hotkey" ) );
table->setAlternatingRowColors( true );
table->setSelectionBehavior( QAbstractItemView::SelectItems );
table->setStyleSheet( "QTreeView::item { padding: 5px 0; }" );
table->installEventFilter( this );
/* Find the top most widget */
QWidget *parent, *rootWidget = p;
while( (parent = rootWidget->parentWidget()) != NULL )
rootWidget = parent;
buildAppHotkeysList( rootWidget );
finish();
connect( actionSearch, &SearchLineEdit::textChanged, this, &KeySelectorControl::filter );
connect( searchOption, QOverload<int>::of(&QComboBox::activated),
this, &KeySelectorControl::filter );
}
void KeySelectorControl::insertInto( QGridLayout *l, int line )
{
QGridLayout *gLayout = new QGridLayout();
gLayout->addWidget( label, 0, 0, 1, 4 );
gLayout->addWidget( searchLabel, 1, 0, 1, 1 );
gLayout->addWidget( actionSearch, 1, 1, 1, 1 );
gLayout->addWidget( searchOptionLabel, 1, 2, 1, 1 );
gLayout->addWidget( searchOption, 1, 3, 1, 1 );
gLayout->addWidget( table, 2, 0, 1, 4 );
l->addLayout( gLayout, line, 0, 1, -1 );
}
void KeySelectorControl::buildAppHotkeysList( QWidget *rootWidget )
{
QList<QAction *> actionsList = rootWidget->findChildren<QAction *>();
foreach( const QAction *action, actionsList )
{
const QList<QKeySequence> shortcuts = action->shortcuts();
foreach( const QKeySequence &keySequence, shortcuts )
existingkeys << keySequence.toString();
}
}
void KeySelectorControl::finish()
{
/* Get the main Module */
module_t *p_main = module_get_main();
assert( p_main );
/* Access to the module_config_t */
unsigned confsize;
module_config_t *p_config;
p_config = module_config_get (p_main, &confsize);
QList<module_config_t *> global_keys;
global_keys.reserve( 112 );
for (size_t i = 0; i < confsize; i++)
{
module_config_t *p_config_item = p_config + i;
if( p_config_item->i_type != CONFIG_ITEM_KEY )
continue;
/* Capture global key items to fill in afterwards */
if( strncmp( p_config_item->psz_name, "global-", 7 ) == 0 )
{
global_keys.append( p_config_item );
continue;
}
KeyTableItem *treeItem = new KeyTableItem();
treeItem->normal.config_name = p_config_item->psz_name;
treeItem->normal.default_keys = qfu( p_config_item->orig.psz );
treeItem->global.config_name = nullptr;
treeItem->global.default_keys = qfu( "" );
treeItem->setText( ACTION_COL, qfut( p_config_item->psz_text ) );
if (p_config_item->psz_longtext)
treeItem->setToolTip( ACTION_COL, qfut(p_config_item->psz_longtext) );
treeItem->set_keys( p_config_item->value.psz, HOTKEY_COL );
treeItem->setToolTip( HOTKEY_COL, qtr("Double click to change.\nDelete key to remove.") );
treeItem->setToolTip( GLOBAL_HOTKEY_COL, qtr("Double click to change.\nDelete key to remove.") );
table->addTopLevelItem( treeItem );
}
for (int i = 0; i < global_keys.count(); i++)
{
for (QTreeWidgetItemIterator iter(table); *iter; ++iter)
{
KeyTableItem *item = static_cast<KeyTableItem *>( *iter );
if( strcmp( item->normal.config_name, global_keys[i]->psz_name + 7 ) == 0 )
{
item->global.config_name = global_keys[i]->psz_name;
item->global.default_keys = qfu( global_keys[i]->orig.psz );
item->set_keys( global_keys[i]->value.psz, GLOBAL_HOTKEY_COL );
break;
}
}
}
module_config_free (p_config);
table->resizeColumnToContents( ACTION_COL );
table->resizeColumnToContents( HOTKEY_COL );
table->setUniformRowHeights( true );
connect( table, &QTreeWidget::itemActivated,
this, QOverload<QTreeWidgetItem *, int>::of(&KeySelectorControl::selectKey) );
}
void KeySelectorControl::changeVisibility( bool visible )
{
table->setVisible( visible );
if ( label ) label->setVisible( visible );
}
void KeySelectorControl::filter()
{
const QString &qs_search = actionSearch->text();
int i_column = searchOption->itemData( searchOption->currentIndex() ).toInt();
int i_column_count = 1;
if( i_column == ANY_COL )
{
i_column = 0; // ACTION_COL
i_column_count = ANY_COL;
}
for (QTreeWidgetItemIterator iter(table); *iter; ++iter)
{
QTreeWidgetItem *item = *iter;
bool found = false;
for( int idx = i_column; idx < (i_column + i_column_count); idx++ )
{
if( item->text( idx ).contains( qs_search, Qt::CaseInsensitive ) )
{
found = true;
break;
}
}
item->setHidden( !found );
}
}
void KeySelectorControl::selectKey( QTreeWidgetItem *item, int column )
{
selectKey( static_cast<KeyTableItem *>( item ), (enum ColumnIndex) column );
}
void KeySelectorControl::selectKey( KeyTableItem *item, enum ColumnIndex column )
{
/* This happens when triggered by ClickEater */
if( item == NULL )
item = static_cast<KeyTableItem *>( table->currentItem() );
/* This can happen when nothing is selected on the treeView
and the shortcutValue is clicked */
if( !item ) return;
/* If clicked on the first column, assuming user wants the normal hotkey */
if( column == ACTION_COL ) column = HOTKEY_COL;
/* Launch a small dialog to ask for a new key */
KeyInputDialog *d = new KeyInputDialog( table, item, column );
d->setExistingkeysSet( &existingkeys );
d->exec();
if( d->result() == QDialog::Accepted )
{
/* In case of conflict, reset other keys*/
if( d->conflicts )
reassign_key( item, d->vlckey, column );
else
item->set_keys( d->vlckey, column );
}
else if( d->result() == 2 )
unset( item, column );
delete d;
}
void KeySelectorControl::doApply()
{
for (QTreeWidgetItemIterator iter(table); *iter; ++iter)
{
KeyTableItem *item = static_cast<KeyTableItem *>( *iter );
config_PutPsz( item->normal.config_name, qtu( item->normal.keys ) );
config_PutPsz( item->global.config_name, qtu( item->global.keys ) );
}
}
bool KeySelectorControl::eventFilter( QObject *obj, QEvent *e )
{
#ifndef QT_NO_CONTEXTMENU
if( obj == table && e->type() == QEvent::ContextMenu )
{
tableContextMenuEvent( table, static_cast<QContextMenuEvent*>(e) );
return true;
}
#endif
if( obj != table || e->type() != QEvent::KeyPress )
return ConfigControl::eventFilter(obj, e);
switch( static_cast<QKeyEvent*>(e)->key() )
{
case Qt::Key_Escape:
table->clearFocus();
return true;
case Qt::Key_Return:
case Qt::Key_Enter:
selectKey( table->currentItem(), table->currentColumn() );
return true;
case Qt::Key_Delete:
if( table->currentColumn() != ACTION_COL )
unset( table->currentItem(), table->currentColumn() );
return true;
default:
return false;
}
}
#ifndef QT_NO_CONTEXTMENU
void KeySelectorControl::tableContextMenuEvent( QWidget *widget, QContextMenuEvent *event )
{
KeyTableItem *item = static_cast<KeyTableItem *>( this->table->currentItem() );
if( !item || item->isHidden() )
return;
/* Avoid menu from right-click on empty space after last item */
if( event->reason() == QContextMenuEvent::Mouse &&
!this->table->itemAt( this->table->viewport()->mapFromGlobal( event->globalPos() ) ) )
return;
enum ColumnIndex column = (enum ColumnIndex) this->table->currentColumn();
bool empty;
bool matches_default;
switch ( column )
{
case ACTION_COL:
empty = (item->normal.keys.isEmpty() && item->global.keys.isEmpty());
matches_default = (item->normal.matches_default && item->global.matches_default);
break;
case HOTKEY_COL:
empty = item->normal.keys.isEmpty();
matches_default = item->normal.matches_default;
break;
case GLOBAL_HOTKEY_COL:
empty = item->global.keys.isEmpty();
matches_default = item->global.matches_default;
break;
default:
unreachable();
}
assert(widget);
QMenu *menu = new QMenu(widget);
menu->setAttribute(Qt::WA_DeleteOnClose);
QAction *modify = new QAction( qtr( "&Modify" ), this->table );
connect( modify, &QAction::triggered, [=]() { this->selectKey( item, column ); } );
menu->addAction( modify );
if( column != ACTION_COL )
{
QAction *copy = new QAction( qtr( "&Copy value" ), this->table );
if( empty )
copy->setEnabled( false );
else
connect( copy, &QAction::triggered, [=]() {
this->copy_value( item, column );
} );
menu->addAction( copy );
}
QAction *unset = new QAction( qtr( "&Unset" ), this->table );
if( empty )
unset->setEnabled( false );
else
connect( unset, &QAction::triggered, [=]() { this->unset( item, column ); } );
menu->addAction( unset );
QAction *reset = new QAction( qtr( "&Reset" ), this->table );
if( matches_default )
reset->setEnabled( false );
else
connect( reset, &QAction::triggered, [=]() {
if( column != ACTION_COL )
this->reset( item, column );
else
{
this->reset( item, HOTKEY_COL );
this->reset( item, GLOBAL_HOTKEY_COL );
}
} );
menu->addAction( reset );
QString reset_all_label = (column == ACTION_COL) ? qtr( "Reset &all" )
: qtr( "Reset &all (column)" );
QAction *reset_all = new QAction( reset_all_label, this->table );
connect( reset_all, &QAction::triggered, [=]() { this->reset_all( column ); } );
menu->addAction( reset_all );
menu->popup( event->globalPos() );
}
#endif // QT_NO_CONTEXTMENU
void KeySelectorControl::unset( QTreeWidgetItem *item, int column )
{
unset( static_cast<KeyTableItem*>( item ), (enum ColumnIndex) column );
}
void KeySelectorControl::unset( KeyTableItem *item,
enum KeySelectorControl::ColumnIndex column )
{
if( item == nullptr )
return;
if( column == ACTION_COL )
column = HOTKEY_COL;
item->set_keys( nullptr, column );
}
void KeySelectorControl::reset( KeyTableItem *item,
enum KeySelectorControl::ColumnIndex column )
{
QString item_default = item->get_default_keys( column );
KeyTableItem *conflict = find_conflict( table, item_default, item, column );
if( conflict != nullptr )
{
KeyConflictDialog *dialog = new KeyConflictDialog( this->table, conflict, column );
dialog->exec();
if( dialog->result() == QDialog::Accepted )
reassign_key( item, item_default, column );
delete dialog;
}
else
item->set_keys( item_default, column );
}
void KeySelectorControl::reset_all( enum KeySelectorControl::ColumnIndex column )
{
for (QTreeWidgetItemIterator iter(table); *iter; ++iter)
{
KeyTableItem *item = static_cast<KeyTableItem *>( *iter );
if( column != GLOBAL_HOTKEY_COL )
item->set_keys( item->get_default_keys( HOTKEY_COL ), HOTKEY_COL );
if( column != HOTKEY_COL )
item->set_keys( item->get_default_keys( GLOBAL_HOTKEY_COL ), GLOBAL_HOTKEY_COL );
}
}
void KeySelectorControl::reassign_key( KeyTableItem *item, const QString &key,
enum KeySelectorControl::ColumnIndex column )
{
for (QTreeWidgetItemIterator iter(table); *iter; ++iter)
{
KeyTableItem *iter_item = static_cast<KeyTableItem *>( *iter );
if( iter_item != item )
iter_item->remove_key( key, column );
}
item->set_keys( key, column );
}
void KeySelectorControl::copy_value( KeyTableItem *item,
enum KeySelectorControl::ColumnIndex column )
{
QClipboard *clipboard = QGuiApplication::clipboard();
clipboard->setText( item->get_keys( column ) );
}
KeyTableItem * KeySelectorControl::find_conflict( QTreeWidget *table, QString key,
KeyTableItem *ignore_item,
enum KeySelectorControl::ColumnIndex column )
{
if( key.isEmpty() )
return nullptr;
for (QTreeWidgetItemIterator iter(table); *iter; ++iter)
{
KeyTableItem *item = static_cast<KeyTableItem *>( *iter );
if( item == ignore_item )
continue;
if( item->contains_key( key, column ) )
return item;
}
return nullptr;
}
const QString &KeyTableItem::get_keys( enum KeySelectorControl::ColumnIndex column )
{
if( column == KeySelectorControl::GLOBAL_HOTKEY_COL )
return global.keys;
return normal.keys;
}
QString KeyTableItem::get_default_keys( enum KeySelectorControl::ColumnIndex column )
{
if( column == KeySelectorControl::GLOBAL_HOTKEY_COL )
return global.default_keys;
return normal.default_keys;
}
void KeyTableItem::set_keys( QString keys, enum KeySelectorControl::ColumnIndex column )
{
bool matches_default;
if( column == KeySelectorControl::GLOBAL_HOTKEY_COL )
{
global.keys = keys;
matches_default = global.matches_default = ( keys == global.default_keys );
}
else
{
normal.keys = keys;
matches_default = normal.matches_default = ( keys == normal.default_keys );
}
setText( column, keys.replace( "\t", ", " ) );
QFont font = this->font( KeySelectorControl::ACTION_COL );
font.setWeight( matches_default ? QFont::Weight::Normal : QFont::Weight::Bold );
setFont( column, font );
matches_default = (normal.matches_default && global.matches_default);
font.setWeight( matches_default ? QFont::Weight::Normal : QFont::Weight::Bold );
setFont( KeySelectorControl::ACTION_COL, font );
}
bool KeyTableItem::contains_key( const QString &key, enum KeySelectorControl::ColumnIndex column )
{
return get_keys( column ).split( "\t" ).contains( key );
}
void KeyTableItem::remove_key( const QString &key, enum KeySelectorControl::ColumnIndex column )
{
QStringList keys_list = get_keys( column ).split( "\t" );
if( keys_list.removeAll( key ) )
set_keys( keys_list.join( "\t" ), column );
}
/**
* Class KeyInputDialog
**/
KeyInputDialog::KeyInputDialog( QTreeWidget *table_,
KeyTableItem * keyItem_,
enum KeySelectorControl::ColumnIndex column_ ) :
QDialog( table_ ), table( table_ ),
keyItem( keyItem_ ), column( column_ )
{
setModal( true );
conflicts = false;
existingkeys = NULL;
wheelConverter = new WheelToVLCConverter(this);
connect(wheelConverter, &WheelToVLCConverter::vlcWheelKey, this, [this](int i_vlck){
vlckey = VLCKeyToString( i_vlck, false );
vlckey_tr = VLCKeyToString( i_vlck, true );
selected->setText( qtr( "Key: <b>%1</b>" ).arg( vlckey_tr ) );
checkForConflicts( QString() );
});
bool global = ( column == KeySelectorControl::GLOBAL_HOTKEY_COL );
setWindowTitle( global ? qtr( "Global Hotkey change" )
: qtr( "Hotkey change" ) );
setWindowRole( "vlc-key-input" );
QVBoxLayout *vLayout = new QVBoxLayout( this );
selected = new QLabel( qtr( "Press the new key or combination for <b>%1</b>" )
.arg( keyItem->text( KeySelectorControl::ACTION_COL ) ) );
vLayout->addWidget( selected , Qt::AlignCenter );
warning = new QLabel;
warning->hide();
vLayout->insertWidget( 1, warning );
QDialogButtonBox *buttonBox = new QDialogButtonBox;
ok = new QPushButton( qtr("Assign") );
QPushButton *cancel = new QPushButton( qtr("Cancel") );
unset = new QPushButton( qtr("Unset") );
buttonBox->addButton( ok, QDialogButtonBox::AcceptRole );
buttonBox->addButton( unset, QDialogButtonBox::ActionRole );
buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
ok->setDefault( true );
ok->setFocusPolicy(Qt::NoFocus);
unset->setFocusPolicy(Qt::NoFocus);
cancel->setFocusPolicy(Qt::NoFocus);
vLayout->addWidget( buttonBox );
ok->hide();
connect( buttonBox, &QDialogButtonBox::accepted, this, &KeyInputDialog::accept );
connect( buttonBox, &QDialogButtonBox::rejected, this, &KeyInputDialog::reject );
BUTTONACT( unset, &KeyInputDialog::unsetAction );
}
void KeyInputDialog::setExistingkeysSet( const QSet<QString> *keyset )
{
existingkeys = keyset;
}
void KeyInputDialog::checkForConflicts( const QString &sequence )
{
conflicts = false;
if ( vlckey == "" )
{
accept();
return;
}
KeyTableItem *conflict = KeySelectorControl::find_conflict( table, vlckey, keyItem, column );
if( conflict != nullptr )
{
warning->setText(
qtr("Warning: this key or combination is already assigned to \"<b>%1</b>\"")
.arg( conflict->text( KeySelectorControl::ACTION_COL ) ) );
warning->show();
ok->show();
unset->hide();
conflicts = true;
return;
}
if( existingkeys && !sequence.isEmpty()
&& existingkeys->contains( sequence ) )
{
warning->setText(
qtr( "Warning: <b>%1</b> is already an application menu shortcut" )
.arg( sequence )
);
warning->show();
ok->show();
unset->hide();
conflicts = true;
}
else accept();
}
void KeyInputDialog::keyPressEvent( QKeyEvent *e )
{
if( e->key() == Qt::Key_Tab ||
e->key() == Qt::Key_Shift ||
e->key() == Qt::Key_Control ||
e->key() == Qt::Key_Meta ||
e->key() == Qt::Key_Alt ||
e->key() == Qt::Key_AltGr )
return;
int i_vlck = qtEventToVLCKey( e );
QKeySequence sequence( e->key() | e->modifiers() );
vlckey = VLCKeyToString( i_vlck, false );
vlckey_tr = VLCKeyToString( i_vlck, true );
selected->setText( qtr( "Key or combination: <b>%1</b>" ).arg( vlckey_tr ) );
checkForConflicts( sequence.toString() );
}
void KeyInputDialog::wheelEvent( QWheelEvent *e )
{
wheelConverter->wheelEvent(e);
}
void KeyInputDialog::unsetAction() { done( 2 ); }
KeyConflictDialog::KeyConflictDialog( QTreeWidget *table, KeyTableItem * item,
enum KeySelectorControl::ColumnIndex column ) :
QDialog( table )
{
setModal( true );
bool global = ( column == KeySelectorControl::GLOBAL_HOTKEY_COL );
setWindowTitle( global ? qtr( "Global Hotkey assignment conflict" )
: qtr( "Hotkey assignment conflict" ) );
setWindowRole( "vlc-key-conflict" );
QVBoxLayout *vLayout = new QVBoxLayout( this );
QLabel *warning = new QLabel;
warning->setText(
qtr("Warning: this key or combination is already assigned to \"<b>%1</b>\"")
.arg( item->text( KeySelectorControl::ACTION_COL ) ) );
vLayout->addWidget( warning , Qt::AlignCenter );
QDialogButtonBox *buttonBox = new QDialogButtonBox;
QPushButton *force = new QPushButton( qtr("Assign") );
QPushButton *cancel = new QPushButton( qtr("Cancel") );
buttonBox->addButton( force, QDialogButtonBox::AcceptRole );
buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
force->setDefault( true );
vLayout->addWidget( buttonBox );
connect( buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
connect( buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
}
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|