Commit 7f52a95b authored by Bhushan Shah's avatar Bhushan Shah 📱
Browse files

kcms: move desktoptheme and icons kcm to plasma-workspace

They can be useful for mobile, they are taken from the git master of
plasma-desktop at 5d8a64ce569b5592d073eaff5f7e8a0c243fc515 sha.
parent 0b73287c
......@@ -7,7 +7,7 @@ set(PROJECT_VERSION_MAJOR 5)
set(QT_MIN_VERSION "5.14.0")
set(KF5_MIN_VERSION "5.72.0")
set(INSTALL_SDDM_THEME TRUE)
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Widgets Quick QuickWidgets Concurrent Test Network)
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Svg Widgets Quick QuickWidgets Concurrent Test Network)
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
......
add_subdirectory(desktoptheme)
add_subdirectory(icons)
add_subdirectory(translations)
if(KUserFeedback_FOUND)
......
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_desktoptheme\")
set(kcm_desktoptheme_SRCS
kcm.cpp
themesmodel.cpp
filterproxymodel.cpp
)
kconfig_add_kcfg_files(kcm_desktoptheme_SRCS desktopthemesettings.kcfgc GENERATE_MOC)
add_library(kcm_desktoptheme MODULE ${kcm_desktoptheme_SRCS})
target_link_libraries(kcm_desktoptheme
KF5::CoreAddons
KF5::KCMUtils
KF5::KIOCore
KF5::KIOWidgets
KF5::I18n
KF5::Plasma
KF5::Declarative
KF5::QuickAddons
)
kcoreaddons_desktop_to_json(kcm_desktoptheme "kcm_desktoptheme.desktop" SERVICE_TYPES kcmodule.desktop)
#this desktop file is installed only for retrocompatibility with sycoca
install(FILES kcm_desktoptheme.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(FILES plasma-themes.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR})
install(TARGETS kcm_desktoptheme DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
kpackage_install_package(package kcm_desktoptheme kcms)
#! /usr/bin/env bash
$EXTRACTRC `find . -name "*.kcfg"` >> rc.cpp || exit 11
$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_desktoptheme.pot
rm -f rc.cpp
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="plasmarc" />
<group name="Theme">
<entry name="name" type="String">
<label>Name of the current Plasma Style</label>
<default>default</default>
</entry>
</group>
</kcfg>
File=desktopthemesettings.kcfg
ClassName=DesktopThemeSettings
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
ParentInConstructor=true
/*
* Copyright (C) 2019 Kai Uwe Broulik <kde@privat.broulik.de>
* Copyright (c) 2019 David Redondo <kde@david-redondo.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 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 14 of version 3 of the license.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "filterproxymodel.h"
#include "themesmodel.h"
FilterProxyModel::FilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
{
}
FilterProxyModel::~FilterProxyModel() = default;
QString FilterProxyModel::selectedTheme() const
{
return m_selectedTheme;
}
void FilterProxyModel::setSelectedTheme(const QString &pluginName)
{
if (m_selectedTheme == pluginName) {
return;
}
const bool firstTime = m_selectedTheme.isNull();
m_selectedTheme = pluginName;
if (!firstTime) {
emit selectedThemeChanged();
}
emit selectedThemeIndexChanged();
}
int FilterProxyModel::selectedThemeIndex() const
{
// We must search in the source model and then map the index to our proxy model.
const auto results = sourceModel()->match(sourceModel()->index(0, 0), ThemesModel::PluginNameRole, m_selectedTheme);
if (results.count() == 1) {
const QModelIndex result = mapFromSource(results.first());
if (result.isValid()) {
return result.row();
}
}
return -1;
}
QString FilterProxyModel::query() const
{
return m_query;
}
void FilterProxyModel::setQuery(const QString &query)
{
if (m_query != query) {
const int oldIndex = selectedThemeIndex();
m_query = query;
invalidateFilter();
emit queryChanged();
if (selectedThemeIndex() != oldIndex) {
emit selectedThemeIndexChanged();
}
}
}
FilterProxyModel::ThemeFilter FilterProxyModel::filter() const
{
return m_filter;
}
void FilterProxyModel::setFilter(ThemeFilter filter)
{
if (m_filter != filter) {
const int oldIndex = selectedThemeIndex();
m_filter = filter;
invalidateFilter();
emit filterChanged();
if (selectedThemeIndex() != oldIndex) {
emit selectedThemeIndexChanged();
}
}
}
bool FilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
const QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent);
if (!m_query.isEmpty()) {
if (!idx.data(Qt::DisplayRole).toString().contains(m_query, Qt::CaseInsensitive)
&& !idx.data(ThemesModel::PluginNameRole).toString().contains(m_query, Qt::CaseInsensitive)) {
return false;
}
}
const auto type = idx.data(ThemesModel::ColorTypeRole).value<ThemesModel::ColorType>();
switch (m_filter) {
case AllThemes:
return true;
case LightThemes:
return type == ThemesModel::LightTheme;
case DarkThemes:
return type == ThemesModel::DarkTheme;
case ThemesFollowingColors:
return type == ThemesModel::FollowsColorTheme;
}
return true;
}
/*
* Copyright (c) 2019 Kai Uwe Broulik <kde@privat.broulik.de>
* Copyright (c) 2019 David Redondo <kde@david-redondo.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 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 14 of version 3 of the license.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QSortFilterProxyModel>
#include "kcm.h"
class FilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
enum ThemeFilter {
AllThemes,
LightThemes,
DarkThemes,
ThemesFollowingColors
};
Q_ENUM(ThemeFilter)
Q_PROPERTY(QString selectedTheme READ selectedTheme WRITE setSelectedTheme NOTIFY selectedThemeChanged)
Q_PROPERTY(int selectedThemeIndex READ selectedThemeIndex NOTIFY selectedThemeIndexChanged)
Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
Q_PROPERTY(ThemeFilter filter READ filter WRITE setFilter NOTIFY filterChanged)
FilterProxyModel(QObject *parent = nullptr);
~FilterProxyModel() override;
QString selectedTheme() const;
void setSelectedTheme(const QString &pluginName);
int selectedThemeIndex() const;
QString query() const;
void setQuery(const QString &query);
ThemeFilter filter() const;
void setFilter(ThemeFilter filter);
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
Q_SIGNALS:
void filterChanged();
void queryChanged();
void selectedThemeChanged();
void selectedThemeIndexChanged();
private:
QString m_selectedTheme;
QString m_query;
ThemeFilter m_filter = AllThemes;
};
/* This file is part of the KDE Project
Copyright (c) 2014 Marco Martin <mart@kde.org>
Copyright (c) 2014 Vishesh Handa <me@vhanda.in>
Copyright (c) 2016 David Rosca <nowrep@gmail.com>
Copyright (c) 2018 Kai Uwe Broulik <kde@privat.broulik.de>
Copyright (c) 2019 Kevin Ottens <kevin.ottens@enioka.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kcm.h"
#include <KPluginFactory>
#include <KAboutData>
#include <KLocalizedString>
#include <KIO/FileCopyJob>
#include <KIO/JobUiDelegate>
#include <Plasma/Theme>
#include <Plasma/Svg>
#include <QDebug>
#include <QProcess>
#include <QQuickItem>
#include <QQuickWindow>
#include <QStandardPaths>
#include <QStandardItemModel>
#include <QTemporaryFile>
#include "desktopthemesettings.h"
#include "filterproxymodel.h"
#include "themesmodel.h"
Q_LOGGING_CATEGORY(KCM_DESKTOP_THEME, "kcm_desktoptheme")
K_PLUGIN_FACTORY_WITH_JSON(KCMDesktopThemeFactory, "kcm_desktoptheme.json", registerPlugin<KCMDesktopTheme>();)
KCMDesktopTheme::KCMDesktopTheme(QObject *parent, const QVariantList &args)
: KQuickAddons::ManagedConfigModule(parent, args)
, m_settings(new DesktopThemeSettings(this))
, m_model(new ThemesModel(this))
, m_filteredModel(new FilterProxyModel(this))
, m_haveThemeExplorerInstalled(false)
{
qmlRegisterType<DesktopThemeSettings>();
qmlRegisterUncreatableType<ThemesModel>("org.kde.private.kcms.desktoptheme", 1, 0, "ThemesModel", "Cannot create ThemesModel");
qmlRegisterUncreatableType<FilterProxyModel>("org.kde.private.kcms.desktoptheme", 1, 0, "FilterProxyModel", "Cannot create FilterProxyModel");
KAboutData* about = new KAboutData(QStringLiteral("kcm_desktoptheme"), i18n("Plasma Style"),
QStringLiteral("0.1"), QString(), KAboutLicense::LGPL);
about->addAuthor(i18n("David Rosca"), QString(), QStringLiteral("nowrep@gmail.com"));
setAboutData(about);
setButtons(Apply | Default | Help);
m_haveThemeExplorerInstalled = !QStandardPaths::findExecutable(QStringLiteral("plasmathemeexplorer")).isEmpty();
connect(m_model, &ThemesModel::pendingDeletionsChanged, this, &KCMDesktopTheme::settingsChanged);
connect(m_model, &ThemesModel::selectedThemeChanged, this, [this](const QString &pluginName) {
m_settings->setName(pluginName);
});
connect(m_settings, &DesktopThemeSettings::nameChanged, this, [this] {
m_model->setSelectedTheme(m_settings->name());
});
connect(m_model, &ThemesModel::selectedThemeChanged, m_filteredModel, &FilterProxyModel::setSelectedTheme);
m_filteredModel->setSourceModel(m_model);
}
KCMDesktopTheme::~KCMDesktopTheme()
{
}
DesktopThemeSettings *KCMDesktopTheme::desktopThemeSettings() const
{
return m_settings;
}
ThemesModel *KCMDesktopTheme::desktopThemeModel() const
{
return m_model;
}
FilterProxyModel *KCMDesktopTheme::filteredModel() const
{
return m_filteredModel;
}
bool KCMDesktopTheme::downloadingFile() const
{
return m_tempCopyJob;
}
void KCMDesktopTheme::installThemeFromFile(const QUrl &url)
{
if (url.isLocalFile()) {
installTheme(url.toLocalFile());
return;
}
if (m_tempCopyJob) {
return;
}
m_tempInstallFile.reset(new QTemporaryFile());
if (!m_tempInstallFile->open()) {
emit showErrorMessage(i18n("Unable to create a temporary file."));
m_tempInstallFile.reset();
return;
}
m_tempCopyJob = KIO::file_copy(url, QUrl::fromLocalFile(m_tempInstallFile->fileName()),
-1, KIO::Overwrite);
m_tempCopyJob->uiDelegate()->setAutoErrorHandlingEnabled(true);
emit downloadingFileChanged();
connect(m_tempCopyJob, &KIO::FileCopyJob::result, this, [this, url](KJob *job) {
if (job->error() != KJob::NoError) {
emit showErrorMessage(i18n("Unable to download the theme: %1", job->errorText()));
return;
}
installTheme(m_tempInstallFile->fileName());
m_tempInstallFile.reset();
});
connect(m_tempCopyJob, &QObject::destroyed, this, &KCMDesktopTheme::downloadingFileChanged);
}
void KCMDesktopTheme::installTheme(const QString &path)
{
qCDebug(KCM_DESKTOP_THEME) << "Installing ... " << path;
const QString program = QStringLiteral("kpackagetool5");
const QStringList arguments = { QStringLiteral("--type"), QStringLiteral("Plasma/Theme"), QStringLiteral("--install"), path};
qCDebug(KCM_DESKTOP_THEME) << program << arguments.join(QLatin1Char(' '));
QProcess *myProcess = new QProcess(this);
connect(myProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
Q_UNUSED(exitStatus)
if (exitCode == 0) {
emit showSuccessMessage(i18n("Theme installed successfully."));
load();
} else {
Q_EMIT showErrorMessage(i18n("Theme installation failed."));
}
});
connect(myProcess, &QProcess::errorOccurred,
this, [this](QProcess::ProcessError e) {
qCWarning(KCM_DESKTOP_THEME) << "Theme installation failed: " << e;
Q_EMIT showErrorMessage(i18n("Theme installation failed."));
});
myProcess->start(program, arguments);
}
void KCMDesktopTheme::applyPlasmaTheme(QQuickItem *item, const QString &themeName)
{
if (!item) {
return;
}
Plasma::Theme *theme = m_themes[themeName];
if (!theme) {
theme = new Plasma::Theme(themeName, this);
m_themes[themeName] = theme;
}
Q_FOREACH (Plasma::Svg *svg, item->findChildren<Plasma::Svg*>()) {
svg->setTheme(theme);
svg->setUsingRenderingCache(false);
}
}
void KCMDesktopTheme::load()
{
ManagedConfigModule::load();
m_model->load();
m_model->setSelectedTheme(m_settings->name());
}
void KCMDesktopTheme::save()
{
ManagedConfigModule::save();
Plasma::Theme().setThemeName(m_settings->name());
processPendingDeletions();
}
void KCMDesktopTheme::defaults()
{
ManagedConfigModule::defaults();
// can this be done more elegantly?
const auto pendingDeletions = m_model->match(m_model->index(0, 0), ThemesModel::PendingDeletionRole, true);
for (const QModelIndex &idx : pendingDeletions) {
m_model->setData(idx, false, ThemesModel::PendingDeletionRole);
}
}
bool KCMDesktopTheme::canEditThemes() const
{
return m_haveThemeExplorerInstalled;
}
void KCMDesktopTheme::editTheme(const QString &theme)
{
QProcess::startDetached(QStringLiteral("plasmathemeexplorer"), {QStringLiteral("-t"), theme});
}
bool KCMDesktopTheme::isSaveNeeded() const
{
return !m_model->match(m_model->index(0, 0), ThemesModel::PendingDeletionRole, true).isEmpty();
}
void KCMDesktopTheme::processPendingDeletions()
{
const QString program = QStringLiteral("plasmapkg2");
const auto pendingDeletions = m_model->match(m_model->index(0, 0), ThemesModel::PendingDeletionRole, true, -1 /*all*/);
QVector<QPersistentModelIndex> persistentPendingDeletions;
// turn into persistent model index so we can delete as we go
std::transform(pendingDeletions.begin(), pendingDeletions.end(),
std::back_inserter(persistentPendingDeletions), [](const QModelIndex &idx) {
return QPersistentModelIndex(idx);
});
for (const QPersistentModelIndex &idx : persistentPendingDeletions) {
const QString pluginName = idx.data(ThemesModel::PluginNameRole).toString();
const QString displayName = idx.data(Qt::DisplayRole).toString();
Q_ASSERT(pluginName != m_settings->name());
const QStringList arguments = {QStringLiteral("-t"), QStringLiteral("theme"), QStringLiteral("-r"), pluginName};
QProcess *process = new QProcess(this);
connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this,
[this, process, idx, pluginName, displayName](int exitCode, QProcess::ExitStatus exitStatus) {
Q_UNUSED(exitStatus)
if (exitCode == 0) {
m_model->removeRow(idx.row());
} else {
emit showErrorMessage(i18n("Removing theme failed: %1",
QString::fromLocal8Bit(process->readAllStandardOutput().trimmed())));
m_model->setData(idx, false, ThemesModel::PendingDeletionRole);
}
process->deleteLater();
});
process->start(program, arguments);
process->waitForFinished(); // needed so it deletes fine when "OK" is clicked and the dialog destroyed
}
}
#include "kcm.moc"
/*
Copyright (c) 2014 Marco Martin <mart@kde.org>
Copyright (c) 2014 Vishesh Handa <me@vhanda.in>
Copyright (c) 2016 David Rosca <nowrep@gmail.com>
Copyright (c) 2018 Kai Uwe Broulik <kde@privat.broulik.de>
Copyright (c) 2019 Kevin Ottens <kevin.ottens@enioka.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef _KCM_DESKTOPTHEME_H
#define _KCM_DESKTOPTHEME_H
#include <KQuickAddons/ManagedConfigModule>
class QTemporaryFile;
namespace Plasma {
class Theme;
}
namespace KIO
{
class FileCopyJob;
}
class QQuickItem;
class DesktopThemeSettings;
class FilterProxyModel;
class ThemesModel;
class KCMDesktopTheme : public KQuickAddons::ManagedConfigModule
{
Q_OBJECT
Q_PROPERTY(DesktopThemeSettings *desktopThemeSettings READ desktopThemeSettings CONSTANT)
Q_PROPERTY(FilterProxyModel *filteredModel READ filteredModel CONSTANT)
Q_PROPERTY(ThemesModel *desktopThemeModel READ desktopThemeModel CONSTANT)
Q_PROPERTY(bool downloadingFile READ downloadingFile NOTIFY downloadingFileChanged)
Q_PROPERTY(bool canEditThemes READ canEditThemes CONSTANT)
public: