KColorScheme

kcolorschememanager.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kcolorschememanager.h"
9#include "kcolorschememanager_p.h"
10
11#include "kcolorschememodel.h"
12
13#include <KConfigGroup>
14#include <KConfigGui>
15#include <KLocalizedString>
16#include <KSharedConfig>
17#include <kcolorscheme.h>
18
19#include <QDir>
20#include <QFileInfo>
21#include <QGuiApplication>
22#include <QIcon>
23#include <QPainter>
24#include <QStandardPaths>
25
26// ensure we are linking KConfigGui, so QColor I/O from KConfig works
27KCONFIGGUI_EXPORT int initKConfigGroupGui();
28static int s_init = initKConfigGroupGui();
29
30constexpr int defaultSchemeRow = 0;
31
32void KColorSchemeManagerPrivate::activateSchemeInternal(const QString &colorSchemePath)
33{
34 // hint for plasma-integration to synchronize the color scheme with the window manager/compositor
35 // The property needs to be set before the palette change because is is checked upon the
36 // ApplicationPaletteChange event.
37 qApp->setProperty("KDE_COLOR_SCHEME_PATH", colorSchemePath);
38 if (colorSchemePath.isEmpty()) {
39 qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::Ptr(nullptr)));
40 } else {
41 qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(colorSchemePath)));
42 }
43}
44
45// The meaning of the Default entry depends on the platform
46// On Windows and macOS we automatically apply Breeze/Breeze Dark depending on the system preference
47// On other platforms we apply a default KColorScheme
48QString KColorSchemeManagerPrivate::automaticColorSchemePath() const
49{
50#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || defined(Q_OS_ANDROID)
51 const QString colorSchemeId = m_colorSchemeWatcher.systemPreference() == KColorSchemeWatcher::PreferDark ? getDarkColorScheme() : getLightColorScheme();
52 return indexForSchemeId(colorSchemeId).data(KColorSchemeModel::PathRole).toString();
53#else
54 return QString();
55#endif
56}
57
58QIcon KColorSchemeManagerPrivate::createPreview(const QString &path)
59{
60 KSharedConfigPtr schemeConfig = KSharedConfig::openConfig(path, KConfig::SimpleConfig);
61 QIcon result;
62
63 KColorScheme activeWindow(QPalette::Active, KColorScheme::Window, schemeConfig);
64 KColorScheme activeButton(QPalette::Active, KColorScheme::Button, schemeConfig);
65 KColorScheme activeView(QPalette::Active, KColorScheme::View, schemeConfig);
66 KColorScheme activeSelection(QPalette::Active, KColorScheme::Selection, schemeConfig);
67
68 auto pixmap = [&](int size) {
69 QPixmap pix(size, size);
70 pix.fill(Qt::black);
71 QPainter p;
72 p.begin(&pix);
73 const int itemSize = size / 2 - 1;
74 p.fillRect(1, 1, itemSize, itemSize, activeWindow.background());
75 p.fillRect(1 + itemSize, 1, itemSize, itemSize, activeButton.background());
76 p.fillRect(1, 1 + itemSize, itemSize, itemSize, activeView.background());
77 p.fillRect(1 + itemSize, 1 + itemSize, itemSize, itemSize, activeSelection.background());
78 p.end();
79 result.addPixmap(pix);
80 };
81 // 16x16
82 pixmap(16);
83 // 24x24
84 pixmap(24);
85
86 return result;
87}
88
89KColorSchemeManagerPrivate::KColorSchemeManagerPrivate()
90 : model(new KColorSchemeModel())
91{
92}
93
94KColorSchemeManager::KColorSchemeManager(QObject *parent)
95 : QObject(parent)
96 , d(new KColorSchemeManagerPrivate)
97{
98#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || defined(Q_OS_ANDROID)
99 connect(&d->m_colorSchemeWatcher, &KColorSchemeWatcher::systemPreferenceChanged, this, [this]() {
100 if (!d->m_activatedScheme.isEmpty()) {
101 // Don't override what has been manually set
102 return;
103 }
104
105 d->activateSchemeInternal(d->automaticColorSchemePath());
106 });
107#endif
108
109 KSharedConfigPtr config = KSharedConfig::openConfig();
110 KConfigGroup cg(config, QStringLiteral("UiSettings"));
111 const QString scheme = cg.readEntry("ColorScheme", QString());
112
113 QString schemePath;
114
115 if (scheme.isEmpty() || scheme == QLatin1String("Default")) {
116 // Color scheme might be already set from a platform theme
117 // This is used for example by QGnomePlatform that can set color scheme
118 // matching GNOME settings. This avoids issues where QGnomePlatform sets
119 // QPalette for dark theme, but end up mixing it also with Breeze light
120 // that is going to be used as a fallback for apps using KColorScheme.
121 // BUG: 447029
122 schemePath = qApp->property("KDE_COLOR_SCHEME_PATH").toString();
123 if (schemePath.isEmpty()) {
124 schemePath = d->automaticColorSchemePath();
125 }
126 } else {
127 const auto index = indexForScheme(scheme);
128 schemePath = index.data(KColorSchemeModel::PathRole).toString();
129 d->m_activatedScheme = index.data(KColorSchemeModel::IdRole).toString();
130 }
131 d->activateSchemeInternal(schemePath);
132}
133
134KColorSchemeManager::~KColorSchemeManager()
135{
136}
137
139{
140 return d->model.get();
141}
142
143QModelIndex KColorSchemeManagerPrivate::indexForSchemeId(const QString &id) const
144{
145 for (int i = 1; i < model->rowCount(); ++i) {
146 QModelIndex index = model->index(i);
147 if (index.data(KColorSchemeModel::IdRole).toString() == id) {
148 return index;
149 }
150 }
151 return QModelIndex();
152}
153
155{
156 d->m_autosaveChanges = autosaveChanges;
157}
158
160{
161 // Empty string is mapped to "reset to the system scheme"
162 if (name.isEmpty()) {
163 return d->model->index(defaultSchemeRow);
164 }
165 for (int i = 1; i < d->model->rowCount(); ++i) {
166 QModelIndex index = d->model->index(i);
167 if (index.data(KColorSchemeModel::NameRole).toString() == name) {
168 return index;
169 }
170 }
171 return QModelIndex();
172}
173
175{
176 const bool isDefaultEntry = index.data(KColorSchemeModel::PathRole).toString().isEmpty();
177
178 if (index.isValid() && index.model() == d->model.get() && !isDefaultEntry) {
179 d->activateSchemeInternal(index.data(KColorSchemeModel::PathRole).toString());
180 d->m_activatedScheme = index.data(KColorSchemeModel::IdRole).toString();
181 if (d->m_autosaveChanges) {
182 saveSchemeToConfigFile(index.data(KColorSchemeModel::NameRole).toString());
183 }
184 } else {
185 d->activateSchemeInternal(d->automaticColorSchemePath());
186 d->m_activatedScheme = QString();
187 if (d->m_autosaveChanges) {
189 }
190 }
191}
192
194{
195 KSharedConfigPtr config = KSharedConfig::openConfig();
196 KConfigGroup cg(config, QStringLiteral("UiSettings"));
197 cg.writeEntry("ColorScheme", KLocalizedString::removeAcceleratorMarker(schemeName));
198 cg.sync();
199}
200
202{
203 return d->m_activatedScheme;
204}
205
206#include "moc_kcolorschememanager.cpp"
QAbstractItemModel * model() const
A QAbstractItemModel of all available color schemes.
QString activeSchemeId() const
Returns the id of the currently active scheme or an empty string if the default scheme is active.
QModelIndex indexForScheme(const QString &name) const
Returns the model index for the scheme with the given name.
void activateScheme(const QModelIndex &index)
Activates the KColorScheme identified by the provided index.
void saveSchemeToConfigFile(const QString &schemeName) const
Saves the color scheme to config file.
void setAutosaveChanges(bool autosaveChanges)
Sets color scheme autosaving.
A model listing the KColorSchemes available in the system.
void systemPreferenceChanged()
A set of methods used to work with colors.
static QPalette createApplicationPalette(const KSharedConfigPtr &config)
Used to obtain the QPalette that will be used to set the application palette from KDE Platform theme.
@ View
Views; for example, frames, input fields, etc.
@ Window
Non-editable window elements; for example, menus.
@ Selection
Selected items in views.
@ Button
Buttons and button-like controls.
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
bool sync() override
static QString removeAcceleratorMarker(const QString &label)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void addPixmap(const QPixmap &pixmap, Mode mode, State state)
QVariant data(int role) const const
bool isValid() const const
const QAbstractItemModel * model() const const
bool begin(QPaintDevice *device)
bool end()
void fillRect(const QRect &rectangle, QGradient::Preset preset)
QChar * data()
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:50:24 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.