summaryrefslogtreecommitdiffstats
path: root/src/app/xineConfig.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/xineConfig.cpp')
-rw-r--r--src/app/xineConfig.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/app/xineConfig.cpp b/src/app/xineConfig.cpp
new file mode 100644
index 0000000..70ca11a
--- /dev/null
+++ b/src/app/xineConfig.cpp
@@ -0,0 +1,321 @@
+// (C) 2005 Max Howell ([email protected])
+// See COPYING file for licensing information
+
+#include "debug.h"
+#include <kapplication.h> // XineConfigDialog::ctor -> to get the iconloader
+#include <kcombobox.h>
+#include <kiconloader.h> // XineConfigDialog::ctor
+#include <klineedit.h>
+#include <kseparator.h>
+#include <kstdguiitem.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qscrollview.h>
+#include <qspinbox.h>
+#include <qtabwidget.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+#include <xine.h>
+#include "xineConfig.h"
+
+QString i18n(const char *text);
+
+
+KDialogBase *XineConfigDialog::s_instance = 0;
+
+
+namespace Codeine
+{
+ void
+ showXineConfigurationDialog( QWidget *parent, xine_t *xine )
+ {
+ XineConfigDialog d( xine, parent );
+ if( d.exec() == QDialog::Accepted )
+ d.saveSettings();
+ }
+}
+
+
+class TabWidget : public QTabWidget
+{
+public:
+ TabWidget( QWidget *parent ) : QTabWidget( parent ) {}
+
+ virtual QSize sizeHint() const
+ {
+ // Qt gives a stupid default sizeHint for this widget
+ return QSize(
+ reinterpret_cast<QWidget*>(tabBar())->sizeHint().width() + 5,
+ QTabWidget::sizeHint().height() );
+ }
+};
+
+
+///@class XineConfigDialog
+
+XineConfigDialog::XineConfigDialog( xine_t *xine, QWidget *parent )
+ : KDialogBase( parent, "xine_config_dialog",
+ true, //modal
+ i18n("Configure xine"), User1 | Stretch | Ok | Cancel,
+ Ok, //default button
+ false, //draw separator
+ KStdGuiItem::reset() )
+ , m_xine( xine )
+{
+ DEBUG_BLOCK
+
+ s_instance = this;
+ const int METRIC = fontMetrics().width( 'x' );
+ const int METRIC_3B2 = (3*METRIC)/2;
+
+ QVBox *box = new QVBox( this );
+ box->setSpacing( METRIC );
+ setMainWidget( box );
+
+ {
+ QHBox *hbox = new QHBox( box );
+ hbox->setSpacing( METRIC_3B2 );
+ hbox->setMargin( METRIC_3B2 );
+ QPixmap info = kapp->iconLoader()->loadIcon( "messagebox_info", KIcon::NoGroup, KIcon::SizeMedium, KIcon::DefaultState, 0, true );
+ QLabel *label = new QLabel( hbox );
+ label->setPixmap( info );
+ label->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum );
+ label = new QLabel( i18n(
+ "xine's defaults are usually sensible and should not require modification. "
+ "However, full configurability is provided for your pleasure ;-)." ), hbox );
+ label->setAlignment( QLabel::WordBreak | QLabel::AlignVCenter );
+ }
+
+ //FIXME after many hours I have discovered that this
+ // widget somehow sets the minSize of this widget to 0,0
+ // whenever you resize the widget. WTF?
+ TabWidget *tabs = new TabWidget( box );
+
+
+ class XineConfigEntryIterator {
+ xine_t *m_xine;
+ xine_cfg_entry_t m_entry;
+ bool m_valid;
+ public:
+ XineConfigEntryIterator( xine_t *xine ) : m_xine( xine ) { m_valid = xine_config_get_first_entry( m_xine, &m_entry ); }
+ inline XineConfigEntryIterator &operator++() { m_valid = xine_config_get_next_entry( m_xine, &m_entry ); return *this; }
+ inline xine_cfg_entry_t *operator*() { return m_valid ? &m_entry : 0; }
+ };
+
+
+ QGridLayout *grid = 0;
+ QString currentPage;
+ QScrollView *view = 0;
+ parent = 0;
+
+ for( XineConfigEntryIterator it( m_xine ); *it; ++it )
+ {
+ const QString pageName = QString::fromUtf8( (*it)->key ).section( '.', 0, 0 );
+
+ if( (QStringList() << "ui" << "effects" << "subtitles").contains( pageName ) )
+ continue;
+
+ if( pageName != currentPage ) {
+ if( view )
+ //NOTE won't be executed for last tab
+ view->viewport()->setMinimumWidth( grid->sizeHint().width() ); // seems necessary
+
+ QString pageTitle = pageName;
+ pageTitle[0] = pageTitle[0].upper();
+
+ tabs->addTab( view = new QScrollView, pageTitle );
+ view->setResizePolicy( QScrollView::AutoOneFit );
+ view->setHScrollBarMode( QScrollView::AlwaysOff );
+ view->setFrameShape( QFrame::NoFrame );
+ view->addChild( parent = new QWidget( view->viewport() ) );
+
+ QBoxLayout *layout = new QVBoxLayout( parent, /*margin*/METRIC_3B2, /*spacing*/0 );
+
+ parent = new QFrame( parent );
+ static_cast<QFrame*>(parent)->setFrameStyle( QFrame::Panel | QFrame::Raised );
+ static_cast<QFrame*>(parent)->setLineWidth( 2 );
+ grid = new QGridLayout( parent, /*rows*/0, /*cols*/2, /*margin*/20, /*spacing*/int(METRIC*2.5) );
+ grid->setColStretch( 0, 3 );
+ grid->setColStretch( 1, 2 );
+
+ layout->addWidget( parent, 0 );
+ layout->addStretch( 1 );
+
+ currentPage = pageName;
+ }
+
+ m_entrys.append( new XineConfigEntry( parent, grid, *it ) );
+ }
+
+ //finishing touches
+ m_entrys.setAutoDelete( true );
+ enableButton( Ok, false );
+ enableButton( User1, false );
+
+ Q_ASSERT( !isUnsavedSettings() );
+}
+
+void
+XineConfigDialog::slotHelp()
+{
+ /// HACK called when a widget's input value changes
+
+ const bool b = isUnsavedSettings();
+ enableButton( Ok, b );
+ enableButton( User1, b );
+}
+
+void
+XineConfigDialog::slotUser1()
+{
+ for( QPtrListIterator<XineConfigEntry> it( m_entrys ); *it != 0; ++it )
+ (*it)->reset();
+
+ slotHelp();
+}
+
+bool
+XineConfigDialog::isUnsavedSettings() const
+{
+ for( QPtrListIterator<XineConfigEntry> it( m_entrys ); *it != 0; ++it )
+ if( (*it)->isChanged() )
+ return true;
+
+ return false;
+}
+
+#include <qdir.h>
+void
+XineConfigDialog::saveSettings()
+{
+ for( XineConfigEntry *entry = m_entrys.first(); entry; entry = m_entrys.next() )
+ if( entry->isChanged() )
+ entry->save( m_xine );
+
+ xine_config_save( m_xine, QFile::encodeName( QDir::homeDirPath() + "/.xine/config" ) );
+}
+
+
+///@class XineConfigEntry
+
+XineConfigEntry::XineConfigEntry( QWidget *parent, QGridLayout *grid, xine_cfg_entry_t *entry )
+ : m_widget( 0 )
+ , m_key( entry->key )
+ , m_string( entry->str_value )
+ , m_number( entry->num_value )
+{
+ QWidget *&w = m_widget;
+ const char *signal = 0;
+ const int row = grid->numRows();
+
+ QString description_text = QString::fromUtf8( entry->description );
+ description_text[0] = description_text[0].upper();
+
+ switch( entry->type )
+ {
+ case XINE_CONFIG_TYPE_STRING: {
+ w = new KLineEdit( m_string, parent );
+ signal = SIGNAL(textChanged( const QString& ));
+ break;
+ }
+ case XINE_CONFIG_TYPE_ENUM: {
+ w = new KComboBox( parent );
+ for( int i = 0; entry->enum_values[i]; ++i )
+ ((KComboBox*)w)->insertItem( QString::fromUtf8( entry->enum_values[i] ) );
+ ((KComboBox*)w)->setCurrentItem( m_number );
+ signal = SIGNAL(activated( int ));
+ break;
+ }
+ case XINE_CONFIG_TYPE_RANGE:
+ case XINE_CONFIG_TYPE_NUM: {
+ w = new QSpinBox(
+ QMIN( m_number, entry->range_min ), // xine bug, sometimes the min and max ranges
+ QMAX( m_number, entry->range_max ), // are both 0 even though this is bullshit
+ 1, parent );
+ ((QSpinBox*)w)->setValue( m_number );
+ signal = SIGNAL(valueChanged( int ));
+ break;
+ }
+ case XINE_CONFIG_TYPE_BOOL: {
+ w = new QCheckBox( description_text, parent );
+ ((QCheckBox*)w)->setChecked( m_number );
+
+ connect( w, SIGNAL(toggled( bool )), XineConfigDialog::instance(), SLOT(slotHelp()) );
+ QToolTip::add( w, "<qt>" + QString::fromUtf8( entry->help ) );
+ grid->addMultiCellWidget( w, row, row, 0, 1 );
+ return; //no need for a description label
+ }
+ default:
+ ;
+ }
+
+ connect( w, signal, XineConfigDialog::instance(), SLOT(slotHelp()) );
+
+ QLabel *description = new QLabel( description_text + ':', parent );
+ description->setAlignment( QLabel::WordBreak | QLabel::AlignVCenter );
+
+ const QString tip = "<qt>" + QString::fromUtf8( entry->help );
+ QToolTip::add( w, tip );
+ QToolTip::add( description, tip );
+
+// grid->addWidget( description, row, 0, Qt::AlignVCenter );
+ grid->addWidget( w, row, 1, Qt::AlignTop );
+}
+
+bool
+XineConfigEntry::isChanged() const
+{
+ #define _( x ) static_cast<x*>(m_widget)
+
+ switch( classType( m_widget->className() ) ) {
+ case LineEdit: return _(KLineEdit)->text().utf8() != m_string;
+ case ComboBox: return _(KComboBox)->currentItem() != m_number;
+ case SpinBox: return _(QSpinBox)->value() != m_number;
+ case CheckBox: return _(QCheckBox)->isChecked() != m_number;
+ }
+ return false;
+}
+
+void
+XineConfigEntry::reset()
+{
+ // this is because we only get called by the XineConfigDialog reset button
+ // and we don't want to cause a check for Ok/Reset button enabled state for
+ // every XineConfigEntry
+ m_widget->blockSignals( true );
+
+ switch( classType( m_widget->className() ) ) {
+ case LineEdit: _(KLineEdit)->setText( m_string ); break;
+ case ComboBox: _(KComboBox)->setCurrentItem( m_number ); break;
+ case SpinBox: _(QSpinBox)->setValue( m_number ); break;
+ case CheckBox: _(QCheckBox)->setChecked( (bool)m_number ); break;
+ }
+ m_widget->blockSignals( false );
+}
+
+void
+XineConfigEntry::save( xine_t *xine )
+{
+ xine_cfg_entry_t ent;
+
+ if( xine_config_lookup_entry( xine, key(), &ent ) )
+ {
+ switch( classType( m_widget->className() ) ) {
+ case LineEdit: m_string = _(KLineEdit)->text().utf8(); break;
+ case ComboBox: m_number = _(KComboBox)->currentItem(); break;
+ case SpinBox: m_number = _(QSpinBox)->value(); break;
+ case CheckBox: m_number = _(QCheckBox)->isChecked(); break;
+ }
+
+ ent.str_value = qstrdup( m_string );
+ ent.num_value = m_number;
+
+ debug() << "Saving setting: " << key() << endl;
+ xine_config_update_entry( xine, &ent );
+ }
+ else
+ Debug::warning() << "Couldn't save: " << key() << endl;
+
+ #undef _
+}