FrameworkIntegration

kstyle.cpp
1 /**
2  KStyle for KDE4
3  SPDX-FileCopyrightText: 2004-2005 Maksim Orlovich <[email protected]>
4  SPDX-FileCopyrightText: 2005, 2006 Sandro Giessl <[email protected]>
5 
6  Based in part on the following software:
7 
8  KStyle for KDE3
9  SPDX-FileCopyrightText: 2001-2002 Karol Szwed <[email protected]>
10  Portions:
11  SPDX-FileCopyrightText: 1998-2000 TrollTech AS
12 
13  Keramik for KDE3,
14  SPDX-FileCopyrightText: 2002 Malte Starostik <[email protected]>
15  SPDX-FileCopyrightText: 2002-2003 Maksim Orlovich<[email protected]>
16  Portions:
17  SPDX-FileCopyrightText: 2001-2002 Karol Szwed <[email protected]>
18  SPDX-FileCopyrightText: 2001-2002 Fredrik Höglund <[email protected]>
19  SPDX-FileCopyrightText: 2000 Daniel M. Duley <[email protected]>
20  SPDX-FileCopyrightText: 2000 Dirk Mueller <[email protected]>
21  SPDX-FileCopyrightText: 2001 Martijn Klingens <[email protected]>
22  SPDX-FileCopyrightText: 2003 Sandro Giessl <[email protected]>
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 
48 static const QStyle::StyleHint SH_KCustomStyleElement = (QStyle::StyleHint)0xff000001;
49 static const int X_KdeBase = 0xff000000;
50 
51 class KStylePrivate
52 {
53 public:
54  KStylePrivate();
55 
56  QHash<QString, int> styleElements;
57  int hintCounter, controlCounter, subElementCounter;
58 };
59 
60 KStylePrivate::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 
71 static 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 
89 QStyle::ControlElement KStyle::customControlElement(const QString &element, const QWidget *widget)
90 {
91  return (ControlElement)customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
92 }
93 
94 QStyle::SubElement KStyle::customSubElement(const QString &element, const QWidget *widget)
95 {
96  return (SubElement)customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
97 }
98 
99 KStyle::KStyle()
100  : d(new KStylePrivate)
101 {
102 }
103 
104 KStyle::~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 
152 static inline int newStyleElement(const QString &element, const char *check, int &counter, QHash<QString, int> *elements)
153 {
154  if (!element.contains(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 
171 QStyle::ControlElement KStyle::newControlElement(const QString &element)
172 {
173  return (ControlElement)newStyleElement(element, "CE_", d->controlCounter, &d->styleElements);
174 }
175 
176 KStyle::SubElement KStyle::newSubElement(const QString &element)
177 {
178  return (SubElement)newStyleElement(element, "SE_", d->subElementCounter, &d->styleElements);
179 }
180 
181 void 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()) {
201  case KMessageWidget::Positive:
202  color = scheme.foreground(KColorScheme::PositiveText).color();
203  break;
204  case KMessageWidget::Information:
205  color = scheme.foreground(KColorScheme::ActiveText).color();
206  break;
207  case KMessageWidget::Warning:
208  color = scheme.foreground(KColorScheme::NeutralText).color();
209  break;
210  case KMessageWidget::Error:
211  color = scheme.foreground(KColorScheme::NegativeText).color();
212  break;
213  }
214  palette.setColor(QPalette::Window, color);
215  messageWidget->setPalette(palette);
216  }
218 }
219 
221 {
223 }
224 
225 QIcon 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"));
249  case QStyle::SP_DirIcon:
250  return QIcon::fromTheme(QStringLiteral("folder"));
252  return QIcon::fromTheme(QStringLiteral("folder")); // TODO: generate (!?) folder with link emblem
253  case QStyle::SP_FileIcon:
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"));
306  case QStyle::SP_ArrowUp:
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"));
340  case SP_LineEditClearButton: {
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 
369 int KStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
370 {
371  switch (hint) {
372  case SH_DialogButtonBox_ButtonsHaveIcons: {
373  // was KGlobalSettings::showIconsOnPushButtons() :
375  return g.readEntry("ShowIconsOnPushButtons", true);
376  }
377 
378  case SH_ItemView_ArrowKeysNavigateIntoChildren:
379  return true;
380 
381  case SH_Widget_Animate: {
382  KConfigGroup g(KSharedConfig::openConfig(), "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(), "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 
424  case SH_ScrollBar_LeftClickAbsolutePosition: {
426  return !g.readEntry("ScrollbarLeftClickNavigatesByPage", true);
427  }
428 
429  default:
430  break;
431  };
432 
433  return QCommonStyle::styleHint(hint, option, widget, returnData);
434 }
435 
436 int KStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
437 {
438  switch (metric) {
439  case PM_SmallIconSize:
440  case PM_ButtonIconSize:
442 
443  case PM_ToolBarIconSize:
445 
446  case PM_LargeIconSize:
448 
449  case PM_MessageBoxIconSize:
450  // TODO return KIconLoader::global()->currentSize(KIconLoader::MessageBox);
451  return KIconLoader::SizeHuge;
452  default:
453  break;
454  }
455 
456  return QCommonStyle::pixelMetric(metric, option, widget);
457 }
bool isRightToLeft()
QHash::iterator insert(const Key &key, const T &value)
int currentSize(KIconLoader::Group group) const
StyleHint newStyleHint(const QString &element)
Runtime element extension, allows inheriting styles to add support custom elements merges supporting ...
Definition: kstyle.cpp:166
virtual void polish(QPalette &pal) override
void setColor(QPalette::ColorGroup group, QPalette::ColorRole role, const QColor &color)
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
QStyle * style() const const
virtual const QMetaObject * metaObject() const const
RightToLeft
const QColor & color() const const
QBrush foreground(ForegroundRole=NormalText) const
virtual int pixelMetric(QStyle::PixelMetric m, const QStyleOption *opt, const QWidget *widget) const const override
QVariant property(const char *name) const const
virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const const =0
ToolButtonTextBesideIcon
int indexOfClassInfo(const char *name) const const
static KIconLoader * global()
static QPalette createApplicationPalette(const KSharedConfigPtr &config)
const T value(const Key &key) const const
virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const const =0
void activated()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
WA_Hover
QWidget * parentWidget() const const
bool isValid() const const
QIcon fromTheme(const QString &name)
virtual int styleHint(QStyle::StyleHint sh, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *hret) const const override
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QPalette standardPalette() const override
needed to avoid warnings at compilation time
Definition: kstyle.cpp:220
T readEntry(const QString &key, const T &aDefault) const
Key_Return
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Mar 2 2021 01:03:26 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.