Kstars

thememanager.cpp
1/*
2 This file is a part of digiKam project
3 https://www.digikam.org
4
5 SPDX-FileCopyrightText: 2006-2018 Gilles Caulier <caulier dot gilles at gmail dot com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "thememanager.h"
11
12#include "kstars.h"
13#include "kstars_debug.h"
14#include "Options.h"
15#include "schememanager.h"
16#include "widgets/dmsbox.h"
17
18#include <KLocalizedString>
19#include <KActionCollection>
20#include <KConfigGroup>
21#include <KXmlGuiWindow>
22
23#include <QTabBar>
24#include <QPixmapCache>
25#include <QStringList>
26#include <QStyleFactory>
27#include <QFileInfo>
28#include <QPalette>
29#include <QColor>
30#include <QActionGroup>
31#include <QBitmap>
32#include <QPainter>
33#include <QPixmap>
34#include <QApplication>
35#include <QAction>
36#include <QStandardPaths>
37#include <QDirIterator>
38#include <QMenu>
39#include <QStyle>
40#include <QResource>
41
42namespace KSTheme
43{
44
45class ThemeManagerCreator
46{
47 public:
48
49 Manager object;
50};
51
52Q_GLOBAL_STATIC(ThemeManagerCreator, creator)
53
54// ---------------------------------------------------------------
55
56
57class Manager::Private
58{
59 public:
60
61 Private()
62 : defaultThemeName(i18nc("default theme name", "Default")),
63 themeMenuActionGroup(0),
64 themeMenuAction(0)
65 {
66 }
67
68 const QString defaultThemeName;
69 QMap<QString, QString> themeMap; // map<theme name, theme config path>
70
71 QActionGroup* themeMenuActionGroup;
72 QMenu* themeMenuAction;
73};
74
75Manager::Manager()
76 : d(new Private)
77{
78}
79
80Manager::~Manager()
81{
82 delete d;
83}
84
85Manager* Manager::instance()
86{
87 return &creator->object;
88}
89
90QString Manager::defaultThemeName() const
91{
92 return d->defaultThemeName;
93}
94
95QString Manager::currentThemeName() const
96{
97 if (!d->themeMenuAction || !d->themeMenuActionGroup)
98 {
99 return defaultThemeName();
100 }
101
102 QAction* const action = d->themeMenuActionGroup->checkedAction();
103 return (!action ? defaultThemeName()
104 : action->text().remove(QLatin1Char('&')));
105}
106
107void Manager::setCurrentTheme(const QString &name)
108{
109 if (!d->themeMenuAction || !d->themeMenuActionGroup)
110 {
111 return;
112 }
113
114 QList<QAction*> list = d->themeMenuActionGroup->actions();
115
116 foreach(QAction* const action, list)
117 {
118 if (action->text().remove(QLatin1Char('&')) == name)
119 {
120 action->setChecked(true);
121 slotChangePalette();
122 }
123 }
124}
125
126void Manager::slotChangePalette()
127{
128 updateCurrentDesktopDefaultThemePreview();
129
130 QString theme(currentThemeName());
131
132 /*if (theme == defaultThemeName() || theme.isEmpty())
133 {
134 theme = currentDesktopdefaultTheme();
135 }*/
136
137 //QString themeIconName("breeze-dark");
138 IconTheme themeIconType = BREEZE_DARK_THEME;
139
140 if (theme == "Macintosh" || theme == "White Balance" || theme == "High Key" || (theme == "Default"
141 && currentDesktopdefaultTheme().contains("Dark") == false))
142 themeIconType = BREEZE_THEME;
143
144 setIconTheme(themeIconType);
145
146 QString filename = d->themeMap.value(theme);
147 KSharedConfigPtr config = KSharedConfig::openConfig(filename);
148 // hint for the style to synchronize the color scheme with the window manager/compositor
149 qApp->setProperty("KDE_COLOR_SCHEME_PATH", filename);
151
152 qApp->setPalette(palette);
153
154 QList<QWidget *> widgets = qApp->allWidgets();
155 foreach(QWidget *w, widgets)
156 {
157 dmsBox *box = qobject_cast<dmsBox *>(w);
158 if(box)
159 box->setPalette(palette);
160 QTabBar *bar = qobject_cast<QTabBar *>(w);
161 if(bar)
162 bar->setPalette(palette);
163 }
164
165 if(theme == "Macintosh")
166 qApp->setStyle(QStyleFactory::create("macintosh"));
167 else
168 {
169 if (qgetenv("XDG_CURRENT_DESKTOP") != "KDE")
170 qApp->setStyle(QStyleFactory::create("Fusion"));
171 }
172
173 // Special case. For Night Vision theme, we also change the Sky Color Scheme
174 if (theme == "Default" && Options::colorSchemeFile() == "night.colors")
175 KStars::Instance()->actionCollection()->action("cs_moonless-night")->setChecked(true);
176 else if (theme == "Night Vision")
177 KStars::Instance()->actionCollection()->action("cs_night")->setChecked(true);
178
180
181 qApp->style()->polish(qApp);
182
183 emit signalThemeChanged();
184}
185
186void Manager::setThemeMenuAction(QMenu* const action)
187{
188 d->themeMenuAction = action;
189
190 action->setStyleSheet("QMenu::icon:checked {background: gray;border: 1px inset gray;position: absolute;"
191 "top: 1px;right: 1px;bottom: 1px;left: 1px;}");
192
193 populateThemeMenu();
194}
195
196void Manager::registerThemeActions(KXmlGuiWindow* const win)
197{
198 if (!win)
199 {
200 return;
201 }
202
203 if (!d->themeMenuAction)
204 {
205 qCDebug(KSTARS) << "Cannot register theme actions to " << win->windowTitle();
206 return;
207 }
208
209 win->actionCollection()->addAction(QLatin1String("themes"), d->themeMenuAction->menuAction());
210}
211
212void Manager::populateThemeQListWidget(QListWidget *themeWidget)
213{
214 themeWidget->clear();
215
216 QList<QAction*> list = d->themeMenuActionGroup->actions();
217
218 foreach(QAction* const action, list)
219 {
220 QListWidgetItem *item = new QListWidgetItem();
221 item->setText( action->text().remove('&') );
222 item->setIcon( action->icon() );
223 themeWidget->addItem(item);
224 }
225 themeWidget->sortItems();
226}
227
228void Manager::populateThemeMenu()
229{
230 if (!d->themeMenuAction)
231 {
232 return;
233 }
234
235 //QString theme(currentThemeName());
236
237 d->themeMenuAction->clear();
238 delete d->themeMenuActionGroup;
239
240 d->themeMenuActionGroup = new QActionGroup(d->themeMenuAction);
241
242 connect(d->themeMenuActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotChangePalette()));
243
244 QAction* const action = new QAction(defaultThemeName(), d->themeMenuActionGroup);
245 action->setCheckable(true);
246 d->themeMenuAction->addAction(action);
247
248 QStringList schemeFiles;
249 QStringList dirs;
250
251 // kstars themes
253 QString::fromLatin1("kstars/themes"),
255
256 qCDebug(KSTARS) << "Paths to color scheme : " << dirs;
257
258 Q_FOREACH (const QString &dir, dirs)
259 {
260 QDirIterator it(dir, QStringList() << QLatin1String("*.colors"));
261
262 while (it.hasNext())
263 {
264 schemeFiles.append(it.next());
265 }
266 }
267
268 QMap<QString, QAction*> actionMap;
269
270 for (int i = 0; i < schemeFiles.size(); ++i)
271 {
272 const QString filename = schemeFiles.at(i);
273 const QFileInfo info(filename);
274 KSharedConfigPtr config = KSharedConfig::openConfig(filename);
275 QIcon icon = createSchemePreviewIcon(config);
276 KConfigGroup group(config, "General");
277 const QString name = group.readEntry("Name", info.baseName());
278 QAction* const ac = new QAction(name, d->themeMenuActionGroup);
279 d->themeMap.insert(name, filename);
280 ac->setIcon(icon);
281 ac->setCheckable(true);
282 actionMap.insert(name, ac);
283 }
284
285#ifdef Q_OS_MAC
286 QAction* const macAction = new QAction(QLatin1String("Macintosh"), d->themeMenuActionGroup);
287 macAction->setCheckable(true);
288 //TODO Set appropriate icon
289 //macAction->setAction(..)
290 actionMap.insert(QLatin1String("Macintosh"), macAction);
291#endif
292
293 // sort the list
294 QStringList actionMapKeys = actionMap.keys();
295 actionMapKeys.sort();
296
297 foreach(const QString &name, actionMapKeys)
298 {
299 d->themeMenuAction->addAction(actionMap.value(name));
300 }
301
302 updateCurrentDesktopDefaultThemePreview();
303 //setCurrentTheme(theme);
304}
305
306void Manager::updateCurrentDesktopDefaultThemePreview()
307{
308 QList<QAction*> list = d->themeMenuActionGroup->actions();
309
310 foreach(QAction* const action, list)
311 {
312 if (action->text().remove(QLatin1Char('&')) == defaultThemeName())
313 {
314 KSharedConfigPtr config = KSharedConfig::openConfig(d->themeMap.value(currentDesktopdefaultTheme()));
315 QIcon icon = createSchemePreviewIcon(config);
316 action->setIcon(icon);
317 }
318 }
319}
320
321QPixmap Manager::createSchemePreviewIcon(const KSharedConfigPtr &config) const
322{
323 const uchar bits1[] = { 0xff, 0xff, 0xff, 0x2c, 0x16, 0x0b };
324 const uchar bits2[] = { 0x68, 0x34, 0x1a, 0xff, 0xff, 0xff };
325 const QSize bitsSize(24, 2);
326 const QBitmap b1 = QBitmap::fromData(bitsSize, bits1);
327 const QBitmap b2 = QBitmap::fromData(bitsSize, bits2);
328
329 QPixmap pixmap(23, 16);
330 pixmap.fill(Qt::black); // FIXME use some color other than black for borders?
331
332 KConfigGroup group(config, QLatin1String("WM"));
333 QPainter p(&pixmap);
335 p.fillRect(1, 1, 7, 7, windowScheme.background());
336 p.fillRect(2, 2, 5, 2, QBrush(windowScheme.foreground().color(), b1));
337
339 p.fillRect(8, 1, 7, 7, buttonScheme.background());
340 p.fillRect(9, 2, 5, 2, QBrush(buttonScheme.foreground().color(), b1));
341
342 p.fillRect(15, 1, 7, 7, group.readEntry(QLatin1String("activeBackground"), QColor(96, 148, 207)));
343 p.fillRect(16, 2, 5, 2, QBrush(group.readEntry(QLatin1String("activeForeground"), QColor(255, 255, 255)), b1));
344
346 p.fillRect(1, 8, 7, 7, viewScheme.background());
347 p.fillRect(2, 12, 5, 2, QBrush(viewScheme.foreground().color(), b2));
348
350 p.fillRect(8, 8, 7, 7, selectionScheme.background());
351 p.fillRect(9, 12, 5, 2, QBrush(selectionScheme.foreground().color(), b2));
352
353 p.fillRect(15, 8, 7, 7, group.readEntry(QLatin1String("inactiveBackground"), QColor(224, 223, 222)));
354 p.fillRect(16, 12, 5, 2, QBrush(group.readEntry(QLatin1String("inactiveForeground"), QColor(20, 19, 18)), b2));
355
356 p.end();
357 return pixmap;
358}
359
360QString Manager::currentDesktopdefaultTheme() const
361{
362 KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String("kdeglobals"));
363 KConfigGroup group(config, "General");
364 return group.readEntry("ColorScheme");
365}
366
367void Manager::slotSettingsChanged()
368{
369 populateThemeMenu();
370 slotChangePalette();
371}
372
373void Manager::setIconTheme(IconTheme theme)
374{
375 QString rccFile("breeze-icons.rcc");
376 QString iconTheme("breeze");
377
378#if QT_VERSION < 0x051200
379 qCWarning(KSTARS) << "Current icon theme is" << QIcon::themeName();
380#else
381 qCWarning(KSTARS) << "Current icon theme is" << QIcon::themeName() << "(fallback" << QIcon::fallbackThemeName() << ")";
382#endif
383
384 if (theme == BREEZE_DARK_THEME)
385 {
386 rccFile = "breeze-icons-dark.rcc";
387 iconTheme = "breeze-dark";
388 }
389
390 QStringList themeSearchPaths = (QStringList() << QIcon::themeSearchPaths());
391#ifdef Q_OS_MACOS
392 themeSearchPaths = themeSearchPaths << QDir(QCoreApplication::applicationDirPath() + "/../Resources/icons").absolutePath();
393 QString resourcePath = QDir(QCoreApplication::applicationDirPath() + "/../Resources/icons/" + rccFile).absolutePath();
394 QResource::registerResource(resourcePath, "/icons/" + iconTheme);
395#elif defined(Q_OS_WIN)
396 themeSearchPaths = themeSearchPaths << QStandardPaths::locate(QStandardPaths::GenericDataLocation, "icons",
400 QResource::registerResource(resourcePath, "/icons/" + iconTheme);
401#else
402 // On Linux on non-KDE Distros, find out if the themes are installed or not and perhaps warn the user
403 // The important point is that the current theme must be left as is to avoid empty icons
404 {
405 bool missing = true;
406 foreach (auto &path, themeSearchPaths)
407 if (QFile(path + '/' + iconTheme + "/index.theme").exists())
408 missing = false;
409
410 if (missing)
411 {
412 qCWarning(KSTARS) << "Warning: icon theme" << iconTheme << "not found, keeping original" << QIcon::themeName() << ".";
413 iconTheme = QIcon::themeName();
414 }
415 }
416#endif
417
418 QIcon::setThemeSearchPaths(themeSearchPaths);
419 //Note: in order to get it to actually load breeze from resources on mac, we had to add the index.theme, and just one icon from breeze into the qrc. Not sure why this was needed, but it works.
420 QIcon::setThemeName(iconTheme);
421}
422
423}
Q_INVOKABLE QAction * action(const QString &name) const
QAction * addAction(const QString &name, const QObject *receiver=nullptr, const char *member=nullptr)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static KStars * Instance()
Definition kstars.h:121
virtual KActionCollection * actionCollection() const
Primary class to handle all Ekos modules.
A set of methods used to work with colors.
@ Selection
Selected items in views.
@ View
Views; for example, frames, input fields, etc.
@ Button
Buttons and button-like controls.
@ Window
Non-editable window elements; for example, menus.
static QPalette createApplicationPalette(const KSharedConfigPtr &config)
Used to obtain the QPalette that will be used to set the application palette from KDE Platform theme.
A QLineEdit which is capable of displaying and parsing angle values flexibly and robustly.
Definition dmsbox.h:34
QString i18nc(const char *context, const char *text, const TYPE &arg...)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
void setCheckable(bool)
void setChecked(bool)
QBitmap fromData(const QSize &size, const uchar *bits, QImage::Format monoFormat)
QString applicationDirPath()
QString absolutePath() const const
QChar separator()
QString fallbackThemeName()
void setThemeName(const QString &name)
void setThemeSearchPaths(const QStringList &paths)
QString themeName()
QStringList themeSearchPaths()
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype size() const const
void addItem(QListWidgetItem *item)
void clear()
void sortItems(Qt::SortOrder order)
void setIcon(const QIcon &icon)
void setText(const QString &text)
iterator insert(const Key &key, const T &value)
QList< Key > keys() const const
T value(const Key &key, const T &defaultValue) const const
bool registerResource(const QString &rccFileName, const QString &mapRoot)
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
QStringList locateAll(StandardLocation type, const QString &fileName, LocateOptions options)
QString fromLatin1(QByteArrayView str)
void sort(Qt::CaseSensitivity cs)
QStyle * create(const QString &key)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setPalette(const QPalette &)
void setStyleSheet(const QString &styleSheet)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:40 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.