diff --git a/src/abstractappearance.cpp b/src/abstractappearance.cpp index 56c6c76..43f710c 100644 --- a/src/abstractappearance.cpp +++ b/src/abstractappearance.cpp @@ -1,84 +1,82 @@ /* KDE GTK Configuration Module * * Copyright 2011 Aleix Pol Gonzalez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "abstractappearance.h" #include #include #include static bool isTrue(const QString& value) { return value == "1" || value == "true"; } //SETTERS void AbstractAppearance::setTheme(const QString& name) { m_settings["theme"] = name;} -void AbstractAppearance::setPrimaryButtonWarpsSlider(bool enabled) { m_settings["primary_button_warps_slider"] = enabled ? "1" : "0"; } // GETTERS QString AbstractAppearance::getTheme() const { return m_settings["theme"];} QString AbstractAppearance::getThemeGtk3() const { return m_settings["themegtk3"]; } -bool AbstractAppearance::getPrimaryButtonWarpsSlider() const { return isTrue(m_settings["primary_button_warps_slider"]); } QRegExp valueRx(" *([a-zA-Z\\-_]+) *= *\"?([^\"\\n]+)\"?", Qt::CaseSensitive, QRegExp::RegExp2); QMap AbstractAppearance::readSettingsTuples(QIODevice* device) { QMap ret; QTextStream flow(device); for(; !flow.atEnd() ;) { QString line = flow.readLine(); int idxComment = line.indexOf('#'); if(idxComment>=0) line = line.left(idxComment).simplified(); if(valueRx.exactMatch(line)) ret[valueRx.cap(1)] = valueRx.cap(2); else if(line.startsWith("include \"")) { QString filename = line.mid(9); filename.chop(1); // qDebug() << "including: " << filename; QFile f(filename); if(f.open(QFile::Text|QFile::ReadOnly)) { ret.unite(readSettingsTuples(&f)); } else qWarning() << "couldn't include " << filename; } // else if(!line.isEmpty()) // qWarning() << "misinterpreted line" << line; } return ret; } QStringList AbstractAppearance::installedThemesNames() const { QStringList themes = installedThemes(); QStringList ret; foreach(const QString& theme, themes) ret += QDir(theme).dirName(); return ret; } bool AbstractAppearance::hasProperty(const QString& key) const { return !m_settings.value(key).isEmpty(); } diff --git a/src/abstractappearance.h b/src/abstractappearance.h index 3f5cb74..86b6349 100644 --- a/src/abstractappearance.h +++ b/src/abstractappearance.h @@ -1,57 +1,55 @@ /* KDE GTK Configuration Module * * Copyright 2011 Aleix Pol Gonzalez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef ABSTACTAPPEARANCE_H #define ABSTACTAPPEARANCE_H #include #include #include class AbstractAppearance { public: virtual ~AbstractAppearance() {} virtual bool loadSettings() = 0; virtual bool saveSettings() const = 0; virtual bool loadSettings(const QString& path) = 0; virtual bool saveSettings(const QString& path) const = 0; /** @returns the installed themes' paths*/ virtual QStringList installedThemes() const = 0; void setTheme(const QString& name); - void setPrimaryButtonWarpsSlider(bool enabled); QString getTheme() const; QString getThemeGtk3() const; - bool getPrimaryButtonWarpsSlider() const; QStringList installedThemesNames() const; bool hasProperty(const QString& key) const; static QMap readSettingsTuples(QIODevice* device); protected: QMap m_settings; }; #endif diff --git a/src/appearancegtk2.cpp b/src/appearancegtk2.cpp index ebdaef1..97da9e1 100644 --- a/src/appearancegtk2.cpp +++ b/src/appearancegtk2.cpp @@ -1,210 +1,209 @@ /* KDE GTK Configuration Module * * Copyright 2011 José Antonio Sanchez Reynaga * Copyright 2011 Aleix Pol Gonzalez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "appearancegtk2.h" #include #include #include #include #include #include #include #include #include bool AppearanceGTK2::loadSettingsPrivate(const QString& path) { QFile configFile(path); if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) return false; const QMap foundSettings = readSettingsTuples(&configFile); for(auto it = foundSettings.constBegin(), itEnd = foundSettings.constEnd(); it!=itEnd; ++it) { if (it.key() == "gtk-theme-name") m_settings["theme"] = *it; else if (it.key() == "gtk-primary-button-warps-slider") m_settings["primary_button_warps_slider"] = *it; } return true; } QString AppearanceGTK2::themesGtkrcFile(const QString& themeName) const { QStringList themes=installedThemes(); themes=themes.filter(QRegExp("/"+themeName+"/?$")); if(themes.size()==1) { QDirIterator it(themes.first(), QDirIterator::Subdirectories); while(it.hasNext()) { it.next(); if(it.fileName()=="gtkrc") { // qDebug() << "\tgtkrc file found at : " << it.filePath(); return it.filePath(); } } } return QString(); } bool AppearanceGTK2::saveSettingsPrivate(const QString& gtkrcFile) const { QFile gtkrc{gtkrcFile}; if (gtkrc.open(QIODevice::ReadWrite | QIODevice::Text)) { QString fileContents{gtkrc.readAll()}; modifyGtkrcContents(fileContents); gtkrc.remove(); gtkrc.open(QIODevice::WriteOnly | QIODevice::Text); gtkrc.write(fileContents.toUtf8()); if (QFileInfo(gtkrc).filePath() == defaultConfigFile()) { QProcess::startDetached(QStandardPaths::findExecutable("reload_gtk_apps", {CMAKE_INSTALL_FULL_LIBEXECDIR})); } return true; } else { qWarning() << "There was unable to write the .gtkrc-2.0 file"; return false; } } void AppearanceGTK2::modifyGtkrcContents(QString& fileContents) const { modifyGtkrcProperty("gtk-theme-name", m_settings["theme"], fileContents); - modifyGtkrcProperty("gtk-primary-button-warps-slider", m_settings["primary_button_warps_slider"], fileContents); removeGtkrcLegacyContents(fileContents); } void AppearanceGTK2::modifyGtkrcProperty(const QString& propertyName, const QString& newValue, QString& fileContents) const { const QRegularExpression regExp{propertyName + "=[^\n]*($|\n)"}; static const QStringList nonStringProperties{ "gtk-toolbar-style", "gtk-menu-images", "gtk-button-images", "gtk-primary-button-warps-slider", }; QString newConfigString; if (nonStringProperties.contains(propertyName)) { newConfigString = propertyName + "=" + newValue + "\n"; } else { newConfigString = propertyName + "=\"" + newValue + "\"\n"; } if (fileContents.contains(regExp)) { fileContents.replace(regExp, newConfigString); } else { fileContents = newConfigString + "\n" + fileContents; } } void AppearanceGTK2::removeGtkrcLegacyContents(QString &fileContents) const { // Remove "include" lines // Example: // include "/usr/share/themes/Adwaita-dark/gtk-2.0/gtkrc" static const QRegularExpression includeRegExp(QStringLiteral("include .*\n")); fileContents.remove(includeRegExp); // Remove redundant font config lines // Example: // style "user-font" // { // font_name="Noto Sans Regular" // } // widget_class "*" style "user-font" static const QRegularExpression userFontStyleRegexp(QStringLiteral("style(.|\n)*{(.|\n)*}\nwidget_class.*\"user-font\"")); fileContents.remove(userFontStyleRegexp); } void AppearanceGTK2::reset() { m_settings = QMap { {"toolbar_style", "GTK_TOOLBAR_ICONS"}, {"show_icons_buttons", "0"}, {"show_icons_menus", "0"}, {"primary_button_warps_slider", "false"} }; } QString AppearanceGTK2::defaultConfigFile() const { return QDir::homePath()+"/.gtkrc-2.0"; } QStringList AppearanceGTK2::installedThemes() const { QFileInfoList availableThemes; foreach(const QString& themesDir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "themes", QStandardPaths::LocateDirectory)) { QDir root(themesDir); availableThemes += root.entryInfoList(QDir::NoDotAndDotDot|QDir::AllDirs); } //Check if there are themes installed by the user QDir user(QDir::homePath()+"/.themes"); availableThemes += user.entryInfoList(QDir::NoDotAndDotDot|QDir::AllDirs); //we just want actual themes QStringList paths; for(QFileInfoList::const_iterator it=availableThemes.constBegin(); it!=availableThemes.constEnd(); ++it) { bool hasGtkrc = QDir(it->filePath()).exists("gtk-2.0"); //If it doesn't exist, we don't want it on the list if(hasGtkrc) paths += it->filePath(); } return paths; } bool AppearanceGTK2::loadSettings() { reset(); bool b = loadSettingsPrivate("/etc/gtk-2.0/gtkrc"); b |= loadSettingsPrivate(defaultConfigFile()); return b; } bool AppearanceGTK2::saveSettings() const { return saveSettings(defaultConfigFile()); } bool AppearanceGTK2::loadSettings(const QString& gtkrcFile) { reset(); return loadSettingsPrivate(gtkrcFile); } bool AppearanceGTK2::saveSettings(const QString& gtkrcFile) const { return saveSettingsPrivate(gtkrcFile); } diff --git a/src/appearancegtk3.cpp b/src/appearancegtk3.cpp index 78868ce..7c8589a 100644 --- a/src/appearancegtk3.cpp +++ b/src/appearancegtk3.cpp @@ -1,158 +1,157 @@ /* KDE GTK Configuration Module * * Copyright 2011 José Antonio Sanchez Reynaga * Copyright 2011 Aleix Pol Gonzalez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "appearancegtk3.h" #include #include #include #include #include #include #undef signals #include #include #define signals Q_SIGNALS QStringList AppearanceGTK3::installedThemes() const { QFileInfoList availableThemes; foreach(const QString& themesDir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "themes", QStandardPaths::LocateDirectory)) { QDir root(themesDir); availableThemes += root.entryInfoList(QDir::NoDotAndDotDot|QDir::AllDirs); } //Also show the user-installed themes QDir user(QDir::homePath()+"/.themes"); availableThemes += user.entryInfoList(QDir::NoDotAndDotDot|QDir::AllDirs); //we just want actual themes QStringList themes; // Check that the theme contains a gtk-3.* subdirectory QStringList gtk3SubdirPattern{QStringLiteral("gtk-3.*")}; for(QFileInfoList::const_iterator it=availableThemes.constBegin(); it!=availableThemes.constEnd(); ++it) { QDir themeDir(it->filePath()); if(!themeDir.entryList(gtk3SubdirPattern, QDir::Dirs).isEmpty()) themes += it->filePath(); } return themes; } bool AppearanceGTK3::saveSettings(const KSharedConfig::Ptr& file) const { KConfigGroup group(file, "Settings"); group.writeEntry("gtk-theme-name", m_settings["theme"]); - group.writeEntry("gtk-primary-button-warps-slider", m_settings["primary_button_warps_slider"]); group.writeEntry("gtk-application-prefer-dark-theme", m_settings["application_prefer_dark_theme"]); const bool sync = group.sync(); Q_ASSERT(sync); return true; } bool AppearanceGTK3::loadSettings(const KSharedConfig::Ptr& file) { KConfigGroup group(file, "Settings"); if (!file || !group.isValid()) { qWarning() << "Cannot open the GTK3 config file" << file; return false; } m_settings = QMap { {"primary_button_warps_slider", "false"}, {"application_prefer_dark_theme", "false"} }; m_settings["theme"] = group.readEntry("gtk-theme-name"); m_settings["primary_button_warps_slider"] = group.readEntry("gtk-primary-button-warps-slider"); m_settings["application_prefer_dark_theme"] = group.readEntry("gtk-application-prefer-dark-theme"); for(auto it = m_settings.begin(); it != m_settings.end(); ) { if (it.value().isEmpty()) it = m_settings.erase(it); else ++it; } return true; } QString AppearanceGTK3::configFileName() const { return QStringLiteral("gtk-3.0/settings.ini"); } QString AppearanceGTK3::defaultConfigFile() const { QString root = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); if(root.isEmpty()) root = QFileInfo(QDir::home(), ".config").absoluteFilePath(); return root + '/' + configFileName(); } bool AppearanceGTK3::getApplicationPreferDarkTheme() const { return m_settings["application_prefer_dark_theme"] == "1" || m_settings["application_prefer_dark_theme"] == "true"; } void AppearanceGTK3::setApplicationPreferDarkTheme(const bool& enable) { m_settings["application_prefer_dark_theme"] = enable ? "true" : "false"; } bool AppearanceGTK3::saveSettings(const QString& file) const { auto cfg = KSharedConfig::openConfig(file, KConfig::NoGlobals); return saveSettings(cfg); } bool AppearanceGTK3::loadSettings(const QString& path) { auto cfg = KSharedConfig::openConfig(path, KConfig::NoGlobals); return loadSettings(cfg); } bool AppearanceGTK3::loadSettings() { auto cfg = KSharedConfig::openConfig(configFileName(), KConfig::NoGlobals); return loadSettings(cfg); } bool AppearanceGTK3::saveSettings() const { // FIXME kdebz#387417 // We should maybe use GSettings everywhere in future, but at this moment we // need this to have this configuration available in sandboxed applications which // is only possible through dconf gtk_init(nullptr, nullptr); g_autoptr(GSettings) gsettings = g_settings_new("org.gnome.desktop.interface"); g_settings_set_string(gsettings, "gtk-theme", m_settings["theme"].toUtf8().constData()); g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", getApplicationPreferDarkTheme(), nullptr); auto cfg = KSharedConfig::openConfig(configFileName(), KConfig::NoGlobals); return saveSettings(cfg); } diff --git a/src/appearencegtk.cpp b/src/appearencegtk.cpp index b2ce09c..25ad4e9 100644 --- a/src/appearencegtk.cpp +++ b/src/appearencegtk.cpp @@ -1,76 +1,70 @@ /* KDE GTK Configuration Module * * Copyright 2011 José Antonio Sanchez Reynaga * Copyright 2011 Aleix Pol Gonzalez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "appearencegtk.h" #include #include "abstractappearance.h" #include "appearancegtk2.h" #include "appearancegtk3.h" AppearenceGTK::AppearenceGTK() { m_app << new AppearanceGTK2; m_app << new AppearanceGTK3; } AppearenceGTK::~AppearenceGTK() { qDeleteAll(m_app); } -#define PROPERTY_IMPLEMENTATION(type, name, propname)\ -void AppearenceGTK::set##name(const type& a) { foreach(AbstractAppearance* app, m_app) app->set##name(a); }\ -type AppearenceGTK::get##name() const { foreach(AbstractAppearance* app, m_app) { if(app->hasProperty(propname)) return app->get##name(); } /*Q_ASSERT(false);*/ return type (); } - -PROPERTY_IMPLEMENTATION(bool, PrimaryButtonWarpsSlider, "primary_button_warps_slider") - QString AppearenceGTK::getTheme() const { return gtk2Appearance()->getTheme(); } void AppearenceGTK::setTheme(const QString& name) { return gtk2Appearance()->setTheme(name); } QString AppearenceGTK::getThemeGtk3() const { return gtk3Appearance()->getTheme(); } void AppearenceGTK::setThemeGtk3(const QString& name) { return gtk3Appearance()->setTheme(name); } bool AppearenceGTK::getApplicationPreferDarkTheme() const { return ((AppearanceGTK3*)gtk3Appearance())->getApplicationPreferDarkTheme(); } void AppearenceGTK::setApplicationPreferDarkTheme(const bool& enable) { return ((AppearanceGTK3*)gtk3Appearance())->setApplicationPreferDarkTheme(enable); } //////////////////////////////////// // Methods responsible of file creation bool AppearenceGTK::loadFileConfig() { bool correct = false; foreach(AbstractAppearance* app, m_app) { bool c = app->loadSettings(); correct = correct || c; } // qDebug() << "loading..." << correct; return correct; } bool AppearenceGTK::saveFileConfig() { bool correct = true; foreach(AbstractAppearance* app, m_app) { bool c = app->saveSettings(); correct = correct && c; } // qDebug() << "saving..." << correct; return correct; } diff --git a/src/gtkconfigkcmodule.cpp b/src/gtkconfigkcmodule.cpp index 28c036e..124c7c5 100644 --- a/src/gtkconfigkcmodule.cpp +++ b/src/gtkconfigkcmodule.cpp @@ -1,397 +1,388 @@ /* KDE GTK Configuration Module * * Copyright 2011 José Antonio Sanchez Reynaga * Copyright 2011 Aleix Pol Gonzalez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "gtkconfigkcmodule.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_gui.h" #include "abstractappearance.h" #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(GTKConfigKCModuleFactory, "kde-gtk-config.json", registerPlugin();) GTKConfigKCModule::GTKConfigKCModule(QWidget* parent, const QVariantList& args ) : KCModule(parent) , ui(new Ui::GUI) , installer(0) , uninstaller(0) , m_saveEnabled(true) { Q_UNUSED(args); KAboutData *acercade = new KAboutData("cgc", i18n("GTK Application Style"), PROJECT_VERSION, QString(), KAboutLicense::LGPL_V3, i18n("Copyright 2011 José Antonio Sánchez Reynaga")); acercade->addAuthor(i18n("José Antonio Sánchez Reynaga (antonioJASR)"),i18n("Main Developer"), "joanzare@gmail.com"); acercade->addAuthor(i18n("Aleix Pol i Gonzalez"), i18n("Feature development. Previews, code refactoring."), "aleixpol@blue-systems.com"); acercade->addCredit(i18n("Manuel Tortosa (manutortosa)"), i18n("Ideas, tester, internationalization")); acercade->addCredit(i18n("Adrián Chaves Fernández (Gallaecio)"), i18n("Internationalization")); setAboutData(acercade); setButtons(KCModule::Default | KCModule::Apply); ui->setupUi(this); appareance = new AppearenceGTK; m_tempGtk2Preview = QStandardPaths::writableLocation(QStandardPaths::TempLocation)+ "/gtkrc-2.0"; m_tempGtk3Preview = QStandardPaths::writableLocation(QStandardPaths::TempLocation)+ "/.config/gtk-3.0/settings.ini"; const QIcon previewIcon = QIcon::fromTheme("document-preview"); ui->gtk2Preview->setIcon(previewIcon); ui->gtk3Preview->setIcon(previewIcon); QString gtk2Preview = QStandardPaths::findExecutable("gtk_preview", {CMAKE_INSTALL_FULL_LIBEXECDIR}); QString gtk3Preview = QStandardPaths::findExecutable("gtk3_preview", {CMAKE_INSTALL_FULL_LIBEXECDIR}); m_p2 = new KProcess(this); m_p2->setEnv("GTK2_RC_FILES", m_tempGtk2Preview, true); if(!gtk2Preview.isEmpty()) { *m_p2 << gtk2Preview; connect(m_p2, SIGNAL(finished(int)), this, SLOT(untogglePreview())); } m_p3 = new KProcess(this); m_p3->setEnv("XDG_CONFIG_HOME", QStandardPaths::writableLocation(QStandardPaths::TempLocation)+"/.config"); if(!gtk3Preview.isEmpty()) { *m_p3 << gtk3Preview; connect(m_p3, SIGNAL(finished(int)), this, SLOT(untogglePreview())); } ui->gtk2Preview->setVisible(!gtk2Preview.isEmpty()); ui->gtk3Preview->setVisible(!gtk3Preview.isEmpty()); //UI changes connect(ui->cb_theme, SIGNAL(currentIndexChanged(int)), this, SLOT(appChanged())); connect(ui->cb_theme_gtk3, SIGNAL(currentIndexChanged(int)), this, SLOT(appChanged())); connect(ui->checkBox_theme_gtk3_prefer_dark, &QAbstractButton::clicked, this, >KConfigKCModule::appChanged); connect(ui->buttonGroup_primary_button_warps_slider, SIGNAL(buttonToggled(QAbstractButton*, bool)), this, SLOT(appChanged())); //preview updates connect(ui->gtk2Preview, &QAbstractButton::clicked, this, >KConfigKCModule::runGtk2IfNecessary); connect(ui->gtk3Preview, &QAbstractButton::clicked, this, >KConfigKCModule::runGtk3IfNecessary); QMenu* m = new QMenu(this); m->addAction(QIcon::fromTheme("get-hot-new-stuff"), i18n("Download GTK2 themes..."), this, >KConfigKCModule::showThemeGHNS); m->addAction(QIcon::fromTheme("get-hot-new-stuff"), i18n("Download GTK3 themes..."), this, >KConfigKCModule::installThemeGTK3GHNS); m->addAction(QIcon::fromTheme("archive-insert"), i18n("Install a local theme..."), this, >KConfigKCModule::showDialogForInstall); m->addAction(QIcon::fromTheme("archive-remove"), i18n("Uninstall a local theme..."), this, >KConfigKCModule::showDialogForUninstall); ui->newThemes->setMenu(m); ui->newThemes->setIcon(QIcon::fromTheme("get-hot-new-stuff")); } GTKConfigKCModule::~GTKConfigKCModule() { m_p2->kill(); m_p3->kill(); QFile::remove(m_tempGtk2Preview); QFile::remove(m_tempGtk3Preview); delete appareance; m_p2->waitForFinished(); m_p3->waitForFinished(); delete ui; } void GTKConfigKCModule::syncUI() { appareance->setThemeGtk3(ui->cb_theme_gtk3->currentText()); appareance->setTheme(ui->cb_theme->currentText()); appareance->setApplicationPreferDarkTheme(ui->checkBox_theme_gtk3_prefer_dark->isChecked()); - - appareance->setPrimaryButtonWarpsSlider(ui->buttonGroup_primary_button_warps_slider->checkedButton() == ui->radioButton_warp); } void GTKConfigKCModule::showThemeGHNS() { KNS3::DownloadDialog d("cgctheme.knsrc", this); if(d.exec()) { refreshLists(); } } void GTKConfigKCModule::installThemeGTK3GHNS() { KNS3::DownloadDialog d("cgcgtk3.knsrc", this); if(d.exec()) { refreshLists(); } } void GTKConfigKCModule::refreshLists() { refreshThemesUi(true); - - const bool warps = appareance->getPrimaryButtonWarpsSlider(); - ui->radioButton_warp->setChecked(warps); - ui->radioButton_dont_warp->setChecked(!warps); } void GTKConfigKCModule::appChanged() { if (m_loading) return; savePreviewConfig(); emit changed(true); } void GTKConfigKCModule::savePreviewConfig() { if(!m_saveEnabled || !(ui->gtk2Preview->isChecked() || ui->gtk3Preview->isChecked())) return; // qDebug() << "saving UI..."; syncUI(); if(ui->gtk3Preview->isChecked()) { //we don't want to recursively loop between savePreviewConfig and runIfNecessary m_saveEnabled = false; m_p3->kill(); appareance->gtk3Appearance()->saveSettings(m_tempGtk3Preview); //need to make sure runIfNecessary() to know that it's not running m_p3->waitForFinished(); m_p3->start(); ui->gtk3Preview->setChecked(true); m_saveEnabled = true; } else if(ui->gtk2Preview->isChecked()) { appareance->gtk2Appearance()->saveSettings(m_tempGtk2Preview); } } void GTKConfigKCModule::runGtk2IfNecessary(bool checked) { KProcess* p = m_p2; KProcess* np = m_p3; if(checked) { np->kill(); np->waitForFinished(); savePreviewConfig(); if(p->state() == QProcess::NotRunning) p->start(); } else { p->kill(); p->waitForFinished(); } } void GTKConfigKCModule::runGtk3IfNecessary(bool checked) { KProcess* p = m_p3; KProcess* np = m_p2; if(checked) { np->kill(); np->waitForFinished(); savePreviewConfig(); if(p->state() == QProcess::NotRunning) p->start(); } else { p->kill(); p->waitForFinished(); } } void GTKConfigKCModule::save() { /* qDebug() << "******************************************* INSTALLATION :\n" << "theme : " << appareance->getTheme() << "\n" << "themeGTK3 : " << appareance->getThemeGtk3() << "\n" << "********************************************************"; */ syncUI(); if(!appareance->saveFileConfig()) KMessageBox::error(this, i18n("Failed to save configuration.")); } void setComboItem(QComboBox* combo, const QStringList& texts) { foreach(const QString& text, texts) { int pos = combo->findText(text); if(pos>=0) { combo->setCurrentIndex(pos); return; } } } void GTKConfigKCModule::defaults() { refreshThemesUi(false); // qDebug() << "loading defaults..."; m_saveEnabled = false; - - // this makes it consistent with Qt apps and restores the old Gtk behavior - ui->radioButton_dont_warp->setChecked(true); setComboItem(ui->cb_theme, QStringList("oxygen-gtk") << "Clearlooks"); setComboItem(ui->cb_theme_gtk3, QStringList("oxygen-gtk") << "Adwaita"); m_saveEnabled = true; appChanged(); } void GTKConfigKCModule::load() { m_saveEnabled = false; bool someCorrect = appareance->loadFileConfig(); m_loading = true; if(someCorrect) { refreshLists(); } else { defaults(); } m_loading = false; m_saveEnabled = true; } class MyStringListModel : public QAbstractListModel { public: MyStringListModel(const QStringList &texts, QObject* parent) : QAbstractListModel(parent), m_texts(texts) { } QVariant data(const QModelIndex & index, int role) const override { if (role != Qt::DisplayRole || !index.isValid() || index.row()>=m_texts.count()) return {}; return m_texts[index.row()]; } int rowCount(const QModelIndex & parent) const override { return parent.isValid() ? 0 : m_texts.count(); } void setStrings(const QSet &list) { const auto current = m_texts.toSet(); const auto oldRows = QSet(current).subtract(list); const auto newRows = QSet(list).subtract(current); if (!newRows.isEmpty()) { beginInsertRows({}, m_texts.count(), m_texts.count() + newRows.count()); m_texts += newRows.toList(); endInsertRows(); } int from = -1; for(const auto &row: oldRows) { for(; from(combo->model()); if (!model) { combo->setModel(new MyStringListModel(texts, combo)); } else { model->setStrings(texts.toSet()); } const int idx = combo->findText(temp); combo->setCurrentIndex(qMax(0, idx)); } void GTKConfigKCModule::refreshThemesUi(bool useConfig) { //theme gtk2 bool wasenabled = m_saveEnabled; m_saveEnabled = false; refreshComboSameCurrentValue(ui->cb_theme, useConfig ? appareance->getTheme() : ui->cb_theme->currentText(), appareance->gtk2Appearance()->installedThemesNames()); //theme gtk3 refreshComboSameCurrentValue(ui->cb_theme_gtk3, useConfig ? appareance->getThemeGtk3() : ui->cb_theme_gtk3->currentText(), appareance->gtk3Appearance()->installedThemesNames()); // dark theme for gtk3 ui->checkBox_theme_gtk3_prefer_dark->setChecked(appareance->getApplicationPreferDarkTheme()); m_saveEnabled = wasenabled; emit changed(true); } void GTKConfigKCModule::showDialogForInstall() { if(!installer) { installer = new DialogInstaller(this); connect(installer, &DialogInstaller::themeInstalled, this, >KConfigKCModule::refreshLists); } installer->exec(); refreshThemesUi(); } void GTKConfigKCModule::showDialogForUninstall() { if(!uninstaller) { uninstaller = new DialogUninstaller(this, appareance); connect(uninstaller, &DialogUninstaller::themeUninstalled, this, >KConfigKCModule::refreshLists); } uninstaller->refreshListsForUninstall(); uninstaller->exec(); refreshThemesUi(); } void GTKConfigKCModule::untogglePreview() { if(sender()==m_p2) ui->gtk2Preview->setChecked(false); else ui->gtk3Preview->setChecked(false); } #include "gtkconfigkcmodule.moc" diff --git a/src/ui/gui.ui b/src/ui/gui.ui index 05e6023..45510a7 100644 --- a/src/ui/gui.ui +++ b/src/ui/gui.ui @@ -1,198 +1,168 @@ GUI 0 0 900 600 Qt::Horizontal 40 20 GTK2 theme: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter QComboBox::AdjustToContents Preview Theme true GTK3 theme: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter QComboBox::AdjustToContents Preview Theme true Prefer dark theme - - - - On scrollbar left-click: - - - - - - - Scro&ll one page up/down - - - true - - - buttonGroup_primary_button_warps_slider - - - - - - - &Jump to mouse cursor position - - - buttonGroup_primary_button_warps_slider - - - Qt::Horizontal 40 20 Qt::Vertical 0 0 Qt::Horizontal 0 0 <html><head/><body><p>Here you can install new GTK themes. Even more are available at <a href="http://gnome-look.org"><span style=" text-decoration: underline;">gnome-look.org</span></a></p></body></html> Get New GNOME/GTK Application Styles... .. diff --git a/tests/configsavetest.cpp b/tests/configsavetest.cpp index a1582df..37e4d38 100644 --- a/tests/configsavetest.cpp +++ b/tests/configsavetest.cpp @@ -1,73 +1,71 @@ /* * */ #include "configsavetest.h" #include #include #include QTEST_GUILESS_MAIN(ConfigSaveTest); ConfigSaveTest::ConfigSaveTest() { QStandardPaths::setTestModeEnabled(true); } static void fillValues(QScopedPointer& a) { a->setTheme("a"); - a->setPrimaryButtonWarpsSlider(true); auto a3 = dynamic_cast(a.data()); if (a3) { a3->setApplicationPreferDarkTheme(false); } } void compareAppearances(QScopedPointer& reloaded, QScopedPointer& instance) { QCOMPARE(reloaded->getTheme(), instance->getTheme()); - QCOMPARE(reloaded->getPrimaryButtonWarpsSlider(), instance->getPrimaryButtonWarpsSlider()); } QByteArray readFile(const QString& path) { QFile f(path); if(!f.open(QFile::ReadOnly | QFile::Text)) return QByteArray(); return f.readAll(); } void ConfigSaveTest::testGtk2() { const QString pathA = QDir::current().absoluteFilePath("test-gtk2") , pathB = QDir::current().absoluteFilePath("testB-gtk2"); QScopedPointer instance(new AppearanceGTK2); fillValues(instance); QVERIFY(instance->saveSettings(pathA)); QScopedPointer reloaded(new AppearanceGTK2); QVERIFY(reloaded->loadSettings(pathA)); compareAppearances(reloaded, instance); QVERIFY(reloaded->saveSettings(pathB)); QCOMPARE(readFile(pathA), readFile(pathB)); } void ConfigSaveTest::testGtk3() { QScopedPointer instance(new AppearanceGTK3); fillValues(instance); const QString pathA = QDir::current().absoluteFilePath("test-gtk3") , pathB = QDir::current().absoluteFilePath("testB-gtk3"); QVERIFY(instance->saveSettings(pathA)); QScopedPointer reloaded(new AppearanceGTK3); QVERIFY(QFile::exists(pathA)); QVERIFY(reloaded->loadSettings(pathA)); compareAppearances(reloaded, instance); QVERIFY(reloaded->saveSettings(pathB)); QCOMPARE(readFile(pathA), readFile(pathB)); }