File indexing completed on 2024-12-01 09:48:09
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kcolorschememanager.h" 0009 #include "kcolorschememanager_p.h" 0010 0011 #include "kcolorschememenu.h" 0012 #include "kcolorschememodel.h" 0013 0014 #include <KActionMenu> 0015 #include <KConfigGroup> 0016 #include <KLocalizedString> 0017 #include <KSharedConfig> 0018 #include <kcolorscheme.h> 0019 0020 #include <QApplication> 0021 #include <QDir> 0022 #include <QFileInfo> 0023 #include <QIcon> 0024 #include <QMenu> 0025 #include <QPainter> 0026 #include <QStandardPaths> 0027 0028 constexpr int defaultSchemeRow = 0; 0029 0030 void KColorSchemeManagerPrivate::activateSchemeInternal(const QString &colorSchemePath) 0031 { 0032 // hint for plasma-integration to synchronize the color scheme with the window manager/compositor 0033 // The property needs to be set before the palette change because is is checked upon the 0034 // ApplicationPaletteChange event. 0035 qApp->setProperty("KDE_COLOR_SCHEME_PATH", colorSchemePath); 0036 if (colorSchemePath.isEmpty()) { 0037 qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::Ptr(nullptr))); 0038 } else { 0039 qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(colorSchemePath))); 0040 } 0041 } 0042 0043 // The meaning of the Default entry depends on the platform 0044 // On Windows and macOS we automatically apply Breeze/Breeze Dark depending on the system preference 0045 // On other platforms we apply a default KColorScheme 0046 QString KColorSchemeManagerPrivate::automaticColorSchemePath() const 0047 { 0048 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) 0049 const QString colorSchemeId = m_colorSchemeWatcher.systemPreference() == KColorSchemeWatcher::PreferDark ? getDarkColorScheme() : getLightColorScheme(); 0050 return indexForSchemeId(colorSchemeId).data(KColorSchemeModel::PathRole).toString(); 0051 #else 0052 return QString(); 0053 #endif 0054 } 0055 0056 QIcon KColorSchemeManagerPrivate::createPreview(const QString &path) 0057 { 0058 KSharedConfigPtr schemeConfig = KSharedConfig::openConfig(path, KConfig::SimpleConfig); 0059 QIcon result; 0060 0061 KColorScheme activeWindow(QPalette::Active, KColorScheme::Window, schemeConfig); 0062 KColorScheme activeButton(QPalette::Active, KColorScheme::Button, schemeConfig); 0063 KColorScheme activeView(QPalette::Active, KColorScheme::View, schemeConfig); 0064 KColorScheme activeSelection(QPalette::Active, KColorScheme::Selection, schemeConfig); 0065 0066 auto pixmap = [&](int size) { 0067 QPixmap pix(size, size); 0068 pix.fill(Qt::black); 0069 QPainter p; 0070 p.begin(&pix); 0071 const int itemSize = size / 2 - 1; 0072 p.fillRect(1, 1, itemSize, itemSize, activeWindow.background()); 0073 p.fillRect(1 + itemSize, 1, itemSize, itemSize, activeButton.background()); 0074 p.fillRect(1, 1 + itemSize, itemSize, itemSize, activeView.background()); 0075 p.fillRect(1 + itemSize, 1 + itemSize, itemSize, itemSize, activeSelection.background()); 0076 p.end(); 0077 result.addPixmap(pix); 0078 }; 0079 // 16x16 0080 pixmap(16); 0081 // 24x24 0082 pixmap(24); 0083 0084 return result; 0085 } 0086 0087 KColorSchemeManagerPrivate::KColorSchemeManagerPrivate() 0088 : model(new KColorSchemeModel()) 0089 { 0090 } 0091 0092 KColorSchemeManager::KColorSchemeManager(QObject *parent) 0093 : QObject(parent) 0094 , d(new KColorSchemeManagerPrivate) 0095 { 0096 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) 0097 connect(&d->m_colorSchemeWatcher, &KColorSchemeWatcher::systemPreferenceChanged, this, [this]() { 0098 if (!d->m_activatedScheme.isEmpty()) { 0099 // Don't override what has been manually set 0100 return; 0101 } 0102 0103 d->activateSchemeInternal(d->automaticColorSchemePath()); 0104 }); 0105 #endif 0106 0107 KSharedConfigPtr config = KSharedConfig::openConfig(); 0108 KConfigGroup cg(config, "UiSettings"); 0109 const QString scheme = cg.readEntry("ColorScheme", QString()); 0110 0111 QString schemePath; 0112 0113 if (scheme.isEmpty() || scheme == QLatin1String("Default")) { 0114 // Color scheme might be already set from a platform theme 0115 // This is used for example by QGnomePlatform that can set color scheme 0116 // matching GNOME settings. This avoids issues where QGnomePlatform sets 0117 // QPalette for dark theme, but end up mixing it also with Breeze light 0118 // that is going to be used as a fallback for apps using KColorScheme. 0119 // BUG: 447029 0120 schemePath = qApp->property("KDE_COLOR_SCHEME_PATH").toString(); 0121 if (schemePath.isEmpty()) { 0122 schemePath = d->automaticColorSchemePath(); 0123 } 0124 } else { 0125 const auto index = indexForScheme(scheme); 0126 schemePath = index.data(KColorSchemeModel::PathRole).toString(); 0127 d->m_activatedScheme = index.data(KColorSchemeModel::IdRole).toString(); 0128 } 0129 d->activateSchemeInternal(schemePath); 0130 } 0131 0132 KColorSchemeManager::~KColorSchemeManager() 0133 { 0134 } 0135 0136 QAbstractItemModel *KColorSchemeManager::model() const 0137 { 0138 return d->model.get(); 0139 } 0140 0141 QModelIndex KColorSchemeManagerPrivate::indexForSchemeId(const QString &id) const 0142 { 0143 for (int i = 1; i < model->rowCount(); ++i) { 0144 QModelIndex index = model->index(i); 0145 if (index.data(KColorSchemeModel::IdRole).toString() == id) { 0146 return index; 0147 } 0148 } 0149 return QModelIndex(); 0150 } 0151 0152 void KColorSchemeManager::setAutosaveChanges(bool autosaveChanges) 0153 { 0154 d->m_autosaveChanges = autosaveChanges; 0155 } 0156 0157 QModelIndex KColorSchemeManager::indexForScheme(const QString &name) const 0158 { 0159 // Empty string is mapped to "reset to the system scheme" 0160 if (name.isEmpty()) { 0161 return d->model->index(defaultSchemeRow); 0162 } 0163 for (int i = 1; i < d->model->rowCount(); ++i) { 0164 QModelIndex index = d->model->index(i); 0165 if (index.data(KColorSchemeModel::NameRole).toString() == name) { 0166 return index; 0167 } 0168 } 0169 return QModelIndex(); 0170 } 0171 0172 #if KCONFIGWIDGETS_BUILD_DEPRECATED_SINCE(5, 107) 0173 KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QIcon &icon, const QString &name, const QString &selectedSchemeName, QObject *parent) 0174 { 0175 auto menu = createSchemeSelectionMenu(name, selectedSchemeName, parent); 0176 menu->setIcon(icon); 0177 return menu; 0178 } 0179 0180 KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QString &text, const QString &selectedSchemeName, QObject *parent) 0181 { 0182 auto menu = createSchemeSelectionMenu(selectedSchemeName, parent); 0183 menu->setText(text); 0184 return menu; 0185 } 0186 0187 KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QString &selectedSchemeName, QObject *parent) 0188 { 0189 auto menu = KColorSchemeMenu::createMenu(this, parent); 0190 auto actions = menu->menu()->actions(); 0191 auto it = std::find_if(actions.begin(), actions.end(), [selectedSchemeName](const QAction *action) { 0192 return action->text() == selectedSchemeName; 0193 }); 0194 if (it != actions.end()) { 0195 (*it)->setChecked(true); 0196 } 0197 return menu; 0198 } 0199 0200 KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(QObject *parent) 0201 { 0202 return KColorSchemeMenu::createMenu(this, parent); 0203 } 0204 #endif 0205 0206 void KColorSchemeManager::activateScheme(const QModelIndex &index) 0207 { 0208 const bool isDefaultEntry = index.data(KColorSchemeModel::PathRole).toString().isEmpty(); 0209 0210 if (index.isValid() && index.model() == d->model.get() && !isDefaultEntry) { 0211 d->activateSchemeInternal(index.data(KColorSchemeModel::PathRole).toString()); 0212 d->m_activatedScheme = index.data(KColorSchemeModel::IdRole).toString(); 0213 if (d->m_autosaveChanges) { 0214 saveSchemeToConfigFile(index.data(KColorSchemeModel::NameRole).toString()); 0215 } 0216 } else { 0217 d->activateSchemeInternal(d->automaticColorSchemePath()); 0218 d->m_activatedScheme = QString(); 0219 if (d->m_autosaveChanges) { 0220 saveSchemeToConfigFile(QString()); 0221 } 0222 } 0223 } 0224 0225 void KColorSchemeManager::saveSchemeToConfigFile(const QString &schemeName) const 0226 { 0227 KSharedConfigPtr config = KSharedConfig::openConfig(); 0228 KConfigGroup cg(config, "UiSettings"); 0229 cg.writeEntry("ColorScheme", KLocalizedString::removeAcceleratorMarker(schemeName)); 0230 cg.sync(); 0231 } 0232 0233 QString KColorSchemeManager::activeSchemeId() const 0234 { 0235 return d->m_activatedScheme; 0236 } 0237 0238 #include "moc_kcolorschememanager.cpp"