Changeset View
Standalone View
src/kcolorschememanager.cpp
Show All 16 Lines | |||||
17 | * Boston, MA 02110-1301, USA. | 17 | * Boston, MA 02110-1301, USA. | ||
18 | */ | 18 | */ | ||
19 | #include "kcolorschememanager.h" | 19 | #include "kcolorschememanager.h" | ||
20 | #include "kcolorschememanager_p.h" | 20 | #include "kcolorschememanager_p.h" | ||
21 | 21 | | |||
22 | #include <kactionmenu.h> | 22 | #include <kactionmenu.h> | ||
23 | #include <kconfiggroup.h> | 23 | #include <kconfiggroup.h> | ||
24 | #include <kcolorscheme.h> | 24 | #include <kcolorscheme.h> | ||
25 | #include <klocalizedstring.h> | ||||
25 | #include <ksharedconfig.h> | 26 | #include <ksharedconfig.h> | ||
26 | 27 | | |||
27 | #include <QApplication> | 28 | #include <QApplication> | ||
28 | #include <QDir> | 29 | #include <QDir> | ||
29 | #include <QFileInfo> | 30 | #include <QFileInfo> | ||
30 | #include <QMenu> | 31 | #include <QMenu> | ||
31 | #include <QPainter> | 32 | #include <QPainter> | ||
32 | #include <QStandardPaths> | 33 | #include <QStandardPaths> | ||
34 | #include <QStyle> | ||||
35 | | ||||
36 | constexpr int defaultSchemeRow = 0; | ||||
33 | 37 | | |||
34 | KColorSchemeManagerPrivate::KColorSchemeManagerPrivate() | 38 | KColorSchemeManagerPrivate::KColorSchemeManagerPrivate() | ||
35 | : model(new KColorSchemeModel()) | 39 | : model(new KColorSchemeModel()) | ||
36 | { | 40 | { | ||
37 | } | 41 | } | ||
38 | 42 | | |||
39 | KColorSchemeModel::KColorSchemeModel(QObject *parent) | 43 | KColorSchemeModel::KColorSchemeModel(QObject *parent) | ||
40 | : QAbstractListModel(parent) | 44 | : QAbstractListModel(parent) | ||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Line(s) | 99 | for (const QString &schemeFile : qAsConst(schemeFiles)) { | |||
97 | KConfigGroup group(config, QStringLiteral("General")); | 101 | KConfigGroup group(config, QStringLiteral("General")); | ||
98 | const QString name = group.readEntry("Name", QFileInfo(schemeFile).baseName()); | 102 | const QString name = group.readEntry("Name", QFileInfo(schemeFile).baseName()); | ||
99 | const KColorSchemeModelData data = {name, schemeFile, QIcon()}; | 103 | const KColorSchemeModelData data = {name, schemeFile, QIcon()}; | ||
100 | m_data.append(data); | 104 | m_data.append(data); | ||
101 | } | 105 | } | ||
102 | std::sort(m_data.begin(), m_data.end(), [](const KColorSchemeModelData & first, const KColorSchemeModelData & second) { | 106 | std::sort(m_data.begin(), m_data.end(), [](const KColorSchemeModelData & first, const KColorSchemeModelData & second) { | ||
103 | return first.name < second.name; | 107 | return first.name < second.name; | ||
104 | }); | 108 | }); | ||
109 | m_data.insert(defaultSchemeRow, {i18n("Default"), QString(), QIcon::fromTheme("edit-undo")}); | ||||
asemke: Many applications like kdevelop, digikam, labplot, etc. create a menu "Color Scheme" in the… | |||||
"Default" is probably fine. FWIW the parent menu item is actually mis-named, at least in Kate. It's called "Color Theme" when it should be "Color Scheme" Also this menu should be universal, and not re-implemented on a per-app basis. ngraham: "Default" is probably fine.
FWIW the parent menu item is actually mis-named, at least in Kate. | |||||
Yes, was also wrong in LabPlot. Just corrected https://invent.kde.org/kde/labplot/commit/262f37b59193ed88bf680b155dc6ecd37bd11419. We should have maybe in this class only one public function KActionMenu *createSchemeSelectionMenu(QObject *parent) which internally sets the string to "Color Scheme" and the icon to "preferences-desktop-color". With this we'd enforce a consistent look. Or this is menu is automatically created for KXmlGuiWindow applications... asemke: Yes, was also wrong in LabPlot. Just corrected https://invent.kde. | |||||
That's what I was thinking of, yeah. ngraham: > Or this is menu is automatically created for KXmlGuiWindow applications...
That's what I was… | |||||
105 | endResetModel(); | 110 | endResetModel(); | ||
106 | } | 111 | } | ||
107 | 112 | | |||
108 | QIcon KColorSchemeModel::createPreview(const QString &path) const | 113 | QIcon KColorSchemeModel::createPreview(const QString &path) const | ||
109 | { | 114 | { | ||
110 | KSharedConfigPtr schemeConfig = KSharedConfig::openConfig(path, KConfig::SimpleConfig); | 115 | KSharedConfigPtr schemeConfig = KSharedConfig::openConfig(path, KConfig::SimpleConfig); | ||
111 | QIcon result; | 116 | QIcon result; | ||
112 | 117 | | |||
Show All 35 Lines | |||||
148 | 153 | | |||
149 | QAbstractItemModel *KColorSchemeManager::model() const | 154 | QAbstractItemModel *KColorSchemeManager::model() const | ||
150 | { | 155 | { | ||
151 | return d->model.data(); | 156 | return d->model.data(); | ||
152 | } | 157 | } | ||
153 | 158 | | |||
154 | QModelIndex KColorSchemeManager::indexForScheme(const QString &name) const | 159 | QModelIndex KColorSchemeManager::indexForScheme(const QString &name) const | ||
155 | { | 160 | { | ||
156 | for (int i = 0; i < d->model->rowCount(); ++i) { | 161 | // Empty string is mapped to "reset to the system scheme" | ||
Propose to add a short comment explaining why we return index(0) here for the future code reader starting off at this code before having read all code and docs. E.g. kossebau: Propose to add a short comment explaining why we return index(0) here for the future code… | |||||
162 | if (name.isEmpty()) { | ||||
163 | return d->model->index(defaultSchemeRow); | ||||
164 | } | ||||
165 | for (int i = 1; i < d->model->rowCount(); ++i) { | ||||
kossebau: Could start off at 1 now, no? | |||||
157 | QModelIndex index = d->model->index(i); | 166 | QModelIndex index = d->model->index(i); | ||
158 | if (index.data().toString() == name) { | 167 | if (index.data().toString() == name) { | ||
159 | return index; | 168 | return index; | ||
160 | } | 169 | } | ||
161 | } | 170 | } | ||
162 | return QModelIndex(); | 171 | return QModelIndex(); | ||
163 | } | 172 | } | ||
164 | 173 | | |||
165 | KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QIcon &icon, const QString &name, const QString &selectedSchemeName, QObject *parent) | 174 | KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QIcon &icon, const QString &name, const QString &selectedSchemeName, QObject *parent) | ||
166 | { | 175 | { | ||
167 | KActionMenu *menu = new KActionMenu(icon, name, parent); | 176 | KActionMenu *menu = new KActionMenu(icon, name, parent); | ||
168 | QActionGroup *group = new QActionGroup(menu); | 177 | QActionGroup *group = new QActionGroup(menu); | ||
169 | connect(group, &QActionGroup::triggered, [](QAction * action) { | 178 | connect(group, &QActionGroup::triggered, this, [this](QAction * action) { | ||
170 | // hint for the style to synchronize the color scheme with the window manager/compositor | 179 | activateScheme(d->model->index(action->data().toInt())); | ||
171 | qApp->setProperty("KDE_COLOR_SCHEME_PATH", action->data()); | | |||
172 | qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(action->data().toString()))); | | |||
173 | }); | 180 | }); | ||
174 | for (int i = 0; i < d->model->rowCount(); ++i) { | 181 | for (int i = 0; i < d->model->rowCount(); ++i) { | ||
175 | QModelIndex index = d->model->index(i); | 182 | QModelIndex index = d->model->index(i); | ||
176 | QAction *action = new QAction(index.data(Qt::DisplayRole).toString(), menu); | 183 | QAction *action = new QAction(index.data(Qt::DisplayRole).toString(), menu); | ||
177 | action->setData(index.data(Qt::UserRole)); | 184 | action->setData(index.row()); | ||
178 | action->setActionGroup(group); | 185 | action->setActionGroup(group); | ||
179 | action->setCheckable(true); | 186 | action->setCheckable(true); | ||
180 | if (index.data().toString() == selectedSchemeName) { | 187 | if (index.data().toString() == selectedSchemeName) { | ||
181 | action->setChecked(true); | 188 | action->setChecked(true); | ||
182 | } | 189 | } | ||
183 | menu->addAction(action); | 190 | menu->addAction(action); | ||
184 | } | 191 | } | ||
185 | 192 | if (!group->checkedAction()) { | |||
193 | // If no (valid) color scheme has been selected we select the default one | ||||
194 | group->actions()[defaultSchemeRow]->setChecked(true); | ||||
195 | } | ||||
also could get a short comment what the highlevel logic is here kossebau: also could get a short comment what the highlevel logic is here
`// no color theme selected? so… | |||||
186 | connect(menu->menu(), &QMenu::aboutToShow, group, [this, group] { | 196 | connect(menu->menu(), &QMenu::aboutToShow, group, [this, group] { | ||
187 | const auto actions = group->actions(); | 197 | const auto actions = group->actions(); | ||
188 | for (QAction *action : actions) { | 198 | for (QAction *action : actions) { | ||
189 | if (action->icon().isNull()) { | 199 | if (action->icon().isNull()) { | ||
190 | action->setIcon(d->model->createPreview(action->data().toString())); | 200 | action->setIcon(d->model->index(action->data().toInt()).data(Qt::DecorationRole).value<QIcon>()); | ||
191 | } | 201 | } | ||
192 | } | 202 | } | ||
193 | }); | 203 | }); | ||
194 | 204 | | |||
195 | return menu; | 205 | return menu; | ||
196 | } | 206 | } | ||
197 | 207 | | |||
198 | KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QString &text, const QString &selectedSchemeName, QObject *parent) | 208 | KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QString &text, const QString &selectedSchemeName, QObject *parent) | ||
199 | { | 209 | { | ||
200 | return createSchemeSelectionMenu(QIcon(), text, selectedSchemeName, parent); | 210 | return createSchemeSelectionMenu(QIcon::fromTheme("preferences-desktop-color"), text, selectedSchemeName, parent); | ||
201 | } | 211 | } | ||
202 | 212 | | |||
203 | KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QString &selectedSchemeName, QObject *parent) | 213 | KActionMenu *KColorSchemeManager::createSchemeSelectionMenu(const QString &selectedSchemeName, QObject *parent) | ||
204 | { | 214 | { | ||
205 | return createSchemeSelectionMenu(QIcon(), QString(), selectedSchemeName, parent); | 215 | return createSchemeSelectionMenu(QIcon::fromTheme("preferences-desktop-color"), i18n("Color Scheme"), selectedSchemeName, parent); | ||
206 | } | 216 | } | ||
207 | 217 | | |||
208 | void KColorSchemeManager::activateScheme(const QModelIndex &index) | 218 | KActionMenu *KColorSchemeManager::createSchemeSelectionMenu (QObject *parent) | ||
209 | { | 219 | { | ||
210 | if (!index.isValid()) { | 220 | return createSchemeSelectionMenu(QIcon::fromTheme("preferences-desktop-color"), i18n("Color Scheme"), QString(), parent); | ||
211 | return; | | |||
212 | } | 221 | } | ||
213 | if (index.model() != d->model.data()) { | 222 | | ||
214 | return; | 223 | void KColorSchemeManager::activateScheme(const QModelIndex &index) | ||
215 | } | 224 | { | ||
216 | // hint for the style to synchronize the color scheme with the window manager/compositor | 225 | // hint for plasma-integration to synchronize the color scheme with the window manager/compositor | ||
why not to use reasonable default values here like QIcon::fromTheme(QStringLiteral("preferences-desktop-color") and i18n("Color Scheme")? This function should be used then by all applications and this will help to get a more consistent behavior across the different applications. asemke: why not to use reasonable default values here like QIcon::fromTheme(QStringLiteral("preferences… | |||||
Should we also do this for the other overloads? Or would that behavior change be a blocker? ALso an application would want to call KColorSchemeManager::createSchemeSelectionMenu(const QString &selectedSchemeName, QObject *parent) probably if the custom scheme is saved between launches. davidre: Should we also do this for the other overloads? Or would that behavior change be a blocker? | |||||
I'm not the author of this code but I don't see why this should be a blocker. With this you wouldn't break anything and would simply add more consistency across different applications. asemke: I'm not the author of this code but I don't see why this should be a blocker. With this you… | |||||
226 | // The property needs to be set before the palette change because is is checked upon the | ||||
227 | // ApplicationPaletteChange event. | ||||
Using // for each comment line is more typical for explanation comments, why the different style here? kossebau: Using `//` for each comment line is more typical for explanation comments, why the different… | |||||
Because I didn't see another multiline comment in this file to compare to ;) davidre: Because I didn't see another multiline comment in this file to compare to ;) | |||||
217 | qApp->setProperty("KDE_COLOR_SCHEME_PATH", index.data(Qt::UserRole)); | 228 | qApp->setProperty("KDE_COLOR_SCHEME_PATH", index.data(Qt::UserRole)); | ||
229 | if (index.isValid() && index.model() == d->model.data() && index.row() != defaultSchemeRow) { | ||||
218 | qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(index.data(Qt::UserRole).toString()))); | 230 | qApp->setPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(index.data(Qt::UserRole).toString()))); | ||
231 | } else { | ||||
232 | qApp->setPalette(qApp->style()->standardPalette()); | ||||
233 | } | ||||
asemke: if (index.row() == 0) would also do the job and is simpler and faster. | |||||
219 | } | 234 | } |
Many applications like kdevelop, digikam, labplot, etc. create a menu "Color Scheme" in the main menu bar and add then menu item via KColorSchemeManager. By using "System color scheme" here we'd have "Color Scheme" -> "System color scheme" with this repeated "color scheme" string. Can we simply use "Default" or "System" or "Desktop" here?