FrameworkIntegration

kstyle.cpp
1/**
2 KStyle for KDE4
3 SPDX-FileCopyrightText: 2004-2005 Maksim Orlovich <maksim@kde.org>
4 SPDX-FileCopyrightText: 2005, 2006 Sandro Giessl <giessl@kde.org>
5
6 Based in part on the following software:
7
8 KStyle for KDE3
9 SPDX-FileCopyrightText: 2001-2002 Karol Szwed <gallium@kde.org>
10 Portions:
11 SPDX-FileCopyrightText: 1998-2000 TrollTech AS
12
13 Keramik for KDE3,
14 SPDX-FileCopyrightText: 2002 Malte Starostik <malte@kde.org>
15 SPDX-FileCopyrightText: 2002-2003 Maksim Orlovich<maksim@kde.org>
16 Portions:
17 SPDX-FileCopyrightText: 2001-2002 Karol Szwed <gallium@kde.org>
18 SPDX-FileCopyrightText: 2001-2002 Fredrik Höglund <fredrik@kde.org>
19 SPDX-FileCopyrightText: 2000 Daniel M. Duley <mosfet@kde.org>
20 SPDX-FileCopyrightText: 2000 Dirk Mueller <mueller@kde.org>
21 SPDX-FileCopyrightText: 2001 Martijn Klingens <klingens@kde.org>
22 SPDX-FileCopyrightText: 2003 Sandro Giessl <sandro@giessl.com>
23
24 Many thanks to Bradley T. Hughes for the 3 button scrollbar code.
25
26 SPDX-License-Identifier: LGPL-2.0-or-later
27*/
28
29#include "kstyle.h"
30
31#include <QAbstractItemView>
32#include <QApplication>
33#include <QDialogButtonBox>
34#include <QEvent>
35#include <QIcon>
36#include <QPushButton>
37#include <QShortcut>
38#include <QStyleOption>
39#include <QToolBar>
40
41#include <KColorScheme>
42#include <KConfigGroup>
43#include <KIconLoader>
44#include <KMessageWidget>
45
46// ----------------------------------------------------------------------------
47
48static const QStyle::StyleHint SH_KCustomStyleElement = (QStyle::StyleHint)0xff000001;
49static const int X_KdeBase = 0xff000000;
50
51class KStylePrivate
52{
53public:
54 KStylePrivate();
55
56 QHash<QString, int> styleElements;
57 int hintCounter, controlCounter, subElementCounter;
58};
59
60KStylePrivate::KStylePrivate()
61{
62 controlCounter = subElementCounter = X_KdeBase;
63 hintCounter = X_KdeBase + 1; // sic! X_KdeBase is covered by SH_KCustomStyleElement
64}
65
66/*
67 The functions called by widgets that request custom element support, passed to the effective style.
68 Collected in a static inline function due to similarity.
69*/
70
71static inline int customStyleElement(QStyle::StyleHint type, const QString &element, QWidget *widget)
72{
73 if (!widget || widget->style()->metaObject()->indexOfClassInfo("X-KDE-CustomElements") < 0) {
74 return 0;
75 }
76
77 const QString originalName = widget->objectName();
78 widget->setObjectName(element);
79 const int id = widget->style()->styleHint(type, nullptr, widget);
80 widget->setObjectName(originalName);
81 return id;
82}
83
85{
86 return (StyleHint)customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
87}
88
89QStyle::ControlElement KStyle::customControlElement(const QString &element, const QWidget *widget)
90{
91 return (ControlElement)customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
92}
93
94QStyle::SubElement KStyle::customSubElement(const QString &element, const QWidget *widget)
95{
96 return (SubElement)customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
97}
98
99KStyle::KStyle()
100 : d(new KStylePrivate)
101{
102}
103
104KStyle::~KStyle()
105{
106 delete d;
107}
108
109/*
110 Custom Style Element runtime extension:
111 We reserve one StyleHint to let the effective style inform widgets whether it supports certain
112 string based style elements.
113 As this could lead to number conflicts (i.e. an app utilizing one of the hints itself for other
114 purposes) there're various safety mechanisms to rule out such interference.
115
116 1) It's most unlikely that a widget in some 3rd party app will accidentally call a general
117 QStyle/KStyle styleHint() or draw*() and (unconditionally) expect a valid return, however:
118 a. The StyleHint is not directly above Qt's custom base, assuming most 3rd party apps would
119 - in case - make use of such
120 b. In order to be accepted, the StyleHint query must pass a widget with a perfectly matching
121 name, containing the typical element prefix ("CE_", etc.) and being supported by the current style
122 c. Instead using Qt's fragile qstyleoption_cast on the QStyleOption provided to the StyleHint
123 query, try to dump out a string and hope for the best, we now manipulate the widgets objectName().
124 Plain Qt dependent widgets can do that themselves and if a widget uses KStyle's convenience access
125 functions, it won't notice this at all
126
127 2) The key problem is that a common KDE widget will run into an apps custom style which will then
128 falsely respond to the styleHint() call with an invalid value.
129 To prevent this, supporting styles *must* set a Q_CLASSINFO "X-KDE-CustomElements".
130
131 3) If any of the above traps snaps, the returned id is 0 - the QStyle default, indicating
132 that this element is not supported by the current style.
133
134 Obviously, this contains the "diminished clean" action to (temporarily) manipulate the
135 objectName() of a const QWidget* - but this happens completely inside KStyle or the widget, if
136 it does not make use of KStyles static convenience functions.
137 My biggest worry here would be, that in a multithreaded environment a thread (usually not being
138 owner of the widget) does something crucially relying on the widgets name property...
139 This however would also have to happen during the widget construction or stylechanges, when
140 the functions in doubt will typically be called.
141 So this is imho unlikely causing any trouble, ever.
142*/
143
144/*
145 The functions called by the real style implementation to add support for a certain element.
146 Checks for well-formed string (containing the element prefix) and returns 0 otherwise.
147 Checks whether the element is already supported or inserts it otherwise; Returns the proper id
148 NOTICE: We could check for "X-KDE-CustomElements", but this would bloat style start up times
149 (if they e.g. register 100 elements or so)
150*/
151
152static inline int newStyleElement(const QString &element, const char *check, int &counter, QHash<QString, int> *elements)
153{
154 if (!element.contains(QLatin1String(check))) {
155 return 0;
156 }
157 int id = elements->value(element, 0);
158 if (!id) {
159 ++counter;
160 id = counter;
161 elements->insert(element, id);
162 }
163 return id;
164}
165
167{
168 return (StyleHint)newStyleElement(element, "SH_", d->hintCounter, &d->styleElements);
169}
170
171QStyle::ControlElement KStyle::newControlElement(const QString &element)
172{
173 return (ControlElement)newStyleElement(element, "CE_", d->controlCounter, &d->styleElements);
174}
175
176KStyle::SubElement KStyle::newSubElement(const QString &element)
177{
178 return (SubElement)newStyleElement(element, "SE_", d->subElementCounter, &d->styleElements);
179}
180
181void KStyle::polish(QWidget *w)
182{
183 // Enable hover effects in all itemviews
184 if (QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(w)) {
185 itemView->viewport()->setAttribute(Qt::WA_Hover);
186 }
187
188 if (QDialogButtonBox *box = qobject_cast<QDialogButtonBox *>(w)) {
189 QPushButton *button = box->button(QDialogButtonBox::Ok);
190
191 if (button) {
192 auto shortcut = new QShortcut(Qt::CTRL | Qt::Key_Return, button);
194 }
195 }
196 if (auto messageWidget = qobject_cast<KMessageWidget *>(w)) {
197 KColorScheme scheme;
198 QColor color;
199 QPalette palette = messageWidget->palette();
200 switch (messageWidget->messageType()) {
203 break;
205 color = scheme.foreground(KColorScheme::ActiveText).color();
206 break;
209 break;
212 break;
213 }
214 palette.setColor(QPalette::Window, color);
215 messageWidget->setPalette(palette);
216 }
218}
219
224
225QIcon KStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const
226{
227 switch (standardIcon) {
229 return QIcon::fromTheme(QStringLiteral("user-desktop"));
231 return QIcon::fromTheme(QStringLiteral("user-trash"));
233 return QIcon::fromTheme(QStringLiteral("computer"));
235 return QIcon::fromTheme(QStringLiteral("media-floppy"));
237 return QIcon::fromTheme(QStringLiteral("drive-harddisk"));
240 return QIcon::fromTheme(QStringLiteral("drive-optical"));
242 return QIcon::fromTheme(QStringLiteral("folder-remote"));
244 return QIcon::fromTheme(QStringLiteral("user-home"));
246 return QIcon::fromTheme(QStringLiteral("document-open-folder"));
248 return QIcon::fromTheme(QStringLiteral("folder"));
250 return QIcon::fromTheme(QStringLiteral("folder"));
252 return QIcon::fromTheme(QStringLiteral("folder")); // TODO: generate (!?) folder with link emblem
254 return QIcon::fromTheme(QStringLiteral("text-plain")); // TODO: look for a better icon
256 return QIcon::fromTheme(QStringLiteral("text-plain")); // TODO: generate (!?) file with link emblem
258 return QIcon::fromTheme(QStringLiteral("media-playback-start")); // TODO: find correct icon
260 return QIcon::fromTheme(QStringLiteral("media-playback-stop")); // TODO: find correct icon
262 return QIcon::fromTheme(QStringLiteral("go-up"));
264 return QIcon::fromTheme(QStringLiteral("folder-new"));
266 return QIcon::fromTheme(QStringLiteral("view-list-details"));
268 return QIcon::fromTheme(QStringLiteral("document-properties"));
270 return QIcon::fromTheme(QStringLiteral("view-list-icons"));
272 return QIcon::fromTheme(QStringLiteral("view-list-text"));
274 return QIcon::fromTheme(QStringLiteral("go-previous"));
276 return QIcon::fromTheme(QStringLiteral("dialog-information"));
278 return QIcon::fromTheme(QStringLiteral("dialog-warning"));
280 return QIcon::fromTheme(QStringLiteral("dialog-error"));
282 // This used to be dialog-information for a long time, so keep it as a fallback
283 return QIcon::fromTheme(QStringLiteral("dialog-question"), QIcon::fromTheme(QStringLiteral("dialog-information")));
285 return QIcon::fromTheme(QStringLiteral("dialog-ok"));
287 return QIcon::fromTheme(QStringLiteral("dialog-cancel"));
289 return QIcon::fromTheme(QStringLiteral("help-contents"));
291 return QIcon::fromTheme(QStringLiteral("document-open"));
293 return QIcon::fromTheme(QStringLiteral("document-save"));
295 return QIcon::fromTheme(QStringLiteral("dialog-close"));
297 return QIcon::fromTheme(QStringLiteral("dialog-ok-apply"));
299 return QIcon::fromTheme(QStringLiteral("edit-undo"));
301 return QIcon::fromTheme(QStringLiteral("edit-delete"));
303 return QIcon::fromTheme(QStringLiteral("dialog-ok-apply"));
305 return QIcon::fromTheme(QStringLiteral("dialog-cancel"));
307 return QIcon::fromTheme(QStringLiteral("go-up"));
309 return QIcon::fromTheme(QStringLiteral("go-down"));
311 return QIcon::fromTheme(QStringLiteral("go-previous-view"));
313 return QIcon::fromTheme(QStringLiteral("go-next-view"));
315 return QIcon::fromTheme(QStringLiteral("go-previous"));
317 return QIcon::fromTheme(QStringLiteral("go-next"));
319 return QIcon::fromTheme(QStringLiteral("view-refresh"));
321 return QIcon::fromTheme(QStringLiteral("process-stop"));
323 return QIcon::fromTheme(QStringLiteral("media-playback-start"));
325 return QIcon::fromTheme(QStringLiteral("media-playback-stop"));
327 return QIcon::fromTheme(QStringLiteral("media-playback-pause"));
329 return QIcon::fromTheme(QStringLiteral("media-skip-forward"));
331 return QIcon::fromTheme(QStringLiteral("media-skip-backward"));
333 return QIcon::fromTheme(QStringLiteral("media-seek-forward"));
335 return QIcon::fromTheme(QStringLiteral("media-seek-backward"));
337 return QIcon::fromTheme(QStringLiteral("audio-volume-medium"));
339 return QIcon::fromTheme(QStringLiteral("audio-volume-muted"));
341 const bool rtl = (option && option->direction == Qt::RightToLeft) || (!option && QApplication::isRightToLeft());
342
343 const QString directionalThemeName = rtl ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl");
344
345 return QIcon::fromTheme(directionalThemeName, QIcon::fromTheme(QStringLiteral("edit-clear")));
346 }
348 return QIcon::fromTheme(QStringLiteral("dialog-ok"));
350 return QIcon::fromTheme(QStringLiteral("dialog-cancel"));
352 return QIcon::fromTheme(QStringLiteral("document-save-all"));
354 return QIcon::fromTheme(QStringLiteral("dialog-cancel"));
356 return QIcon::fromTheme(QStringLiteral("view-refresh"));
358 return QIcon::fromTheme(QStringLiteral("dialog-cancel"));
360 return QIcon::fromTheme(QStringLiteral("document-revert"));
361
362 default:
363 break;
364 }
365
366 return QCommonStyle::standardIcon(standardIcon, option, widget);
367}
368
369int KStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
370{
371 switch (hint) {
373 // was KGlobalSettings::showIconsOnPushButtons() :
374 KConfigGroup g(KSharedConfig::openConfig(), QStringLiteral("KDE"));
375 return g.readEntry("ShowIconsOnPushButtons", true);
376 }
377
379 return true;
380
381 case SH_Widget_Animate: {
382 KConfigGroup g(KSharedConfig::openConfig(), QStringLiteral("KDE-Global GUI Settings"));
383 return g.readEntry("GraphicEffectsLevel", true);
384 }
385
387 return 300;
388
389 case SH_ToolButtonStyle: {
390 KConfigGroup g(KSharedConfig::openConfig(), QStringLiteral("Toolbar style"));
391
392 bool useOthertoolbars = false;
393 const QWidget *parent = widget ? widget->parentWidget() : nullptr;
394
395 // If the widget parent is a QToolBar and the magic property is set
396 if (parent && qobject_cast<const QToolBar *>(parent)) {
397 if (parent->property("otherToolbar").isValid()) {
398 useOthertoolbars = true;
399 }
400 }
401
402 QString buttonStyle;
403 if (useOthertoolbars) {
404 buttonStyle = g.readEntry("ToolButtonStyleOtherToolbars", "NoText").toLower();
405 } else {
406 buttonStyle = g.readEntry("ToolButtonStyle", "TextBesideIcon").toLower();
407 }
408
409 return buttonStyle == QLatin1String("textbesideicon") ? Qt::ToolButtonTextBesideIcon
410 : buttonStyle == QLatin1String("icontextright") ? Qt::ToolButtonTextBesideIcon
411 : buttonStyle == QLatin1String("textundericon") ? Qt::ToolButtonTextUnderIcon
412 : buttonStyle == QLatin1String("icontextbottom") ? Qt::ToolButtonTextUnderIcon
413 : buttonStyle == QLatin1String("textonly") ? Qt::ToolButtonTextOnly
415 }
416
417 case SH_KCustomStyleElement:
418 if (!widget) {
419 return 0;
420 }
421
422 return d->styleElements.value(widget->objectName(), 0);
423
425 KConfigGroup g(KSharedConfig::openConfig(), QStringLiteral("KDE"));
426 return !g.readEntry("ScrollbarLeftClickNavigatesByPage", false);
427 }
428
429 default:
430 break;
431 };
432
433 return QCommonStyle::styleHint(hint, option, widget, returnData);
434}
435
436int KStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
437{
438 switch (metric) {
439 case PM_SmallIconSize:
442
445
446 case PM_LargeIconSize:
448
450 // TODO return KIconLoader::global()->currentSize(KIconLoader::MessageBox);
452 default:
453 break;
454 }
455
456 return QCommonStyle::pixelMetric(metric, option, widget);
457}
458
459#include "moc_kstyle.cpp"
static QPalette createApplicationPalette(const KSharedConfigPtr &config)
QBrush foreground(ForegroundRole=NormalText) const
int currentSize(KIconLoader::Group group) const
static KIconLoader * global()
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static StyleHint customStyleHint(const QString &element, const QWidget *widget)
Runtime element extension This is just convenience and does /not/ require the using widgets style to ...
Definition kstyle.cpp:84
QPalette standardPalette() const override
needed to avoid warnings at compilation time
Definition kstyle.cpp:220
StyleHint newStyleHint(const QString &element)
Runtime element extension, allows inheriting styles to add support custom elements merges supporting ...
Definition kstyle.cpp:166
const QList< QKeySequence > & shortcut(StandardShortcut id)
const QColor & color() const const
virtual int pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *widget) const const override
virtual void polish(QApplication *app) override
virtual int styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *hret) const const override
bool isRightToLeft()
iterator insert(const Key &key, const T &value)
T value(const Key &key) const const
QIcon fromTheme(const QString &name)
int indexOfClassInfo(const char *name) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual const QMetaObject * metaObject() const const
QObject * parent() const const
QVariant property(const char *name) const const
void setObjectName(QAnyStringView name)
void setColor(ColorGroup group, ColorRole role, const QColor &color)
void activated()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString toLower() const const
PM_SmallIconSize
virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const const=0
virtual int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const const=0
Key_Return
RightToLeft
ToolButtonTextBesideIcon
WA_Hover
bool isValid() const const
QWidget * parentWidget() const const
QStyle * style() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.