File indexing completed on 2025-04-27 03:58:32

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2004-08-02
0007  * Description : colors theme manager
0008  *
0009  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "thememanager_p.h"
0016 
0017 namespace Digikam
0018 {
0019 
0020 class Q_DECL_HIDDEN ThemeManagerCreator
0021 {
0022 public:
0023 
0024     ThemeManager object;
0025 };
0026 
0027 Q_GLOBAL_STATIC(ThemeManagerCreator, creator)
0028 
0029 // -----------------------------------------------------
0030 
0031 ThemeManager::ThemeManager()
0032     : d(new Private)
0033 {
0034 }
0035 
0036 ThemeManager::~ThemeManager()
0037 {
0038     delete d;
0039 }
0040 
0041 ThemeManager* ThemeManager::instance()
0042 {
0043     return &creator->object;
0044 }
0045 
0046 QString ThemeManager::defaultThemeName() const
0047 {
0048     return d->defaultThemeName;
0049 }
0050 
0051 QString ThemeManager::currentThemeName() const
0052 {
0053     if (!d->themeMenuAction || !d->themeMenuActionGroup)
0054     {
0055         return defaultThemeName();
0056     }
0057 
0058     QAction* const action = d->themeMenuActionGroup->checkedAction();
0059 
0060     return (!action ? defaultThemeName()
0061                     : action->text().remove(QLatin1Char('&')));
0062 }
0063 
0064 void ThemeManager::setCurrentTheme(const QString& name)
0065 {
0066     if (!d->themeMenuAction || !d->themeMenuActionGroup)
0067     {
0068         return;
0069     }
0070 
0071     QList<QAction*> list = d->themeMenuActionGroup->actions();
0072 
0073     Q_FOREACH (QAction* const action, list)
0074     {
0075         if (action->text().remove(QLatin1Char('&')) == name)
0076         {
0077             action->setChecked(true);
0078             slotChangePalette();
0079         }
0080     }
0081 }
0082 
0083 void ThemeManager::slotChangePalette()
0084 {
0085     updateCurrentDesktopDefaultThemePreview();
0086 
0087     QString theme(currentThemeName());
0088 
0089     if (theme.isEmpty()                                                                              ||
0090         (theme == defaultThemeName())                                                                ||
0091         (qApp->style()->objectName().compare(QLatin1String("windowsvista"), Qt::CaseInsensitive) == 0))
0092     {
0093         theme = currentDesktopdefaultTheme();
0094     }
0095 
0096     QString filePath        = d->themeMap.value(theme);
0097     KSharedConfigPtr config = KSharedConfig::openConfig(filePath);
0098 
0099     // hint for the style to synchronize the color scheme with the window manager/compositor
0100 
0101     qApp->setProperty("KDE_COLOR_SCHEME_PATH", filePath);
0102     qApp->setPalette(SchemeManager::createApplicationPalette(config));
0103     qApp->style()->polish(qApp);
0104 
0105     qCDebug(DIGIKAM_WIDGETS_LOG) << theme << " :: " << filePath;
0106 
0107     Q_EMIT signalThemeChanged();
0108 }
0109 
0110 void ThemeManager::setThemeMenuAction(QMenu* const action)
0111 {
0112     d->themeMenuAction = action;
0113     populateThemeMenu();
0114 }
0115 
0116 void ThemeManager::registerThemeActions(DXmlGuiWindow* const win)
0117 {
0118     if (!win)
0119     {
0120         return;
0121     }
0122 
0123     if (!d->themeMenuAction)
0124     {
0125         qCDebug(DIGIKAM_WIDGETS_LOG) << "Cannot register theme actions to " << win->windowTitle();
0126         return;
0127     }
0128 
0129     win->actionCollection()->addAction(QLatin1String("theme_menu"), d->themeMenuAction->menuAction());
0130 }
0131 
0132 void ThemeManager::populateThemeMenu()
0133 {
0134     if (!d->themeMenuAction)
0135     {
0136         return;
0137     }
0138 
0139     QString theme(currentThemeName());
0140 
0141     d->themeMap.clear();
0142     d->themeMenuAction->clear();
0143     delete d->themeMenuActionGroup;
0144 
0145     d->themeMenuActionGroup = new QActionGroup(d->themeMenuAction);
0146 
0147     QAction* const action   = new QAction(defaultThemeName(), d->themeMenuActionGroup);
0148     action->setCheckable(true);
0149     action->setChecked(true);
0150     d->themeMenuAction->addAction(action);
0151 
0152     if (qApp->style()->objectName().compare(QLatin1String("windowsvista"), Qt::CaseInsensitive) != 0)
0153     {
0154         QMap<QString, QAction*> actionMap;
0155         QStringList dirs;
0156 
0157         // digiKam colors scheme
0158 
0159         dirs << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
0160                                           QLatin1String("digikam/colorschemes"),
0161                                           QStandardPaths::LocateDirectory);
0162 
0163         qCDebug(DIGIKAM_WIDGETS_LOG) << "Paths to color scheme : " << dirs;
0164 
0165         Q_FOREACH (const QString& dir, dirs)
0166         {
0167             QDirIterator it(dir, QStringList() << QLatin1String("*.colors"));
0168 
0169             while (it.hasNext())
0170             {
0171                 const QString filePath  = it.next();
0172                 KSharedConfigPtr config = KSharedConfig::openConfig(filePath);
0173                 QIcon icon              = d->createSchemePreviewIcon(config);
0174                 KConfigGroup group(config, QLatin1String("General"));
0175                 const QString name      = group.readEntry("Name",
0176                                                           it.fileInfo().baseName());
0177                 QAction* const ac       = new QAction(name, d->themeMenuActionGroup);
0178                 d->themeMap.insert(name, filePath);
0179                 ac->setIcon(icon);
0180                 ac->setCheckable(true);
0181                 actionMap.insert(name, ac);
0182             }
0183         }
0184 
0185         Q_FOREACH (QAction* const menuAction, actionMap.values())
0186         {
0187             d->themeMenuAction->addAction(menuAction);
0188         }
0189     }
0190 
0191     connect(d->themeMenuActionGroup, SIGNAL(triggered(QAction*)),
0192             this, SLOT(slotChangePalette()));
0193 
0194     updateCurrentDesktopDefaultThemePreview();
0195     setCurrentTheme(theme);
0196 }
0197 
0198 void ThemeManager::updateCurrentDesktopDefaultThemePreview()
0199 {
0200     QList<QAction*> list = d->themeMenuActionGroup->actions();
0201 
0202     Q_FOREACH (QAction* const action, list)
0203     {
0204         if (action->text().remove(QLatin1Char('&')) == defaultThemeName())
0205         {
0206             KSharedConfigPtr config = KSharedConfig::openConfig(d->themeMap.value(currentDesktopdefaultTheme()));
0207             QIcon icon              = d->createSchemePreviewIcon(config);
0208             action->setIcon(icon);
0209         }
0210     }
0211 }
0212 
0213 QString ThemeManager::currentDesktopdefaultTheme() const
0214 {
0215     KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String("kdeglobals"));
0216     KConfigGroup group(config, QLatin1String("General"));
0217 
0218     return group.readEntry("ColorScheme");
0219 }
0220 
0221 void ThemeManager::updateThemeMenu()
0222 {
0223     populateThemeMenu();
0224     slotChangePalette();
0225 }
0226 
0227 } // namespace Digikam
0228 
0229 #include "moc_thememanager.cpp"