1 | /* |
2 | * KCMStyle |
3 | * Copyright (C) 2002 Karol Szwed <gallium@kde.org> |
4 | * Copyright (C) 2002 Daniel Molkentin <molkentin@kde.org> |
5 | * Copyright (C) 2007 Urs Wolfer <uwolfer @ kde.org> |
6 | * Copyright (C) 2009 by Davide Bettio <davide.bettio@kdemail.net> |
7 | |
8 | * Portions Copyright (C) 2007 Paolo Capriotti <p.capriotti@gmail.com> |
9 | * Portions Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde@gmail.com> |
10 | * Portions Copyright (C) 2008 by Petri Damsten <damu@iki.fi> |
11 | * Portions Copyright (C) 2000 TrollTech AS. |
12 | * |
13 | * This program is free software; you can redistribute it and/or |
14 | * modify it under the terms of the GNU General Public |
15 | * License version 2 as published by the Free Software Foundation. |
16 | * |
17 | * This program is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
20 | * General Public License for more details. |
21 | * |
22 | * You should have received a copy of the GNU General Public License |
23 | * along with this program; see the file COPYING. If not, write to |
24 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
25 | * Boston, MA 02110-1301, USA. |
26 | */ |
27 | |
28 | #include "kcmstyle.h" |
29 | |
30 | #ifdef Q_WS_X11 |
31 | #include <config-X11.h> |
32 | #endif |
33 | |
34 | #include "styleconfdialog.h" |
35 | #include "ui_stylepreview.h" |
36 | |
37 | #include <kaboutdata.h> |
38 | #include <kapplication.h> |
39 | #include <kcombobox.h> |
40 | #include <kmessagebox.h> |
41 | #include <kstyle.h> |
42 | #include <kstandarddirs.h> |
43 | #include <kautostart.h> |
44 | #include <KDebug> |
45 | #include <KNotification> |
46 | #include <KLibrary> |
47 | #include <KColorScheme> |
48 | #include <KStandardDirs> |
49 | #include <knewstuff3/downloaddialog.h> |
50 | #ifdef Q_WS_X11 |
51 | #include <kdecoration.h> |
52 | #endif |
53 | |
54 | |
55 | #include <QtCore/QFile> |
56 | #include <QtCore/QSettings> |
57 | #include <QtGui/QAbstractItemView> |
58 | #include <QtGui/QLabel> |
59 | #include <QtGui/QPainter> |
60 | #include <QtGui/QPixmapCache> |
61 | #include <QtGui/QStyleFactory> |
62 | #include <QtGui/QFormLayout> |
63 | #include <QtGui/QStandardItemModel> |
64 | #include <QtGui/QStyle> |
65 | #include <QtDBus/QtDBus> |
66 | |
67 | #ifdef Q_WS_X11 |
68 | #include <QX11Info> |
69 | #endif |
70 | |
71 | #include "../krdb/krdb.h" |
72 | |
73 | #ifdef Q_WS_X11 |
74 | #include <X11/Xlib.h> |
75 | #endif |
76 | |
77 | // X11 namespace cleanup |
78 | #undef Below |
79 | #undef KeyPress |
80 | #undef KeyRelease |
81 | |
82 | |
83 | /**** DLL Interface for kcontrol ****/ |
84 | |
85 | #include <kpluginfactory.h> |
86 | #include <kpluginloader.h> |
87 | |
88 | K_PLUGIN_FACTORY(KCMStyleFactory, registerPlugin<KCMStyle>();) |
89 | K_EXPORT_PLUGIN(KCMStyleFactory("kcmstyle" )) |
90 | |
91 | |
92 | extern "C" |
93 | { |
94 | KDE_EXPORT void kcminit_style() |
95 | { |
96 | uint flags = KRdbExportQtSettings | KRdbExportQtColors | KRdbExportXftSettings | KRdbExportGtkTheme; |
97 | KConfig _config( "kcmdisplayrc" , KConfig::NoGlobals ); |
98 | KConfigGroup config(&_config, "X11" ); |
99 | |
100 | // This key is written by the "colors" module. |
101 | bool exportKDEColors = config.readEntry("exportKDEColors" , true); |
102 | if (exportKDEColors) |
103 | flags |= KRdbExportColors; |
104 | runRdb( flags ); |
105 | |
106 | // Write some Qt root property. |
107 | #ifdef Q_WS_X11 |
108 | #ifndef __osf__ // this crashes under Tru64 randomly -- will fix later |
109 | QByteArray properties; |
110 | QDataStream d(&properties, QIODevice::WriteOnly); |
111 | d.setVersion( 3 ); // Qt2 apps need this. |
112 | d << kapp->palette() << KGlobalSettings::generalFont(); |
113 | Atom a = XInternAtom(QX11Info::display(), "_QT_DESKTOP_PROPERTIES" , false); |
114 | |
115 | // do it for all root windows - multihead support |
116 | int screen_count = ScreenCount(QX11Info::display()); |
117 | for (int i = 0; i < screen_count; i++) |
118 | XChangeProperty(QX11Info::display(), RootWindow(QX11Info::display(), i), |
119 | a, a, 8, PropModeReplace, |
120 | (unsigned char*) properties.data(), properties.size()); |
121 | #endif |
122 | #endif |
123 | } |
124 | } |
125 | |
126 | class StylePreview : public QWidget, public Ui::StylePreview |
127 | { |
128 | public: |
129 | StylePreview(QWidget *parent = 0) |
130 | : QWidget(parent) |
131 | { |
132 | setupUi(this); |
133 | |
134 | // Ensure that the user can't toy with the child widgets. |
135 | // Method borrowed from Qt's qtconfig. |
136 | QList<QWidget*> widgets = findChildren<QWidget*>(); |
137 | foreach (QWidget* widget, widgets) |
138 | { |
139 | widget->installEventFilter(this); |
140 | widget->setFocusPolicy(Qt::NoFocus); |
141 | } |
142 | } |
143 | |
144 | bool eventFilter( QObject* /* obj */, QEvent* ev ) |
145 | { |
146 | switch( ev->type() ) |
147 | { |
148 | case QEvent::MouseButtonPress: |
149 | case QEvent::MouseButtonRelease: |
150 | case QEvent::MouseButtonDblClick: |
151 | case QEvent::MouseMove: |
152 | case QEvent::KeyPress: |
153 | case QEvent::KeyRelease: |
154 | case QEvent::Enter: |
155 | case QEvent::Leave: |
156 | case QEvent::Wheel: |
157 | case QEvent::ContextMenu: |
158 | return true; // ignore |
159 | default: |
160 | break; |
161 | } |
162 | return false; |
163 | } |
164 | }; |
165 | |
166 | |
167 | KCMStyle::KCMStyle( QWidget* parent, const QVariantList& ) |
168 | : KCModule( KCMStyleFactory::componentData(), parent ), appliedStyle(NULL) |
169 | { |
170 | setQuickHelp( i18n("<h1>Style</h1>" |
171 | "This module allows you to modify the visual appearance " |
172 | "of user interface elements, such as the widget style " |
173 | "and effects." )); |
174 | |
175 | m_bStyleDirty= false; |
176 | m_bEffectsDirty = false; |
177 | |
178 | |
179 | KGlobal::dirs()->addResourceType("themes" , "data" , "kstyle/themes" ); |
180 | |
181 | KAboutData *about = |
182 | new KAboutData( I18N_NOOP("kcmstyle" ), 0, |
183 | ki18n("KDE Style Module" ), |
184 | 0, KLocalizedString(), KAboutData::License_GPL, |
185 | ki18n("(c) 2002 Karol Szwed, Daniel Molkentin" )); |
186 | |
187 | about->addAuthor(ki18n("Karol Szwed" ), KLocalizedString(), "gallium@kde.org" ); |
188 | about->addAuthor(ki18n("Daniel Molkentin" ), KLocalizedString(), "molkentin@kde.org" ); |
189 | about->addAuthor(ki18n("Ralf Nolden" ), KLocalizedString(), "nolden@kde.org" ); |
190 | setAboutData( about ); |
191 | |
192 | // Setup pages and mainLayout |
193 | mainLayout = new QVBoxLayout( this ); |
194 | mainLayout->setMargin(0); |
195 | |
196 | tabWidget = new QTabWidget( this ); |
197 | mainLayout->addWidget( tabWidget ); |
198 | |
199 | // Add Page1 (Applications Style) |
200 | // ----------------- |
201 | //gbWidgetStyle = new QGroupBox( i18n("Widget Style"), page1 ); |
202 | page1 = new QWidget; |
203 | page1Layout = new QVBoxLayout( page1 ); |
204 | |
205 | QWidget* gbWidgetStyle = new QWidget( page1 ); |
206 | QVBoxLayout *widgetLayout = new QVBoxLayout(gbWidgetStyle); |
207 | |
208 | gbWidgetStyleLayout = new QVBoxLayout; |
209 | widgetLayout->addLayout( gbWidgetStyleLayout ); |
210 | gbWidgetStyleLayout->setAlignment( Qt::AlignTop ); |
211 | hbLayout = new QHBoxLayout( ); |
212 | hbLayout->setObjectName( "hbLayout" ); |
213 | |
214 | QLabel* label=new QLabel(i18n("Widget style:" ),this); |
215 | hbLayout->addWidget( label ); |
216 | |
217 | cbStyle = new KComboBox( gbWidgetStyle ); |
218 | cbStyle->setObjectName( "cbStyle" ); |
219 | cbStyle->setEditable( false ); |
220 | hbLayout->addWidget( cbStyle ); |
221 | hbLayout->setStretchFactor( cbStyle, 1 ); |
222 | label->setBuddy(cbStyle); |
223 | |
224 | pbConfigStyle = new QPushButton( i18n("Con&figure..." ), gbWidgetStyle ); |
225 | pbConfigStyle->setEnabled( false ); |
226 | hbLayout->addWidget( pbConfigStyle ); |
227 | |
228 | gbWidgetStyleLayout->addLayout( hbLayout ); |
229 | |
230 | lblStyleDesc = new QLabel( gbWidgetStyle ); |
231 | gbWidgetStyleLayout->addWidget( lblStyleDesc ); |
232 | |
233 | QGroupBox *gbPreview = new QGroupBox( i18n( "Preview" ), page1 ); |
234 | QVBoxLayout *previewLayout = new QVBoxLayout(gbPreview); |
235 | previewLayout->setMargin( 0 ); |
236 | stylePreview = new StylePreview( gbPreview ); |
237 | gbPreview->layout()->addWidget( stylePreview ); |
238 | |
239 | page1Layout->addWidget( gbWidgetStyle ); |
240 | page1Layout->addWidget( gbPreview ); |
241 | page1Layout->addStretch(); |
242 | |
243 | connect( cbStyle, SIGNAL(activated(int)), this, SLOT(styleChanged()) ); |
244 | connect( cbStyle, SIGNAL(activated(int)), this, SLOT(updateConfigButton())); |
245 | connect( pbConfigStyle, SIGNAL(clicked()), this, SLOT(styleSpecificConfig())); |
246 | |
247 | // Add Page2 (Effects) |
248 | // ------------------- |
249 | page2 = new QWidget; |
250 | fineTuningUi.setupUi(page2); |
251 | |
252 | fineTuningUi.comboGraphicEffectsLevel->setObjectName( "cbGraphicEffectsLevel" ); |
253 | fineTuningUi.comboGraphicEffectsLevel->setEditable( false ); |
254 | fineTuningUi.comboGraphicEffectsLevel->addItem(i18n("Low display resolution and Low CPU" ), KGlobalSettings::NoEffects); |
255 | fineTuningUi.comboGraphicEffectsLevel->addItem(i18n("High display resolution and Low CPU" ), KGlobalSettings::GradientEffects); |
256 | fineTuningUi.comboGraphicEffectsLevel->addItem(i18n("Low display resolution and High CPU" ), KGlobalSettings::SimpleAnimationEffects); |
257 | fineTuningUi.comboGraphicEffectsLevel->addItem(i18n("High display resolution and High CPU" ), (int) (KGlobalSettings::SimpleAnimationEffects | KGlobalSettings::GradientEffects)); |
258 | fineTuningUi.comboGraphicEffectsLevel->addItem(i18n("Low display resolution and Very High CPU" ), KGlobalSettings::ComplexAnimationEffects); |
259 | fineTuningUi.comboGraphicEffectsLevel->addItem(i18n("High display resolution and Very High CPU" ), (int) (KGlobalSettings::ComplexAnimationEffects | KGlobalSettings::GradientEffects)); |
260 | |
261 | connect(cbStyle, SIGNAL(activated(int)), this, SLOT(setStyleDirty())); |
262 | connect(fineTuningUi.cbIconsOnButtons, SIGNAL(toggled(bool)), this, SLOT(setEffectsDirty())); |
263 | connect(fineTuningUi.cbIconsInMenus, SIGNAL(toggled(bool)), this, SLOT(setEffectsDirty())); |
264 | connect(fineTuningUi.comboGraphicEffectsLevel, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); |
265 | connect(fineTuningUi.comboToolbarIcons, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); |
266 | connect(fineTuningUi.comboSecondaryToolbarIcons, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); |
267 | connect(fineTuningUi.comboMenubarStyle, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); |
268 | |
269 | addWhatsThis(); |
270 | |
271 | if (!QFile::exists(QLibraryInfo::location(QLibraryInfo::PluginsPath) + "/menubar/libappmenu-qt.so" )) { |
272 | fineTuningUi.menubarBox->hide(); |
273 | } |
274 | |
275 | // Insert the pages into the tabWidget |
276 | tabWidget->addTab(page1, i18nc("@title:tab" , "&Applications" )); |
277 | tabWidget->addTab(page2, i18nc("@title:tab" , "&Fine Tuning" )); |
278 | } |
279 | |
280 | |
281 | KCMStyle::~KCMStyle() |
282 | { |
283 | qDeleteAll(styleEntries); |
284 | delete appliedStyle; |
285 | } |
286 | |
287 | void KCMStyle::updateConfigButton() |
288 | { |
289 | if (!styleEntries[currentStyle()] || styleEntries[currentStyle()]->configPage.isEmpty()) { |
290 | pbConfigStyle->setEnabled(false); |
291 | return; |
292 | } |
293 | |
294 | // We don't check whether it's loadable here - |
295 | // lets us report an error and not waste time |
296 | // loading things if the user doesn't click the button |
297 | pbConfigStyle->setEnabled( true ); |
298 | } |
299 | |
300 | void KCMStyle::styleSpecificConfig() |
301 | { |
302 | QString libname = styleEntries[currentStyle()]->configPage; |
303 | |
304 | KLibrary library(libname, KCMStyleFactory::componentData()); |
305 | if (!library.load()) { |
306 | KMessageBox::detailedError(this, |
307 | i18n("There was an error loading the configuration dialog for this style." ), |
308 | library.errorString(), |
309 | i18n("Unable to Load Dialog" )); |
310 | return; |
311 | } |
312 | |
313 | KLibrary::void_function_ptr allocPtr = library.resolveFunction("allocate_kstyle_config" ); |
314 | |
315 | if (!allocPtr) |
316 | { |
317 | KMessageBox::detailedError(this, |
318 | i18n("There was an error loading the configuration dialog for this style." ), |
319 | library.errorString(), |
320 | i18n("Unable to Load Dialog" )); |
321 | return; |
322 | } |
323 | |
324 | //Create the container dialog |
325 | StyleConfigDialog* dial = new StyleConfigDialog(this, styleEntries[currentStyle()]->name); |
326 | |
327 | typedef QWidget*(* factoryRoutine)( QWidget* parent ); |
328 | |
329 | //Get the factory, and make the widget. |
330 | factoryRoutine factory = (factoryRoutine)(allocPtr); //Grmbl. So here I am on my |
331 | //"never use C casts" moralizing streak, and I find that one can't go void* -> function ptr |
332 | //even with a reinterpret_cast. |
333 | |
334 | QWidget* pluginConfig = factory( dial ); |
335 | |
336 | //Insert it in... |
337 | dial->setMainWidget( pluginConfig ); |
338 | |
339 | //..and connect it to the wrapper |
340 | connect(pluginConfig, SIGNAL(changed(bool)), dial, SLOT(setDirty(bool))); |
341 | connect(dial, SIGNAL(defaults()), pluginConfig, SLOT(defaults())); |
342 | connect(dial, SIGNAL(save()), pluginConfig, SLOT(save())); |
343 | |
344 | if (dial->exec() == QDialog::Accepted && dial->isDirty() ) { |
345 | // Force re-rendering of the preview, to apply settings |
346 | switchStyle(currentStyle(), true); |
347 | |
348 | //For now, ask all KDE apps to recreate their styles to apply the setitngs |
349 | KGlobalSettings::self()->emitChange(KGlobalSettings::StyleChanged); |
350 | |
351 | // We call setStyleDirty here to make sure we force style re-creation |
352 | setStyleDirty(); |
353 | } |
354 | |
355 | delete dial; |
356 | } |
357 | |
358 | void KCMStyle::changeEvent( QEvent *event ) |
359 | { |
360 | KCModule::changeEvent( event ); |
361 | if ( event->type() == QEvent::PaletteChange ) { |
362 | // Force re-rendering of the preview, to apply new palette |
363 | switchStyle(currentStyle(), true); |
364 | } |
365 | } |
366 | |
367 | void KCMStyle::load() |
368 | { |
369 | KConfig config( "kdeglobals" , KConfig::FullConfig ); |
370 | |
371 | loadStyle( config ); |
372 | loadEffects( config ); |
373 | |
374 | m_bStyleDirty= false; |
375 | m_bEffectsDirty = false; |
376 | //Enable/disable the button for the initial style |
377 | updateConfigButton(); |
378 | |
379 | emit changed( false ); |
380 | } |
381 | |
382 | |
383 | void KCMStyle::save() |
384 | { |
385 | // Don't do anything if we don't need to. |
386 | if ( !(m_bStyleDirty | m_bEffectsDirty ) ) |
387 | return; |
388 | |
389 | const bool = !QApplication::testAttribute(Qt::AA_DontShowIconsInMenus); |
390 | if (fineTuningUi.cbIconsInMenus->isChecked() != showMenuIcons) { |
391 | KMessageBox::information(this, |
392 | i18n("<p>Changes to the visibility of menu icons will only affect newly started applications.</p>" ), |
393 | i18nc("@title:window" , "Menu Icons Changed" ), "MenuIconsChanged" ); |
394 | } |
395 | |
396 | // Save effects. |
397 | KConfig _config("kdeglobals" , KConfig::NoGlobals); |
398 | KConfigGroup config(&_config, "KDE" ); |
399 | // Effects page |
400 | config.writeEntry( "ShowIconsOnPushButtons" , fineTuningUi.cbIconsOnButtons->isChecked()); |
401 | config.writeEntry( "ShowIconsInMenuItems" , fineTuningUi.cbIconsInMenus->isChecked()); |
402 | KConfigGroup g( &_config, "KDE-Global GUI Settings" ); |
403 | g.writeEntry( "GraphicEffectsLevel" , fineTuningUi.comboGraphicEffectsLevel->itemData(fineTuningUi.comboGraphicEffectsLevel->currentIndex())); |
404 | |
405 | KConfigGroup generalGroup(&_config, "General" ); |
406 | generalGroup.writeEntry("widgetStyle" , currentStyle()); |
407 | |
408 | KConfigGroup toolbarStyleGroup(&_config, "Toolbar style" ); |
409 | toolbarStyleGroup.writeEntry("ToolButtonStyle" , |
410 | toolbarButtonText(fineTuningUi.comboToolbarIcons->currentIndex())); |
411 | toolbarStyleGroup.writeEntry("ToolButtonStyleOtherToolbars" , |
412 | toolbarButtonText(fineTuningUi.comboSecondaryToolbarIcons->currentIndex())); |
413 | |
414 | // menubar page |
415 | KConfigGroup (&_config, "Appmenu Style" ); |
416 | |
417 | // load kded module if needed |
418 | bool load = false; |
419 | QList<QVariant> args; |
420 | |
421 | QString style = menuBarStyleText(fineTuningUi.comboMenubarStyle->currentIndex()); |
422 | |
423 | QString previous = menuBarStyleGroup.readEntry("Style" , "InApplication" ); |
424 | menuBarStyleGroup.writeEntry("Style" , style); |
425 | _config.sync(); |
426 | |
427 | QDBusMessage method = QDBusMessage::createMethodCall("org.kde.kded" , |
428 | "/modules/appmenu" , |
429 | "org.kde.kded" , |
430 | "reconfigure" ); |
431 | QDBusConnection::sessionBus().asyncCall(method); |
432 | |
433 | if (previous == "InApplication" && style != "InApplication" ) { |
434 | load = true; |
435 | KNotification *notification = new KNotification("reload" , 0); |
436 | notification->setComponentData(KComponentData("kcmstyle" )); |
437 | notification->setText(i18n("Settings changes will take effect only on application restart" )); |
438 | notification->sendEvent(); |
439 | } |
440 | |
441 | #ifdef Q_WS_X11 |
442 | // If user select ButtonVertical, we add (if needed) a button to titlebar |
443 | if (style == "ButtonVertical" ) { |
444 | KConfig _kwinConfig("kwinrc" , KConfig::NoGlobals); |
445 | KConfigGroup kwinConfig(&_kwinConfig, "Style" ); |
446 | QString buttonsOnLeft = kwinConfig.readEntry("ButtonsOnLeft" , KDecorationOptions::defaultTitleButtonsLeft()); |
447 | QString buttonsOnRight = kwinConfig.readEntry("ButtonsOnRight" , KDecorationOptions::defaultTitleButtonsRight()); |
448 | qDebug() << buttonsOnLeft << buttonsOnRight; |
449 | if (!buttonsOnLeft.contains("N" ) && !buttonsOnRight.contains("N" )) { |
450 | buttonsOnLeft = "N" + buttonsOnLeft; |
451 | } |
452 | kwinConfig.writeEntry("ButtonsOnLeft" , buttonsOnLeft); |
453 | kwinConfig.writeEntry("CustomButtonPositions" , "true" ); |
454 | } |
455 | #endif |
456 | |
457 | args = QList<QVariant>() << "appmenu" << (style != "InApplication" ); |
458 | method = QDBusMessage::createMethodCall("org.kde.kded" , |
459 | "/kded" , |
460 | "org.kde.kded" , |
461 | "setModuleAutoloading" ); |
462 | method.setArguments(args); |
463 | QDBusConnection::sessionBus().asyncCall(method); |
464 | |
465 | args = QList<QVariant>() << "appmenu" ; |
466 | if (load) { |
467 | method = QDBusMessage::createMethodCall("org.kde.kded" , |
468 | "/kded" , |
469 | "org.kde.kded" , |
470 | "loadModule" ); |
471 | QDBusMessage method = QDBusMessage::createMethodCall("org.kde.kded" , "/modules/appmenu" , "org.kde.kded" , "reconfigure" ); |
472 | QDBusConnection::sessionBus().asyncCall(method); |
473 | } else if (style == "InApplication" ) { |
474 | method = QDBusMessage::createMethodCall("org.kde.kded" , |
475 | "/kded" , |
476 | "org.kde.kded" , |
477 | "unloadModule" ); |
478 | } |
479 | method.setArguments(args); |
480 | QDBusConnection::sessionBus().asyncCall(method); |
481 | |
482 | // Export the changes we made to qtrc, and update all qt-only |
483 | // applications on the fly, ensuring that we still follow the user's |
484 | // export fonts/colors settings. |
485 | if (m_bStyleDirty | m_bEffectsDirty) // Export only if necessary |
486 | { |
487 | uint flags = KRdbExportQtSettings | KRdbExportGtkTheme; |
488 | KConfig _kconfig( "kcmdisplayrc" , KConfig::NoGlobals ); |
489 | KConfigGroup kconfig(&_kconfig, "X11" ); |
490 | bool exportKDEColors = kconfig.readEntry("exportKDEColors" , true); |
491 | if (exportKDEColors) |
492 | flags |= KRdbExportColors; |
493 | runRdb( flags ); |
494 | } |
495 | |
496 | // Now allow KDE apps to reconfigure themselves. |
497 | if ( m_bStyleDirty ) |
498 | KGlobalSettings::self()->emitChange(KGlobalSettings::StyleChanged); |
499 | |
500 | if ( m_bEffectsDirty ) { |
501 | KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_STYLE); |
502 | // ##### FIXME - Doesn't apply all settings correctly due to bugs in |
503 | // KApplication/KToolbar |
504 | KGlobalSettings::self()->emitChange(KGlobalSettings::ToolbarStyleChanged); |
505 | |
506 | #ifdef Q_WS_X11 |
507 | // Send signal to all kwin instances |
508 | QDBusMessage message = |
509 | QDBusMessage::createSignal("/KWin" , "org.kde.KWin" , "reloadConfig" ); |
510 | QDBusConnection::sessionBus().send(message); |
511 | #endif |
512 | } |
513 | |
514 | // Clean up |
515 | m_bStyleDirty = false; |
516 | m_bEffectsDirty = false; |
517 | emit changed( false ); |
518 | } |
519 | |
520 | |
521 | bool KCMStyle::findStyle( const QString& str, int& combobox_item ) |
522 | { |
523 | StyleEntry* se = styleEntries[str.toLower()]; |
524 | |
525 | QString name = se ? se->name : str; |
526 | |
527 | combobox_item = 0; |
528 | |
529 | //look up name |
530 | for( int i = 0; i < cbStyle->count(); i++ ) |
531 | { |
532 | if ( cbStyle->itemText(i) == name ) |
533 | { |
534 | combobox_item = i; |
535 | return true; |
536 | } |
537 | } |
538 | |
539 | return false; |
540 | } |
541 | |
542 | |
543 | void KCMStyle::defaults() |
544 | { |
545 | // Select default style |
546 | int item = 0; |
547 | bool found; |
548 | |
549 | found = findStyle( KStyle::defaultStyle(), item ); |
550 | if (!found) |
551 | found = findStyle( "plastique" , item ); |
552 | if (!found) |
553 | found = findStyle( "windows" , item ); |
554 | if (!found) |
555 | found = findStyle( "platinum" , item ); |
556 | if (!found) |
557 | found = findStyle( "motif" , item ); |
558 | |
559 | cbStyle->setCurrentIndex( item ); |
560 | |
561 | m_bStyleDirty = true; |
562 | switchStyle( currentStyle() ); // make resets visible |
563 | |
564 | // Effects |
565 | fineTuningUi.comboToolbarIcons->setCurrentIndex(toolbarButtonIndex("TextBesideIcon" )); |
566 | fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex("TextBesideIcon" )); |
567 | fineTuningUi.comboMenubarStyle->setCurrentIndex(menuBarStyleIndex("InApplication" )); |
568 | fineTuningUi.cbIconsOnButtons->setChecked(true); |
569 | fineTuningUi.cbIconsInMenus->setChecked(true); |
570 | fineTuningUi.comboGraphicEffectsLevel->setCurrentIndex(fineTuningUi.comboGraphicEffectsLevel->findData(((int) KGlobalSettings::graphicEffectsLevelDefault()))); |
571 | emit changed(true); |
572 | } |
573 | |
574 | void KCMStyle::setEffectsDirty() |
575 | { |
576 | m_bEffectsDirty = true; |
577 | emit changed(true); |
578 | } |
579 | |
580 | void KCMStyle::setStyleDirty() |
581 | { |
582 | m_bStyleDirty = true; |
583 | emit changed(true); |
584 | } |
585 | |
586 | // ---------------------------------------------------------------- |
587 | // All the Style Switching / Preview stuff |
588 | // ---------------------------------------------------------------- |
589 | |
590 | void KCMStyle::loadStyle( KConfig& config ) |
591 | { |
592 | cbStyle->clear(); |
593 | // Create a dictionary of WidgetStyle to Name and Desc. mappings, |
594 | // as well as the config page info |
595 | qDeleteAll(styleEntries); |
596 | styleEntries.clear(); |
597 | |
598 | QString strWidgetStyle; |
599 | QStringList list = KGlobal::dirs()->findAllResources("themes" , "*.themerc" , |
600 | KStandardDirs::Recursive | |
601 | KStandardDirs::NoDuplicates); |
602 | for (QStringList::iterator it = list.begin(); it != list.end(); ++it) |
603 | { |
604 | KConfig config( *it, KConfig::SimpleConfig); |
605 | if ( !(config.hasGroup("KDE" ) && config.hasGroup("Misc" )) ) |
606 | continue; |
607 | |
608 | KConfigGroup configGroup = config.group("KDE" ); |
609 | |
610 | strWidgetStyle = configGroup.readEntry("WidgetStyle" ); |
611 | if (strWidgetStyle.isNull()) |
612 | continue; |
613 | |
614 | // We have a widgetstyle, so lets read the i18n entries for it... |
615 | StyleEntry* entry = new StyleEntry; |
616 | configGroup = config.group("Misc" ); |
617 | entry->name = configGroup.readEntry("Name" ); |
618 | entry->desc = configGroup.readEntry("Comment" , i18n("No description available." )); |
619 | entry->configPage = configGroup.readEntry("ConfigPage" , QString()); |
620 | |
621 | // Check if this style should be shown |
622 | configGroup = config.group("Desktop Entry" ); |
623 | entry->hidden = configGroup.readEntry("Hidden" , false); |
624 | |
625 | // Insert the entry into our dictionary. |
626 | styleEntries.insert(strWidgetStyle.toLower(), entry); |
627 | } |
628 | |
629 | // Obtain all style names |
630 | QStringList allStyles = QStyleFactory::keys(); |
631 | |
632 | // Get translated names, remove all hidden style entries. |
633 | QStringList styles; |
634 | StyleEntry* entry; |
635 | for (QStringList::iterator it = allStyles.begin(); it != allStyles.end(); ++it) |
636 | { |
637 | QString id = (*it).toLower(); |
638 | // Find the entry. |
639 | if ( (entry = styleEntries[id]) != 0 ) |
640 | { |
641 | // Do not add hidden entries |
642 | if (entry->hidden) |
643 | continue; |
644 | |
645 | styles += entry->name; |
646 | |
647 | nameToStyleKey[entry->name] = id; |
648 | } |
649 | else |
650 | { |
651 | styles += (*it); //Fall back to the key (but in original case) |
652 | nameToStyleKey[*it] = id; |
653 | } |
654 | } |
655 | |
656 | // Sort the style list, and add it to the combobox |
657 | styles.sort(); |
658 | cbStyle->addItems( styles ); |
659 | |
660 | // Find out which style is currently being used |
661 | KConfigGroup configGroup = config.group( "General" ); |
662 | QString defaultStyle = KStyle::defaultStyle(); |
663 | QString cfgStyle = configGroup.readEntry( "widgetStyle" , defaultStyle ); |
664 | |
665 | // Select the current style |
666 | // Do not use cbStyle->listBox() as this may be NULL for some styles when |
667 | // they use QPopupMenus for the drop-down list! |
668 | |
669 | // ##### Since Trolltech likes to seemingly copy & paste code, |
670 | // QStringList::findItem() doesn't have a Qt::StringComparisonMode field. |
671 | // We roll our own (yuck) |
672 | cfgStyle = cfgStyle.toLower(); |
673 | int item = 0; |
674 | for( int i = 0; i < cbStyle->count(); i++ ) |
675 | { |
676 | QString id = nameToStyleKey[cbStyle->itemText(i)]; |
677 | item = i; |
678 | if ( id == cfgStyle ) // ExactMatch |
679 | break; |
680 | else if ( id.contains( cfgStyle ) ) |
681 | break; |
682 | else if ( id.contains( QApplication::style()->metaObject()->className() ) ) |
683 | break; |
684 | item = 0; |
685 | } |
686 | cbStyle->setCurrentIndex( item ); |
687 | m_bStyleDirty = false; |
688 | |
689 | switchStyle( currentStyle() ); // make resets visible |
690 | } |
691 | |
692 | QString KCMStyle::currentStyle() |
693 | { |
694 | return nameToStyleKey[cbStyle->currentText()]; |
695 | } |
696 | |
697 | |
698 | void KCMStyle::styleChanged() |
699 | { |
700 | switchStyle( currentStyle() ); |
701 | } |
702 | |
703 | |
704 | void KCMStyle::switchStyle(const QString& styleName, bool force) |
705 | { |
706 | // Don't flicker the preview if the same style is chosen in the cb |
707 | if (!force && appliedStyle && appliedStyle->objectName() == styleName) |
708 | return; |
709 | |
710 | // Create an instance of the new style... |
711 | QStyle* style = QStyleFactory::create(styleName); |
712 | if (!style) |
713 | return; |
714 | |
715 | // Prevent Qt from wrongly caching radio button images |
716 | QPixmapCache::clear(); |
717 | |
718 | setStyleRecursive( stylePreview, style ); |
719 | |
720 | // this flickers, but reliably draws the widgets correctly. |
721 | stylePreview->resize( stylePreview->sizeHint() ); |
722 | |
723 | delete appliedStyle; |
724 | appliedStyle = style; |
725 | |
726 | // Set the correct style description |
727 | StyleEntry* entry = styleEntries[ styleName ]; |
728 | QString desc; |
729 | desc = i18n("Description: %1" , entry ? entry->desc : i18n("No description available." ) ); |
730 | lblStyleDesc->setText( desc ); |
731 | } |
732 | |
733 | void KCMStyle::setStyleRecursive(QWidget* w, QStyle* s) |
734 | { |
735 | // Don't let broken styles kill the palette |
736 | // for other styles being previewed. (e.g SGI style) |
737 | w->setPalette(QPalette()); |
738 | |
739 | QPalette newPalette(KGlobalSettings::createApplicationPalette()); |
740 | s->polish( newPalette ); |
741 | w->setPalette(newPalette); |
742 | |
743 | // Apply the new style. |
744 | w->setStyle(s); |
745 | |
746 | // Recursively update all children. |
747 | const QObjectList children = w->children(); |
748 | |
749 | // Apply the style to each child widget. |
750 | foreach (QObject* child, children) |
751 | { |
752 | if (child->isWidgetType()) |
753 | setStyleRecursive((QWidget *) child, s); |
754 | } |
755 | } |
756 | |
757 | // ---------------------------------------------------------------- |
758 | // All the Effects stuff |
759 | // ---------------------------------------------------------------- |
760 | QString KCMStyle::toolbarButtonText(int index) |
761 | { |
762 | switch (index) { |
763 | case 1: |
764 | return "TextOnly" ; |
765 | case 2: |
766 | return "TextBesideIcon" ; |
767 | case 3: |
768 | return "TextUnderIcon" ; |
769 | default: |
770 | break; |
771 | } |
772 | |
773 | return "NoText" ; |
774 | } |
775 | |
776 | int KCMStyle::toolbarButtonIndex(const QString &text) |
777 | { |
778 | if (text == "TextOnly" ) { |
779 | return 1; |
780 | } else if (text == "TextBesideIcon" ) { |
781 | return 2; |
782 | } else if (text == "TextUnderIcon" ) { |
783 | return 3; |
784 | } |
785 | |
786 | return 0; |
787 | } |
788 | |
789 | QString KCMStyle::(int index) |
790 | { |
791 | switch (index) { |
792 | case 1: |
793 | return "ButtonVertical" ; |
794 | case 2: |
795 | return "TopMenuBar" ; |
796 | case 3: |
797 | return "Others" ; |
798 | } |
799 | |
800 | return "InApplication" ; |
801 | } |
802 | |
803 | int KCMStyle::(const QString &text) |
804 | { |
805 | if (text == "ButtonVertical" ) { |
806 | return 1; |
807 | } else if (text == "TopMenuBar" ) { |
808 | return 2; |
809 | } else if (text == "Others" ) { |
810 | return 3; |
811 | } |
812 | |
813 | return 0; |
814 | } |
815 | |
816 | void KCMStyle::loadEffects( KConfig& config ) |
817 | { |
818 | // KDE's Part via KConfig |
819 | KConfigGroup configGroup = config.group("Toolbar style" ); |
820 | |
821 | QString tbIcon = configGroup.readEntry("ToolButtonStyle" , "TextBesideIcon" ); |
822 | fineTuningUi.comboToolbarIcons->setCurrentIndex(toolbarButtonIndex(tbIcon)); |
823 | tbIcon = configGroup.readEntry("ToolButtonStyleOtherToolbars" , "TextBesideIcon" ); |
824 | fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex(tbIcon)); |
825 | |
826 | configGroup = config.group("Appmenu Style" ); |
827 | QString = configGroup.readEntry("Style" , "InApplication" ); |
828 | fineTuningUi.comboMenubarStyle->setCurrentIndex(menuBarStyleIndex(menuBarStyle)); |
829 | |
830 | configGroup = config.group("KDE" ); |
831 | fineTuningUi.cbIconsOnButtons->setChecked(configGroup.readEntry("ShowIconsOnPushButtons" , true)); |
832 | fineTuningUi.cbIconsInMenus->setChecked(configGroup.readEntry("ShowIconsInMenuItems" , true)); |
833 | |
834 | KConfigGroup graphicConfigGroup = config.group("KDE-Global GUI Settings" ); |
835 | fineTuningUi.comboGraphicEffectsLevel->setCurrentIndex(fineTuningUi.comboGraphicEffectsLevel->findData(graphicConfigGroup.readEntry("GraphicEffectsLevel" , ((int) KGlobalSettings::graphicEffectsLevel())))); |
836 | |
837 | m_bEffectsDirty = false; |
838 | } |
839 | |
840 | void KCMStyle::addWhatsThis() |
841 | { |
842 | // Page1 |
843 | cbStyle->setWhatsThis( i18n("Here you can choose from a list of" |
844 | " predefined widget styles (e.g. the way buttons are drawn) which" |
845 | " may or may not be combined with a theme (additional information" |
846 | " like a marble texture or a gradient)." ) ); |
847 | stylePreview->setWhatsThis( i18n("This area shows a preview of the currently selected style " |
848 | "without having to apply it to the whole desktop." ) ); |
849 | // Page2 |
850 | page2->setWhatsThis( i18n("This page allows you to choose details about the widget style options" ) ); |
851 | fineTuningUi.comboToolbarIcons->setWhatsThis( i18n( "<p><b>No Text:</b> Shows only icons on toolbar buttons. " |
852 | "Best option for low resolutions.</p>" |
853 | "<p><b>Text Only: </b>Shows only text on toolbar buttons.</p>" |
854 | "<p><b>Text Beside Icons: </b> Shows icons and text on toolbar buttons. " |
855 | "Text is aligned beside the icon.</p>" |
856 | "<b>Text Below Icons: </b> Shows icons and text on toolbar buttons. " |
857 | "Text is aligned below the icon." ) ); |
858 | fineTuningUi.cbIconsOnButtons->setWhatsThis( i18n( "If you enable this option, KDE Applications will " |
859 | "show small icons alongside some important buttons." ) ); |
860 | fineTuningUi.cbIconsInMenus->setWhatsThis( i18n( "If you enable this option, KDE Applications will " |
861 | "show small icons alongside most menu items." ) ); |
862 | fineTuningUi.comboGraphicEffectsLevel->setWhatsThis( i18n( "If you enable this option, KDE Applications will " |
863 | "run internal animations." ) ); |
864 | } |
865 | |
866 | #include "kcmstyle.moc" |
867 | |
868 | // vim: set noet ts=4: |
869 | |