[plasma/plasma-sdk] themeexplorer/src: Fix plasmathemeexplorer
Tobias Fella <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit ffe34c617390006a38c10ed2e4b27a71b6eb86e8 by Tobias Fella.
Committed on 05/08/2026 at 14:05.
Pushed by tfella into branch 'master'.
Fix plasmathemeexplorer
M +3 -3 themeexplorer/src/qml/Main.qml
M +12 -10 themeexplorer/src/themelistmodel.cpp
M +95 -58 themeexplorer/src/thememodel.cpp
M +4 -1 themeexplorer/src/thememodel.h
https://invent.kde.org/plasma/plasma-sdk/-/commit/ffe34c617390006a38c10ed2e4b27a71b6eb86e8
diff --git a/themeexplorer/src/qml/Main.qml b/themeexplorer/src/qml/Main.qml
index 8daef8f7..70e5b8a2 100644
--- a/themeexplorer/src/qml/Main.qml
+++ b/themeexplorer/src/qml/Main.qml
@@ -66,7 +66,7 @@ Kirigami.AbstractApplicationWindow {
ToolButton {
ToolTip.text: i18n("Edit Metadata…")
icon.name: "configure"
- enabled: view.currentItem?.modelData.isWritable ?? false
+ enabled: themeModel.isWritable
onClicked: {
if (!root.metadataEditor) {
root.metadataEditor = metadataEditorComponent.createObject(root);
@@ -83,7 +83,7 @@ Kirigami.AbstractApplicationWindow {
ToolButton {
ToolTip.text: i18n("Edit Colors…")
icon.name: "color"
- enabled: view.currentItem?.modelData.isWritable ?? false
+ enabled: themeModel.isWritable
onClicked: {
if (!root.colorEditor) {
root.colorEditor = colorEditorComponent.createObject(root);
@@ -260,7 +260,7 @@ Kirigami.AbstractApplicationWindow {
}
Button {
text: view.currentItem && view.currentItem.modelData.usesFallback ? i18n("Create with Editor…") : i18n("Open In Editor…")
- enabled: view.currentItem?.modelData.isWritable ?? false
+ enabled: themeModel.isWritable
Layout.alignment: Qt.AlignHCenter
onClicked: {
print(view.currentItem.modelData.svgAbsolutePath)
diff --git a/themeexplorer/src/themelistmodel.cpp b/themeexplorer/src/themelistmodel.cpp
index 1b1cd5c6..61838350 100644
--- a/themeexplorer/src/themelistmodel.cpp
+++ b/themeexplorer/src/themelistmodel.cpp
@@ -17,10 +17,12 @@
#include <QApplication>
#include <QDir>
#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
#include <QPainter>
#include <QStandardPaths>
-#include <KConfigGroup>
#include <KDesktopFile>
#include <Plasma/Theme>
@@ -68,19 +70,19 @@ void ThemeListModel::reload()
const auto themeNameSepIndex = themeRoot.lastIndexOf('/', -1);
const auto packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1);
- KDesktopFile desktopFile(theme);
+ QFile file(theme);
+ (void)file.open(QFile::ReadOnly);
+ const auto json = QJsonDocument::fromJson(file.readAll()).object();
- if (desktopFile.noDisplay()) {
- continue;
- }
-
- QString name = desktopFile.readName();
+ auto name = json["KPlugin"]["Name"].toString();
if (name.isEmpty()) {
name = packageName;
}
- const QString comment = desktopFile.readComment();
- const QString author = desktopFile.desktopGroup().readEntry("X-KDE-PluginInfo-Author", QString());
- const QString version = desktopFile.desktopGroup().readEntry("X-KDE-PluginInfo-Version", QString());
+ const auto comment = json["KPlugin"]["Description"].toString();
+
+ auto authors = json["KPlugin"]["Author"].toArray();
+ const auto author = authors.size() > 0 ? authors[0].toObject()["Name"].toString() : QString();
+ const auto version = json["KPlugin"]["Version"].toString();
ThemeInfo info;
info.package = packageName;
diff --git a/themeexplorer/src/thememodel.cpp b/themeexplorer/src/thememodel.cpp
index 92ea0a72..74bdadac 100644
--- a/themeexplorer/src/thememodel.cpp
+++ b/themeexplorer/src/thememodel.cpp
@@ -18,14 +18,14 @@
#include <KAboutData>
#include <KCompressionDevice>
-#include <KConfigGroup>
#include <KIO/FileCopyJob>
#include <KIO/MkdirJob>
#include <KProcess>
#include <Plasma/Theme>
+#include <kio/mkdirjob.h>
-using namespace Qt::Literals::StringLiterals;
+using namespace Qt::StringLiterals;
ThemeModel::ThemeModel(QObject *parent)
: QAbstractListModel(parent)
@@ -43,13 +43,19 @@ ThemeModel::ThemeModel(QObject *parent)
m_roleNames.insert(Delegate, "delegate");
m_roleNames.insert(UsesFallback, "usesFallback");
m_roleNames.insert(SvgAbsolutePath, "svgAbsolutePath");
- m_roleNames.insert(IsWritable, "isWritable");
m_roleNames.insert(IconElements, "iconElements");
m_roleNames.insert(FrameSvgPrefixes, "frameSvgPrefixes");
load();
}
+QString compactName(const QString &name)
+{
+ auto compactName = name.toLower();
+ compactName.replace(' ', QString());
+ return compactName;
+}
+
ThemeModel::~ThemeModel()
{
}
@@ -99,8 +105,6 @@ QVariant ThemeModel::data(const QModelIndex &index, int role) const
}
return path;
}
- case IsWritable:
- return QFile::exists(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/plasma/desktoptheme/" + m_themeName);
case IconElements:
case FrameSvgPrefixes: {
QString path = m_imageSet.imagePath(value.value("imagePath").toString());
@@ -156,6 +160,7 @@ void ThemeModel::load()
}
endResetModel();
+ Q_EMIT isWritableChanged();
}
QString ThemeModel::theme() const
@@ -166,13 +171,13 @@ QString ThemeModel::theme() const
QString ThemeModel::author() const
{
const QList<KAboutPerson> authors = m_theme->metadata().authors();
- return authors.isEmpty() ? authors.at(0).name() : QString();
+ return authors.isEmpty() ? QString() : authors.at(0).name();
}
QString ThemeModel::email() const
{
const QList<KAboutPerson> authors = m_theme->metadata().authors();
- return authors.isEmpty() ? authors.at(0).emailAddress() : QString();
+ return authors.isEmpty() ? QString() : authors.at(0).emailAddress();
}
QString ThemeModel::license() const
@@ -211,7 +216,8 @@ void ThemeModel::editElement(const QString &imagePath)
if (m_imageSet.currentImageSetHasImage(imagePath)) {
finalFile = file;
} else {
- finalFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/plasma/desktoptheme/" + m_themeName + "/" + imagePath + ".svgz";
+ finalFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/plasma/desktoptheme/" + compactName(m_themeName) + "/" + imagePath
+ + ".svgz";
const QString dirPath = QFileInfo(finalFile).absoluteDir().absolutePath();
KIO::mkdir(QUrl::fromLocalFile(dirPath))->exec();
@@ -222,20 +228,19 @@ void ThemeModel::editElement(const QString &imagePath)
}
auto process = new QProcess(this);
- process->execute("bash",
- {u"-c"_s,
- u""
- "cd %2;"
- "inkscape \"%1.svgz\";"
- "mv \"%1.svgz\" \"%1.svg.gz\";"
- "gunzip \"%1.svg.gz\";"
- "/usr/bin/perl -p -i -e \"s/color:#[^;]*;fill:currentColor/fill:currentColor/g\" \"%1.svg\";"
- "gzip \"%1.svg\";"
- "mv \"%1.svg.gz\" \"%1.svgz\""
- ""_s.arg(finalFile.mid(finalFile.lastIndexOf("/") + 1).split(".")[0], finalFile.left(finalFile.lastIndexOf("/")))});
+ process->start("bash",
+ {u"-c"_s,
+ u""
+ "cd %2;"
+ "inkscape \"%1.svgz\";"
+ "mv \"%1.svgz\" \"%1.svg.gz\";"
+ "gunzip \"%1.svg.gz\";"
+ "/usr/bin/perl -p -i -e \"s/color:#[^;]*;fill:currentColor/fill:currentColor/g\" \"%1.svg\";"
+ "gzip \"%1.svg\";"
+ "mv \"%1.svg.gz\" \"%1.svgz\""
+ ""_s.arg(finalFile.mid(finalFile.lastIndexOf("/") + 1).split(".")[0], finalFile.left(finalFile.lastIndexOf("/")))});
connect(process, &QProcess::finished, this, &ThemeModel::processFinished);
- process->start();
}
void ThemeModel::processFinished()
@@ -243,11 +248,14 @@ void ThemeModel::processFinished()
/*We increment the microversion of the theme: keeps track and will force the cache to be
discarded in order to reload immediately the graphics*/
const QString metadataPath(
- QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("plasma/desktoptheme/") % m_themeName % QLatin1String("/metadata.desktop")));
- KConfig c(metadataPath);
- KConfigGroup cg(&c, "Desktop Entry");
+ QStandardPaths::locate(QStandardPaths::GenericDataLocation, "plasma/desktoptheme/"_L1 % compactName(m_themeName) % "/metadata.json"_L1));
+
+ QFile file(metadataPath);
+ (void)file.open(QFile::ReadWrite);
+ auto json = QJsonDocument::fromJson(file.readAll()).object();
+
+ auto version = json["KPlugin"_L1]["Version"_L1].toString().split('.');
- QStringList version = cg.readEntry("X-KDE-PluginInfo-Version", "0.0").split('.');
if (version.length() < 2) {
version << QLatin1String("0");
}
@@ -255,52 +263,76 @@ void ThemeModel::processFinished()
version << QLatin1String("0");
}
- cg.writeEntry("X-KDE-PluginInfo-Version",
- QString(version.first() + QLatin1String(".") + version[1] + QLatin1String(".") + QString::number(version.last().toInt() + 1)));
- cg.sync();
+ QString newVersion = version.first() + u"."_s + version[1] + u"."_s + QString::number(version.last().toInt() + 1);
+ auto kPlugin = json["KPlugin"].toObject();
+ kPlugin["Version"] = newVersion;
+ json["KPlugin"] = kPlugin;
+ file.seek(0);
+ file.resize(0);
+ file.write(QJsonDocument(json).toJson());
+ file.close();
}
void ThemeModel::editThemeMetaData(const QString &name, const QString &author, const QString &email, const QString &license, const QString &website)
{
- QString compactName = name.toLower();
- compactName.replace(' ', QString());
- const QString metadataPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QLatin1String("/plasma/desktoptheme/") % compactName
- % QLatin1String("/metadata.desktop"));
- KConfig c(metadataPath);
-
- KConfigGroup cg(&c, "Desktop Entry");
- cg.writeEntry("X-KDE-PluginInfo-Name", name);
- cg.writeEntry("X-KDE-PluginInfo-Author", author);
- cg.writeEntry("X-KDE-PluginInfo-Email", email);
- cg.writeEntry("X-KDE-PluginInfo-Website", website);
- cg.writeEntry("X-KDE-PluginInfo-Category", "Plasma Theme");
- cg.writeEntry("X-KDE-PluginInfo-License", license);
- cg.writeEntry("X-KDE-PluginInfo-EnabledByDefault", "true");
- cg.writeEntry("X-Plasma-API", "5.0");
- cg.writeEntry("X-KDE-PluginInfo-Version", "0.1");
- cg.sync();
-
- KConfigGroup cg2(&c, "ContrastEffect");
- cg2.writeEntry("enabled", "true");
- cg2.writeEntry("contrast", "0.2");
- cg2.writeEntry("intensity", "2.0");
- cg2.writeEntry("saturation", "1.7");
- cg2.sync();
+ const auto metadataPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % "/plasma/desktoptheme/"_L1 % compactName(name)
+ % "/metadata.json"_L1);
+
+ QFile file(metadataPath);
+ (void)file.open(QFile::ReadWrite);
+
+ auto json = QJsonDocument::fromJson(file.readAll()).object();
+
+ json[u"X-Plasma-API"_s] = u"5.0"_s;
+
+ auto kPlugin = json[u"KPlugin"_s].toObject();
+ auto authors = kPlugin[u"Authors"_s].toArray();
+ authors = QJsonArray{QJsonObject{
+ {u"Email"_s, email},
+ {u"Name"_s, author},
+ }};
+ kPlugin["Authors"] = authors;
+ kPlugin["Name"] = name;
+ kPlugin["Category"] = u"Plasma Theme"_s;
+
+ if (!kPlugin.contains("Description")) {
+ kPlugin["Description"] = QString();
+ }
+
+ kPlugin["EnabledByDefault"] = true;
+ if (!kPlugin.contains("Id")) {
+ kPlugin[u"Id"_s] = compactName(name);
+ }
+
+ kPlugin["Website"] = website;
+ kPlugin["License"] = license;
+
+ if (!kPlugin.contains("Version")) {
+ kPlugin["Version"] = "1.0";
+ }
+
+ json["KPlugin"] = kPlugin;
+
+ file.seek(0);
+ file.resize(0);
+ file.write(QJsonDocument(json).toJson());
+ file.close();
}
void ThemeModel::createNewTheme(const QString &name, const QString &author, const QString &email, const QString &license, const QString &website)
{
+ auto dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + u"/plasma/desktoptheme/"_s + compactName(name);
+ QDir().mkdir(dir);
editThemeMetaData(name, author, email, license, website);
- QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, +"/plasma/desktoptheme/default/colors");
+ const auto colorsFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "/plasma/desktoptheme/breeze-light/colors");
- QString compactName = name.toLower();
- compactName.replace(' ', QString());
- QString finalFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/plasma/desktoptheme/" + compactName + "/colors";
+ const auto finalColorsFile =
+ QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/plasma/desktoptheme/" + compactName(name) + "/colors";
- KIO::FileCopyJob *job = KIO::file_copy(QUrl::fromLocalFile(file), QUrl::fromLocalFile(finalFile));
+ KIO::FileCopyJob *job = KIO::file_copy(QUrl::fromLocalFile(colorsFile), QUrl::fromLocalFile(finalColorsFile));
if (!job->exec()) {
- qWarning() << "Error copying" << file << "to" << finalFile;
+ qWarning() << "Error copying" << colorsFile << "to" << finalColorsFile;
}
m_themeListModel->reload();
@@ -308,7 +340,12 @@ void ThemeModel::createNewTheme(const QString &name, const QString &author, cons
QString ThemeModel::themeFolder()
{
- return QStandardPaths::locate(QStandardPaths::GenericDataLocation, +"plasma/desktoptheme/" + m_themeName, QStandardPaths::LocateDirectory);
+ return QStandardPaths::locate(QStandardPaths::GenericDataLocation, +"plasma/desktoptheme/" + compactName(m_themeName), QStandardPaths::LocateDirectory);
+}
+
+bool ThemeModel::isWritable() const
+{
+ return QFile::exists(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/plasma/desktoptheme/" + compactName(m_themeName));
}
#include "moc_thememodel.cpp"
diff --git a/themeexplorer/src/thememodel.h b/themeexplorer/src/thememodel.h
index e92a5367..3697468d 100644
--- a/themeexplorer/src/thememodel.h
+++ b/themeexplorer/src/thememodel.h
@@ -34,6 +34,7 @@ class ThemeModel : public QAbstractListModel
Q_PROPERTY(QString email READ email NOTIFY themeChanged)
Q_PROPERTY(QString license READ license NOTIFY themeChanged)
Q_PROPERTY(QString website READ website NOTIFY themeChanged)
+ Q_PROPERTY(bool isWritable READ isWritable NOTIFY isWritableChanged)
Q_PROPERTY(QString themeFolder READ themeFolder NOTIFY themeChanged)
public:
@@ -43,7 +44,6 @@ public:
Delegate,
UsesFallback,
SvgAbsolutePath,
- IsWritable,
IconElements,
FrameSvgPrefixes,
};
@@ -66,6 +66,8 @@ public:
QString license() const;
QString website() const;
+ bool isWritable() const;
+
void load();
Q_INVOKABLE void editElement(const QString &imagePath);
@@ -76,6 +78,7 @@ public:
Q_SIGNALS:
void themeChanged();
+ void isWritableChanged();
private Q_SLOTS:
void processFinished();