diff options
Diffstat (limited to 'kcontrol/style/kcmstyle.cpp')
-rw-r--r-- | kcontrol/style/kcmstyle.cpp | 1070 |
1 files changed, 1070 insertions, 0 deletions
diff --git a/kcontrol/style/kcmstyle.cpp b/kcontrol/style/kcmstyle.cpp new file mode 100644 index 000000000..9333c0f72 --- /dev/null +++ b/kcontrol/style/kcmstyle.cpp @@ -0,0 +1,1070 @@ +/* + * KCMStyle + * Copyright (C) 2002 Karol Szwed <gallium@kde.org> + * Copyright (C) 2002 Daniel Molkentin <molkentin@kde.org> + * + * Portions Copyright (C) 2000 TrollTech AS. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 as published by the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <qcheckbox.h> +#include <kcombobox.h> +#include <qlistbox.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qslider.h> +#include <qstylefactory.h> +#include <qtabwidget.h> +#include <qvbox.h> +#include <qfile.h> +#include <qsettings.h> +#include <qobjectlist.h> +#include <qpixmapcache.h> +#include <qwhatsthis.h> +#include <qpushbutton.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kglobalsettings.h> +#include <kdebug.h> +#include <kipc.h> +#include <kaboutdata.h> +#include <kdialog.h> +#include <klibloader.h> +#include <klistview.h> +#include <kmessagebox.h> +#include <ksimpleconfig.h> +#include <kstyle.h> +#include <kstandarddirs.h> + +#include "../krdb/krdb.h" + +#include "kcmstyle.h" +#include "styleconfdialog.h" + +#include <X11/Xlib.h> +// X11 namespace cleanup +#undef Below +#undef KeyPress +#undef KeyRelease + + +/**** DLL Interface for kcontrol ****/ + +// Plugin Interface +// Danimo: Why do we use the old interface?! +extern "C" +{ + KDE_EXPORT KCModule *create_style(QWidget *parent, const char*) + { + KGlobal::locale()->insertCatalogue("kcmstyle"); + return new KCMStyle(parent, "kcmstyle"); + } + + KDE_EXPORT void init_style() + { + uint flags = KRdbExportQtSettings | KRdbExportQtColors | KRdbExportXftSettings; + KConfig config("kcmdisplayrc", true /*readonly*/, false /*don't read kdeglobals etc.*/); + config.setGroup("X11"); + + // This key is written by the "colors" module. + bool exportKDEColors = config.readBoolEntry("exportKDEColors", true); + if (exportKDEColors) + flags |= KRdbExportColors; + runRdb( flags ); + + // Write some Qt root property. +#ifndef __osf__ // this crashes under Tru64 randomly -- will fix later + QByteArray properties; + QDataStream d(properties, IO_WriteOnly); + d.setVersion( 3 ); // Qt2 apps need this. + d << kapp->palette() << KGlobalSettings::generalFont(); + Atom a = XInternAtom(qt_xdisplay(), "_QT_DESKTOP_PROPERTIES", false); + + // do it for all root windows - multihead support + int screen_count = ScreenCount(qt_xdisplay()); + for (int i = 0; i < screen_count; i++) + XChangeProperty(qt_xdisplay(), RootWindow(qt_xdisplay(), i), + a, a, 8, PropModeReplace, + (unsigned char*) properties.data(), properties.size()); +#endif + } +} + +/* +typedef KGenericFactory<KWidgetSettingsModule, QWidget> GeneralFactory; +K_EXPORT_COMPONENT_FACTORY( kcm_kcmstyle, GeneralFactory ) +*/ + + +KCMStyle::KCMStyle( QWidget* parent, const char* name ) + : KCModule( parent, name ), appliedStyle(NULL) +{ + setQuickHelp( i18n("<h1>Style</h1>" + "This module allows you to modify the visual appearance " + "of user interface elements, such as the widget style " + "and effects.")); + + m_bEffectsDirty = false; + m_bStyleDirty= false; + m_bToolbarsDirty = false; + + KGlobal::dirs()->addResourceType("themes", + KStandardDirs::kde_default("data") + "kstyle/themes"); + + KAboutData *about = + new KAboutData( I18N_NOOP("kcmstyle"), + I18N_NOOP("KDE Style Module"), + 0, 0, KAboutData::License_GPL, + I18N_NOOP("(c) 2002 Karol Szwed, Daniel Molkentin")); + + about->addAuthor("Karol Szwed", 0, "gallium@kde.org"); + about->addAuthor("Daniel Molkentin", 0, "molkentin@kde.org"); + about->addAuthor("Ralf Nolden", 0, "nolden@kde.org"); + setAboutData( about ); + + // Setup pages and mainLayout + mainLayout = new QVBoxLayout( this ); + tabWidget = new QTabWidget( this ); + mainLayout->addWidget( tabWidget ); + + page1 = new QWidget( tabWidget ); + page1Layout = new QVBoxLayout( page1, KDialog::marginHint(), KDialog::spacingHint() ); + page2 = new QWidget( tabWidget ); + page2Layout = new QVBoxLayout( page2, KDialog::marginHint(), KDialog::spacingHint() ); + page3 = new QWidget( tabWidget ); + page3Layout = new QVBoxLayout( page3, KDialog::marginHint(), KDialog::spacingHint() ); + + // Add Page1 (Style) + // ----------------- + gbWidgetStyle = new QGroupBox( i18n("Widget Style"), page1, "gbWidgetStyle" ); + gbWidgetStyle->setColumnLayout( 0, Qt::Vertical ); + gbWidgetStyle->layout()->setMargin( KDialog::marginHint() ); + gbWidgetStyle->layout()->setSpacing( KDialog::spacingHint() ); + + gbWidgetStyleLayout = new QVBoxLayout( gbWidgetStyle->layout() ); + gbWidgetStyleLayout->setAlignment( Qt::AlignTop ); + hbLayout = new QHBoxLayout( KDialog::spacingHint(), "hbLayout" ); + + cbStyle = new KComboBox( gbWidgetStyle, "cbStyle" ); + cbStyle->setEditable( FALSE ); + hbLayout->addWidget( cbStyle ); + + pbConfigStyle = new QPushButton( i18n("Con&figure..."), gbWidgetStyle ); + pbConfigStyle->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Minimum ); + pbConfigStyle->setEnabled( FALSE ); + hbLayout->addWidget( pbConfigStyle ); + + gbWidgetStyleLayout->addLayout( hbLayout ); + + lblStyleDesc = new QLabel( gbWidgetStyle ); + lblStyleDesc->setTextFormat(Qt::RichText); + gbWidgetStyleLayout->addWidget( lblStyleDesc ); + + cbIconsOnButtons = new QCheckBox( i18n("Sho&w icons on buttons"), gbWidgetStyle ); + gbWidgetStyleLayout->addWidget( cbIconsOnButtons ); + cbEnableTooltips = new QCheckBox( i18n("E&nable tooltips"), gbWidgetStyle ); + gbWidgetStyleLayout->addWidget( cbEnableTooltips ); + cbTearOffHandles = new QCheckBox( i18n("Show tear-off handles in &popup menus"), gbWidgetStyle ); + gbWidgetStyleLayout->addWidget( cbTearOffHandles ); + cbTearOffHandles->hide(); // reenable when the corresponding Qt method is virtual and properly reimplemented + + QGroupBox *gbPreview = new QGroupBox( i18n( "Preview" ), page1 ); + gbPreview->setColumnLayout( 0, Vertical ); + gbPreview->layout()->setMargin( 0 ); + gbPreview->layout()->setSpacing( KDialog::spacingHint() ); + gbPreview->setFlat( true ); + stylePreview = new StylePreview( gbPreview ); + gbPreview->layout()->add( stylePreview ); + + page1Layout->addWidget( gbWidgetStyle ); + page1Layout->addWidget( gbPreview ); + + // Connect all required stuff + connect( cbStyle, SIGNAL(activated(int)), this, SLOT(styleChanged()) ); + connect( cbStyle, SIGNAL(activated(int)), this, SLOT(updateConfigButton())); + connect( pbConfigStyle, SIGNAL(clicked()), this, SLOT(styleSpecificConfig())); + + // Add Page2 (Effects) + // ------------------- + cbEnableEffects = new QCheckBox( i18n("&Enable GUI effects"), page2 ); + containerFrame = new QFrame( page2 ); + containerFrame->setFrameStyle( QFrame::NoFrame | QFrame::Plain ); + containerFrame->setMargin(0); + containerLayout = new QGridLayout( containerFrame, 1, 1, // rows, columns + KDialog::marginHint(), KDialog::spacingHint() ); + + comboComboEffect = new QComboBox( FALSE, containerFrame ); + comboComboEffect->insertItem( i18n("Disable") ); + comboComboEffect->insertItem( i18n("Animate") ); + lblComboEffect = new QLabel( i18n("Combobo&x effect:"), containerFrame ); + lblComboEffect->setBuddy( comboComboEffect ); + containerLayout->addWidget( lblComboEffect, 0, 0 ); + containerLayout->addWidget( comboComboEffect, 0, 1 ); + + comboTooltipEffect = new QComboBox( FALSE, containerFrame ); + comboTooltipEffect->insertItem( i18n("Disable") ); + comboTooltipEffect->insertItem( i18n("Animate") ); + comboTooltipEffect->insertItem( i18n("Fade") ); + lblTooltipEffect = new QLabel( i18n("&Tool tip effect:"), containerFrame ); + lblTooltipEffect->setBuddy( comboTooltipEffect ); + containerLayout->addWidget( lblTooltipEffect, 1, 0 ); + containerLayout->addWidget( comboTooltipEffect, 1, 1 ); + + comboMenuEffect = new QComboBox( FALSE, containerFrame ); + comboMenuEffect->insertItem( i18n("Disable") ); + comboMenuEffect->insertItem( i18n("Animate") ); + comboMenuEffect->insertItem( i18n("Fade") ); + comboMenuEffect->insertItem( i18n("Make Translucent") ); + lblMenuEffect = new QLabel( i18n("&Menu effect:"), containerFrame ); + lblMenuEffect->setBuddy( comboMenuEffect ); + containerLayout->addWidget( lblMenuEffect, 2, 0 ); + containerLayout->addWidget( comboMenuEffect, 2, 1 ); + + comboMenuHandle = new QComboBox( FALSE, containerFrame ); + comboMenuHandle->insertItem( i18n("Disable") ); + comboMenuHandle->insertItem( i18n("Application Level") ); +// comboMenuHandle->insertItem( i18n("Enable") ); + lblMenuHandle = new QLabel( i18n("Me&nu tear-off handles:"), containerFrame ); + lblMenuHandle->setBuddy( comboMenuHandle ); + containerLayout->addWidget( lblMenuHandle, 3, 0 ); + containerLayout->addWidget( comboMenuHandle, 3, 1 ); + + cbMenuShadow = new QCheckBox( i18n("Menu &drop shadow"), containerFrame ); + containerLayout->addWidget( cbMenuShadow, 4, 0 ); + + // Push the [label combo] to the left. + comboSpacer = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); + containerLayout->addItem( comboSpacer, 1, 2 ); + + // Separator. + QFrame* hline = new QFrame ( page2 ); + hline->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + + // Now implement the Menu Transparency container. + menuContainer = new QFrame( page2 ); + menuContainer->setFrameStyle( QFrame::NoFrame | QFrame::Plain ); + menuContainer->setMargin(0); + menuContainerLayout = new QGridLayout( menuContainer, 1, 1, // rows, columns + KDialog::marginHint(), KDialog::spacingHint() ); + + menuPreview = new MenuPreview( menuContainer, /* opacity */ 90, MenuPreview::Blend ); + + comboMenuEffectType = new QComboBox( FALSE, menuContainer ); + comboMenuEffectType->insertItem( i18n("Software Tint") ); + comboMenuEffectType->insertItem( i18n("Software Blend") ); +#ifdef HAVE_XRENDER + comboMenuEffectType->insertItem( i18n("XRender Blend") ); +#endif + + // So much stuffing around for a simple slider.. + sliderBox = new QVBox( menuContainer ); + sliderBox->setSpacing( KDialog::spacingHint() ); + sliderBox->setMargin( 0 ); + slOpacity = new QSlider( 0, 100, 5, /*opacity*/ 90, Qt::Horizontal, sliderBox ); + slOpacity->setTickmarks( QSlider::Below ); + slOpacity->setTickInterval( 10 ); + QHBox* box1 = new QHBox( sliderBox ); + box1->setSpacing( KDialog::spacingHint() ); + box1->setMargin( 0 ); + QLabel* lbl = new QLabel( i18n("0%"), box1 ); + lbl->setAlignment( AlignLeft ); + lbl = new QLabel( i18n("50%"), box1 ); + lbl->setAlignment( AlignHCenter ); + lbl = new QLabel( i18n("100%"), box1 ); + lbl->setAlignment( AlignRight ); + + lblMenuEffectType = new QLabel( comboMenuEffectType, i18n("Menu trans&lucency type:"), menuContainer ); + lblMenuEffectType->setAlignment( AlignBottom | AlignLeft ); + lblMenuOpacity = new QLabel( slOpacity, i18n("Menu &opacity:"), menuContainer ); + lblMenuOpacity->setAlignment( AlignBottom | AlignLeft ); + + menuContainerLayout->addWidget( lblMenuEffectType, 0, 0 ); + menuContainerLayout->addWidget( comboMenuEffectType, 1, 0 ); + menuContainerLayout->addWidget( lblMenuOpacity, 2, 0 ); + menuContainerLayout->addWidget( sliderBox, 3, 0 ); + menuContainerLayout->addMultiCellWidget( menuPreview, 0, 3, 1, 1 ); + + // Layout page2. + page2Layout->addWidget( cbEnableEffects ); + page2Layout->addWidget( containerFrame ); + page2Layout->addWidget( hline ); + page2Layout->addWidget( menuContainer ); + + QSpacerItem* sp1 = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + page2Layout->addItem( sp1 ); + + // Data flow stuff. + connect( cbEnableEffects, SIGNAL(toggled(bool)), containerFrame, SLOT(setEnabled(bool)) ); + connect( cbEnableEffects, SIGNAL(toggled(bool)), this, SLOT(menuEffectChanged(bool)) ); + connect( slOpacity, SIGNAL(valueChanged(int)),menuPreview, SLOT(setOpacity(int)) ); + connect( comboMenuEffect, SIGNAL(activated(int)), this, SLOT(menuEffectChanged()) ); + connect( comboMenuEffect, SIGNAL(highlighted(int)), this, SLOT(menuEffectChanged()) ); + connect( comboMenuEffectType, SIGNAL(activated(int)), this, SLOT(menuEffectTypeChanged()) ); + connect( comboMenuEffectType, SIGNAL(highlighted(int)), this, SLOT(menuEffectTypeChanged()) ); + + // Add Page3 (Miscellaneous) + // ------------------------- + cbHoverButtons = new QCheckBox( i18n("High&light buttons under mouse"), page3 ); + cbTransparentToolbars = new QCheckBox( i18n("Transparent tool&bars when moving"), page3 ); + + QWidget * dummy = new QWidget( page3 ); + + QHBoxLayout* box2 = new QHBoxLayout( dummy, 0, KDialog::spacingHint() ); + lbl = new QLabel( i18n("Text pos&ition:"), dummy ); + comboToolbarIcons = new QComboBox( FALSE, dummy ); + comboToolbarIcons->insertItem( i18n("Icons Only") ); + comboToolbarIcons->insertItem( i18n("Text Only") ); + comboToolbarIcons->insertItem( i18n("Text Alongside Icons") ); + comboToolbarIcons->insertItem( i18n("Text Under Icons") ); + lbl->setBuddy( comboToolbarIcons ); + + box2->addWidget( lbl ); + box2->addWidget( comboToolbarIcons ); + QSpacerItem* sp2 = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); + box2->addItem( sp2 ); + + page3Layout->addWidget( cbHoverButtons ); + page3Layout->addWidget( cbTransparentToolbars ); + page3Layout->addWidget( dummy ); + + // Layout page3. + QSpacerItem* sp3 = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + page3Layout->addItem( sp3 ); + + // Load settings + load(); + + // Do all the setDirty connections. + connect(cbStyle, SIGNAL(activated(int)), this, SLOT(setStyleDirty())); + // Page2 + connect( cbEnableEffects, SIGNAL(toggled(bool)), this, SLOT(setEffectsDirty())); + connect( cbEnableEffects, SIGNAL(toggled(bool)), this, SLOT(setStyleDirty())); + connect( comboTooltipEffect, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); + connect( comboComboEffect, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); + connect( comboMenuEffect, SIGNAL(activated(int)), this, SLOT(setStyleDirty())); + connect( comboMenuHandle, SIGNAL(activated(int)), this, SLOT(setStyleDirty())); + connect( comboMenuEffectType, SIGNAL(activated(int)), this, SLOT(setStyleDirty())); + connect( slOpacity, SIGNAL(valueChanged(int)),this, SLOT(setStyleDirty())); + connect( cbMenuShadow, SIGNAL(toggled(bool)), this, SLOT(setStyleDirty())); + // Page3 + connect( cbHoverButtons, SIGNAL(toggled(bool)), this, SLOT(setToolbarsDirty())); + connect( cbTransparentToolbars, SIGNAL(toggled(bool)), this, SLOT(setToolbarsDirty())); + connect( cbEnableTooltips, SIGNAL(toggled(bool)), this, SLOT(setEffectsDirty())); + connect( cbIconsOnButtons, SIGNAL(toggled(bool)), this, SLOT(setEffectsDirty())); + connect( cbTearOffHandles, SIGNAL(toggled(bool)), this, SLOT(setEffectsDirty())); + connect( comboToolbarIcons, SIGNAL(activated(int)), this, SLOT(setToolbarsDirty())); + + addWhatsThis(); + + // Insert the pages into the tabWidget + tabWidget->insertTab( page1, i18n("&Style")); + tabWidget->insertTab( page2, i18n("&Effects")); + tabWidget->insertTab( page3, i18n("&Toolbar")); + + //Enable/disable the button for the initial style + updateConfigButton(); +} + + +KCMStyle::~KCMStyle() +{ + delete appliedStyle; +} + +void KCMStyle::updateConfigButton() +{ + if (!styleEntries[currentStyle()] || styleEntries[currentStyle()]->configPage.isEmpty()) { + pbConfigStyle->setEnabled(false); + return; + } + + // We don't check whether it's loadable here - + // lets us report an error and not waste time + // loading things if the user doesn't click the button + pbConfigStyle->setEnabled( true ); +} + +void KCMStyle::styleSpecificConfig() +{ + QString libname = styleEntries[currentStyle()]->configPage; + + // Use KLibLoader to get the library, handling + // any errors that arise + KLibLoader* loader = KLibLoader::self(); + + KLibrary* library = loader->library( QFile::encodeName(libname) ); + if (!library) + { + KMessageBox::detailedError(this, + i18n("There was an error loading the configuration dialog for this style."), + loader->lastErrorMessage(), + i18n("Unable to Load Dialog")); + return; + } + + void* allocPtr = library->symbol("allocate_kstyle_config"); + + if (!allocPtr) + { + KMessageBox::detailedError(this, + i18n("There was an error loading the configuration dialog for this style."), + loader->lastErrorMessage(), + i18n("Unable to Load Dialog")); + return; + } + + //Create the container dialog + StyleConfigDialog* dial = new StyleConfigDialog(this, styleEntries[currentStyle()]->name); + dial->enableButtonSeparator(true); + + typedef QWidget*(* factoryRoutine)( QWidget* parent ); + + //Get the factory, and make the widget. + factoryRoutine factory = (factoryRoutine)(allocPtr); //Grmbl. So here I am on my + //"never use C casts" moralizing streak, and I find that one can't go void* -> function ptr + //even with a reinterpret_cast. + + QWidget* pluginConfig = factory( dial ); + + //Insert it in... + dial->setMainWidget( pluginConfig ); + + //..and connect it to the wrapper + connect(pluginConfig, SIGNAL(changed(bool)), dial, SLOT(setDirty(bool))); + connect(dial, SIGNAL(defaults()), pluginConfig, SLOT(defaults())); + connect(dial, SIGNAL(save()), pluginConfig, SLOT(save())); + + if (dial->exec() == QDialog::Accepted && dial->isDirty() ) { + // Force re-rendering of the preview, to apply settings + switchStyle(currentStyle(), true); + + //For now, ask all KDE apps to recreate their styles to apply the setitngs + KIPC::sendMessageAll(KIPC::StyleChanged); + + // We call setStyleDirty here to make sure we force style re-creation + setStyleDirty(); + } + + delete dial; +} + +void KCMStyle::load() +{ + load( false ); +} + +void KCMStyle::load(bool useDefaults) +{ + KConfig config( "kdeglobals", true, false ); + + config.setReadDefaults( useDefaults ); + + // Page1 - Build up the Style ListBox + loadStyle( config ); + + // Page2 - Effects + loadEffects( config ); + + // Page3 - Misc. + loadMisc( config ); + + m_bEffectsDirty = false; + m_bStyleDirty= false; + m_bToolbarsDirty = false; + + emit changed( useDefaults ); +} + + +void KCMStyle::save() +{ + // Don't do anything if we don't need to. + if ( !(m_bToolbarsDirty | m_bEffectsDirty | m_bStyleDirty ) ) + return; + + bool allowMenuTransparency = false; + bool allowMenuDropShadow = false; + + // Read the KStyle flags to see if the style writer + // has enabled menu translucency in the style. + if (appliedStyle && appliedStyle->inherits("KStyle")) + { + allowMenuDropShadow = true; + KStyle* style = dynamic_cast<KStyle*>(appliedStyle); + if (style) { + KStyle::KStyleFlags flags = style->styleFlags(); + if (flags & KStyle::AllowMenuTransparency) + allowMenuTransparency = true; + } + } + + QString warn_string( i18n("<qt>Selected style: <b>%1</b><br><br>" + "One or more effects that you have chosen could not be applied because the selected " + "style does not support them; they have therefore been disabled.<br>" + "<br>" ).arg( cbStyle->currentText()) ); + bool show_warning = false; + + // Warn the user if they're applying a style that doesn't support + // menu translucency and they enabled it. + if ( (!allowMenuTransparency) && + (cbEnableEffects->isChecked()) && + (comboMenuEffect->currentItem() == 3) ) // Make Translucent + { + warn_string += i18n("Menu translucency is not available.<br>"); + comboMenuEffect->setCurrentItem(0); // Disable menu effect. + show_warning = true; + } + + if (!allowMenuDropShadow && cbMenuShadow->isChecked()) + { + warn_string += i18n("Menu drop-shadows are not available."); + cbMenuShadow->setChecked(false); + show_warning = true; + } + + // Tell the user what features we could not apply on their behalf. + if (show_warning) + KMessageBox::information(this, warn_string); + + + // Save effects. + KConfig config( "kdeglobals" ); + config.setGroup("KDE"); + + config.writeEntry( "EffectsEnabled", cbEnableEffects->isChecked()); + int item = comboComboEffect->currentItem(); + config.writeEntry( "EffectAnimateCombo", item == 1 ); + item = comboTooltipEffect->currentItem(); + config.writeEntry( "EffectAnimateTooltip", item == 1); + config.writeEntry( "EffectFadeTooltip", item == 2 ); + item = comboMenuHandle->currentItem(); + config.writeEntry( "InsertTearOffHandle", item ); + item = comboMenuEffect->currentItem(); + config.writeEntry( "EffectAnimateMenu", item == 1 ); + config.writeEntry( "EffectFadeMenu", item == 2 ); + + // Handle KStyle's menu effects + QString engine("Disabled"); + if (item == 3 && cbEnableEffects->isChecked()) // Make Translucent + switch( comboMenuEffectType->currentItem()) + { + case 1: engine = "SoftwareBlend"; break; + case 2: engine = "XRender"; break; + default: + case 0: engine = "SoftwareTint"; break; + } + + { // Braces force a QSettings::sync() + QSettings settings; // Only for KStyle stuff + settings.writeEntry("/KStyle/Settings/MenuTransparencyEngine", engine); + settings.writeEntry("/KStyle/Settings/MenuOpacity", slOpacity->value()/100.0); + settings.writeEntry("/KStyle/Settings/MenuDropShadow", + cbEnableEffects->isChecked() && cbMenuShadow->isChecked() ); + } + + // Misc page + config.writeEntry( "ShowIconsOnPushButtons", cbIconsOnButtons->isChecked(), true, true ); + config.writeEntry( "EffectNoTooltip", !cbEnableTooltips->isChecked(), true, true ); + + config.setGroup("General"); + config.writeEntry( "widgetStyle", currentStyle() ); + + config.setGroup("Toolbar style"); + config.writeEntry( "Highlighting", cbHoverButtons->isChecked(), true, true ); + config.writeEntry( "TransparentMoving", cbTransparentToolbars->isChecked(), true, true ); + QString tbIcon; + switch( comboToolbarIcons->currentItem() ) + { + case 1: tbIcon = "TextOnly"; break; + case 2: tbIcon = "IconTextRight"; break; + case 3: tbIcon = "IconTextBottom"; break; + case 0: + default: tbIcon = "IconOnly"; break; + } + config.writeEntry( "IconText", tbIcon, true, true ); + config.sync(); + + // Export the changes we made to qtrc, and update all qt-only + // applications on the fly, ensuring that we still follow the user's + // export fonts/colors settings. + if (m_bStyleDirty | m_bEffectsDirty) // Export only if necessary + { + uint flags = KRdbExportQtSettings; + KConfig kconfig("kcmdisplayrc", true /*readonly*/, false /*no globals*/); + kconfig.setGroup("X11"); + bool exportKDEColors = kconfig.readBoolEntry("exportKDEColors", true); + if (exportKDEColors) + flags |= KRdbExportColors; + runRdb( flags ); + } + + // Now allow KDE apps to reconfigure themselves. + if ( m_bStyleDirty ) + KIPC::sendMessageAll(KIPC::StyleChanged); + + if ( m_bToolbarsDirty ) + // ##### FIXME - Doesn't apply all settings correctly due to bugs in + // KApplication/KToolbar + KIPC::sendMessageAll(KIPC::ToolbarStyleChanged); + + if (m_bEffectsDirty) { + KIPC::sendMessageAll(KIPC::SettingsChanged); + kapp->dcopClient()->send("kwin*", "", "reconfigure()", ""); + } + //update kicker to re-used tooltips kicker parameter otherwise, it overwritted + //by style tooltips parameters. + QByteArray data; + kapp->dcopClient()->send( "kicker", "kicker", "configure()", data ); + + // Clean up + m_bEffectsDirty = false; + m_bToolbarsDirty = false; + m_bStyleDirty = false; + emit changed( false ); +} + + +bool KCMStyle::findStyle( const QString& str, int& combobox_item ) +{ + StyleEntry* se = styleEntries.find(str.lower()); + + QString name = se ? se->name : str; + + combobox_item = 0; + + //look up name + for( int i = 0; i < cbStyle->count(); i++ ) + { + if ( cbStyle->text(i) == name ) + { + combobox_item = i; + return TRUE; + } + } + + return FALSE; +} + + +void KCMStyle::defaults() +{ + load( true ); +} + +void KCMStyle::setEffectsDirty() +{ + m_bEffectsDirty = true; + emit changed(true); +} + +void KCMStyle::setToolbarsDirty() +{ + m_bToolbarsDirty = true; + emit changed(true); +} + +void KCMStyle::setStyleDirty() +{ + m_bStyleDirty = true; + emit changed(true); +} + +// ---------------------------------------------------------------- +// All the Style Switching / Preview stuff +// ---------------------------------------------------------------- + +void KCMStyle::loadStyle( KConfig& config ) +{ + cbStyle->clear(); + + // Create a dictionary of WidgetStyle to Name and Desc. mappings, + // as well as the config page info + styleEntries.clear(); + styleEntries.setAutoDelete(true); + + QString strWidgetStyle; + QStringList list = KGlobal::dirs()->findAllResources("themes", "*.themerc", true, true); + for (QStringList::iterator it = list.begin(); it != list.end(); ++it) + { + KSimpleConfig config( *it, true ); + if ( !(config.hasGroup("KDE") && config.hasGroup("Misc")) ) + continue; + + config.setGroup("KDE"); + + strWidgetStyle = config.readEntry("WidgetStyle"); + if (strWidgetStyle.isNull()) + continue; + + // We have a widgetstyle, so lets read the i18n entries for it... + StyleEntry* entry = new StyleEntry; + config.setGroup("Misc"); + entry->name = config.readEntry("Name"); + entry->desc = config.readEntry("Comment", i18n("No description available.")); + entry->configPage = config.readEntry("ConfigPage", QString::null); + + // Check if this style should be shown + config.setGroup("Desktop Entry"); + entry->hidden = config.readBoolEntry("Hidden", false); + + // Insert the entry into our dictionary. + styleEntries.insert(strWidgetStyle.lower(), entry); + } + + // Obtain all style names + QStringList allStyles = QStyleFactory::keys(); + + // Get translated names, remove all hidden style entries. + QStringList styles; + StyleEntry* entry; + for (QStringList::iterator it = allStyles.begin(); it != allStyles.end(); it++) + { + QString id = (*it).lower(); + // Find the entry. + if ( (entry = styleEntries.find(id)) != 0 ) + { + // Do not add hidden entries + if (entry->hidden) + continue; + + styles += entry->name; + + nameToStyleKey[entry->name] = id; + } + else + { + styles += (*it); //Fall back to the key (but in original case) + nameToStyleKey[*it] = id; + } + } + + // Sort the style list, and add it to the combobox + styles.sort(); + cbStyle->insertStringList( styles ); + + // Find out which style is currently being used + config.setGroup( "General" ); + QString defaultStyle = KStyle::defaultStyle(); + QString cfgStyle = config.readEntry( "widgetStyle", defaultStyle ); + + // Select the current style + // Do not use cbStyle->listBox() as this may be NULL for some styles when + // they use QPopupMenus for the drop-down list! + + // ##### Since Trolltech likes to seemingly copy & paste code, + // QStringList::findItem() doesn't have a Qt::StringComparisonMode field. + // We roll our own (yuck) + cfgStyle = cfgStyle.lower(); + int item = 0; + for( int i = 0; i < cbStyle->count(); i++ ) + { + QString id = nameToStyleKey[cbStyle->text(i)]; + item = i; + if ( id == cfgStyle ) // ExactMatch + break; + else if ( id.contains( cfgStyle ) ) + break; + else if ( id.contains( QApplication::style().className() ) ) + break; + item = 0; + } + cbStyle->setCurrentItem( item ); + + m_bStyleDirty = false; + + switchStyle( currentStyle() ); // make resets visible +} + +QString KCMStyle::currentStyle() +{ + return nameToStyleKey[cbStyle->currentText()]; +} + + +void KCMStyle::styleChanged() +{ + switchStyle( currentStyle() ); +} + + +void KCMStyle::switchStyle(const QString& styleName, bool force) +{ + // Don't flicker the preview if the same style is chosen in the cb + if (!force && appliedStyle && appliedStyle->name() == styleName) + return; + + // Create an instance of the new style... + QStyle* style = QStyleFactory::create(styleName); + if (!style) + return; + + // Prevent Qt from wrongly caching radio button images + QPixmapCache::clear(); + + setStyleRecursive( stylePreview, style ); + + // this flickers, but reliably draws the widgets correctly. + stylePreview->resize( stylePreview->sizeHint() ); + + delete appliedStyle; + appliedStyle = style; + + // Set the correct style description + StyleEntry* entry = styleEntries.find( styleName ); + QString desc; + desc = i18n("Description: %1").arg( entry ? entry->desc : i18n("No description available.") ); + lblStyleDesc->setText( desc ); +} + +void KCMStyle::setStyleRecursive(QWidget* w, QStyle* s) +{ + // Don't let broken styles kill the palette + // for other styles being previewed. (e.g SGI style) + w->unsetPalette(); + + QPalette newPalette(KApplication::createApplicationPalette()); + s->polish( newPalette ); + w->setPalette(newPalette); + + // Apply the new style. + w->setStyle(s); + + // Recursively update all children. + const QObjectList *children = w->children(); + if (!children) + return; + + // Apply the style to each child widget. + QPtrListIterator<QObject> childit(*children); + QObject *child; + while ((child = childit.current()) != 0) + { + ++childit; + if (child->isWidgetType()) + setStyleRecursive((QWidget *) child, s); + } +} + + +// ---------------------------------------------------------------- +// All the Effects stuff +// ---------------------------------------------------------------- + +void KCMStyle::loadEffects( KConfig& config ) +{ + // Load effects. + config.setGroup("KDE"); + + cbEnableEffects->setChecked( config.readBoolEntry( "EffectsEnabled", false) ); + + if ( config.readBoolEntry( "EffectAnimateCombo", false) ) + comboComboEffect->setCurrentItem( 1 ); + else + comboComboEffect->setCurrentItem( 0 ); + + if ( config.readBoolEntry( "EffectAnimateTooltip", false) ) + comboTooltipEffect->setCurrentItem( 1 ); + else if ( config.readBoolEntry( "EffectFadeTooltip", false) ) + comboTooltipEffect->setCurrentItem( 2 ); + else + comboTooltipEffect->setCurrentItem( 0 ); + + if ( config.readBoolEntry( "EffectAnimateMenu", false) ) + comboMenuEffect->setCurrentItem( 1 ); + else if ( config.readBoolEntry( "EffectFadeMenu", false) ) + comboMenuEffect->setCurrentItem( 2 ); + else + comboMenuEffect->setCurrentItem( 0 ); + + comboMenuHandle->setCurrentItem(config.readNumEntry("InsertTearOffHandle", 0)); + + // KStyle Menu transparency and drop-shadow options... + QSettings settings; + QString effectEngine = settings.readEntry("/KStyle/Settings/MenuTransparencyEngine", "Disabled"); + +#ifdef HAVE_XRENDER + if (effectEngine == "XRender") { + comboMenuEffectType->setCurrentItem(2); + comboMenuEffect->setCurrentItem(3); + } else if (effectEngine == "SoftwareBlend") { + comboMenuEffectType->setCurrentItem(1); + comboMenuEffect->setCurrentItem(3); +#else + if (effectEngine == "XRender" || effectEngine == "SoftwareBlend") { + comboMenuEffectType->setCurrentItem(1); // Software Blend + comboMenuEffect->setCurrentItem(3); +#endif + } else if (effectEngine == "SoftwareTint") { + comboMenuEffectType->setCurrentItem(0); + comboMenuEffect->setCurrentItem(3); + } else + comboMenuEffectType->setCurrentItem(0); + + if (comboMenuEffect->currentItem() != 3) // If not translucency... + menuPreview->setPreviewMode( MenuPreview::Tint ); + else if (comboMenuEffectType->currentItem() == 0) + menuPreview->setPreviewMode( MenuPreview::Tint ); + else + menuPreview->setPreviewMode( MenuPreview::Blend ); + + slOpacity->setValue( (int)(100 * settings.readDoubleEntry("/KStyle/Settings/MenuOpacity", 0.90)) ); + + // Menu Drop-shadows... + cbMenuShadow->setChecked( settings.readBoolEntry("/KStyle/Settings/MenuDropShadow", false) ); + + if (cbEnableEffects->isChecked()) { + containerFrame->setEnabled( true ); + menuContainer->setEnabled( comboMenuEffect->currentItem() == 3 ); + } else { + menuContainer->setEnabled( false ); + containerFrame->setEnabled( false ); + } + + m_bEffectsDirty = false; +} + + +void KCMStyle::menuEffectTypeChanged() +{ + MenuPreview::PreviewMode mode; + + if (comboMenuEffect->currentItem() != 3) + mode = MenuPreview::Tint; + else if (comboMenuEffectType->currentItem() == 0) + mode = MenuPreview::Tint; + else + mode = MenuPreview::Blend; + + menuPreview->setPreviewMode(mode); + + m_bEffectsDirty = true; +} + + +void KCMStyle::menuEffectChanged() +{ + menuEffectChanged( cbEnableEffects->isChecked() ); + m_bEffectsDirty = true; +} + + +void KCMStyle::menuEffectChanged( bool enabled ) +{ + if (enabled && + comboMenuEffect->currentItem() == 3) { + menuContainer->setEnabled(true); + } else + menuContainer->setEnabled(false); + m_bEffectsDirty = true; +} + + +// ---------------------------------------------------------------- +// All the Miscellaneous stuff +// ---------------------------------------------------------------- + +void KCMStyle::loadMisc( KConfig& config ) +{ + // KDE's Part via KConfig + config.setGroup("Toolbar style"); + cbHoverButtons->setChecked(config.readBoolEntry("Highlighting", true)); + cbTransparentToolbars->setChecked(config.readBoolEntry("TransparentMoving", true)); + + QString tbIcon = config.readEntry("IconText", "IconOnly"); + if (tbIcon == "TextOnly") + comboToolbarIcons->setCurrentItem(1); + else if (tbIcon == "IconTextRight") + comboToolbarIcons->setCurrentItem(2); + else if (tbIcon == "IconTextBottom") + comboToolbarIcons->setCurrentItem(3); + else + comboToolbarIcons->setCurrentItem(0); + + config.setGroup("KDE"); + cbIconsOnButtons->setChecked(config.readBoolEntry("ShowIconsOnPushButtons", false)); + cbEnableTooltips->setChecked(!config.readBoolEntry("EffectNoTooltip", false)); + cbTearOffHandles->setChecked(config.readBoolEntry("InsertTearOffHandle", false)); + + m_bToolbarsDirty = false; +} + +void KCMStyle::addWhatsThis() +{ + // Page1 + QWhatsThis::add( cbStyle, i18n("Here you can choose from a list of" + " predefined widget styles (e.g. the way buttons are drawn) which" + " may or may not be combined with a theme (additional information" + " like a marble texture or a gradient).") ); + QWhatsThis::add( stylePreview, i18n("This area shows a preview of the currently selected style " + "without having to apply it to the whole desktop.") ); + + // Page2 + QWhatsThis::add( page2, i18n("This page allows you to enable various widget style effects. " + "For best performance, it is advisable to disable all effects.") ); + QWhatsThis::add( cbEnableEffects, i18n( "If you check this box, you can select several effects " + "for different widgets like combo boxes, menus or tooltips.") ); + QWhatsThis::add( comboComboEffect, i18n( "<p><b>Disable: </b>do not use any combo box effects.</p>\n" + "<b>Animate: </b>Do some animation.") ); + QWhatsThis::add( comboTooltipEffect, i18n( "<p><b>Disable: </b>do not use any tooltip effects.</p>\n" + "<p><b>Animate: </b>Do some animation.</p>\n" + "<b>Fade: </b>Fade in tooltips using alpha-blending.") ); + QWhatsThis::add( comboMenuEffect, i18n( "<p><b>Disable: </b>do not use any menu effects.</p>\n" + "<p><b>Animate: </b>Do some animation.</p>\n" + "<p><b>Fade: </b>Fade in menus using alpha-blending.</p>\n" + "<b>Make Translucent: </b>Alpha-blend menus for a see-through effect. (KDE styles only)") ); + QWhatsThis::add( cbMenuShadow, i18n( "When enabled, all popup menus will have a drop-shadow, otherwise " + "drop-shadows will not be displayed. At present, only KDE styles can have this " + "effect enabled.") ); + QWhatsThis::add( comboMenuEffectType, i18n( "<p><b>Software Tint: </b>Alpha-blend using a flat color.</p>\n" + "<p><b>Software Blend: </b>Alpha-blend using an image.</p>\n" + "<b>XRender Blend: </b>Use the XFree RENDER extension for image blending (if available). " + "This method may be slower than the Software routines on non-accelerated displays, " + "but may however improve performance on remote displays.</p>\n") ); + QWhatsThis::add( slOpacity, i18n("By adjusting this slider you can control the menu effect opacity.") ); + + // Page3 + QWhatsThis::add( page3, i18n("<b>Note:</b> that all widgets in this combobox " + "do not apply to Qt-only applications.") ); + QWhatsThis::add( cbHoverButtons, i18n("If this option is selected, toolbar buttons will change " + "their color when the mouse cursor is moved over them." ) ); + QWhatsThis::add( cbTransparentToolbars, i18n("If you check this box, the toolbars will be " + "transparent when moving them around.") ); + QWhatsThis::add( cbEnableTooltips, i18n( "If you check this option, the KDE application " + "will offer tooltips when the cursor remains over items in the toolbar." ) ); + QWhatsThis::add( comboToolbarIcons, i18n( "<p><b>Icons only:</b> Shows only icons on toolbar buttons. " + "Best option for low resolutions.</p>" + "<p><b>Text only: </b>Shows only text on toolbar buttons.</p>" + "<p><b>Text alongside icons: </b> Shows icons and text on toolbar buttons. " + "Text is aligned alongside the icon.</p>" + "<b>Text under icons: </b> Shows icons and text on toolbar buttons. " + "Text is aligned below the icon.") ); + QWhatsThis::add( cbIconsOnButtons, i18n( "If you enable this option, KDE Applications will " + "show small icons alongside some important buttons.") ); + QWhatsThis::add( cbTearOffHandles, i18n( "If you enable this option some pop-up menus will " + "show so called tear-off handles. If you click them, you get the menu " + "inside a widget. This can be very helpful when performing " + "the same action multiple times.") ); +} + +#include "kcmstyle.moc" + +// vim: set noet ts=4: |