diff options
Diffstat (limited to 'src/plugins/platformthemes/gtk3/qgtk3json.cpp')
-rw-r--r-- | src/plugins/platformthemes/gtk3/qgtk3json.cpp | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/src/plugins/platformthemes/gtk3/qgtk3json.cpp b/src/plugins/platformthemes/gtk3/qgtk3json.cpp new file mode 100644 index 0000000000..eb81e563be --- /dev/null +++ b/src/plugins/platformthemes/gtk3/qgtk3json.cpp @@ -0,0 +1,404 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qgtk3json_p.h" +#include <QtCore/QFile> +#include <QMetaEnum> + +QT_BEGIN_NAMESPACE + +QLatin1String QGtk3Json::fromPalette(QPlatformTheme::Palette palette) +{ + return QLatin1String(QMetaEnum::fromType<QPlatformTheme::Palette>().valueToKey(static_cast<int>(palette))); +} + +QLatin1String QGtk3Json::fromGtkState(GtkStateFlags state) +{ + return QGtk3Interface::fromGtkState(state); +} + +QLatin1String fromColor(const QColor &color) +{ + return QLatin1String(QByteArray(color.name(QColor::HexRgb).toLatin1())); +} + +QLatin1String QGtk3Json::fromColorRole(QPalette::ColorRole role) +{ + return QLatin1String(QMetaEnum::fromType<QPalette::ColorRole>().valueToKey(static_cast<int>(role))); +} + +QLatin1String QGtk3Json::fromColorGroup(QPalette::ColorGroup group) +{ + return QLatin1String(QMetaEnum::fromType<QPalette::ColorGroup>().valueToKey(static_cast<int>(group))); +} + +QLatin1String QGtk3Json::fromGdkSource(QGtk3Interface::QGtkColorSource source) +{ + return QLatin1String(QMetaEnum::fromType<QGtk3Interface::QGtkColorSource>().valueToKey(static_cast<int>(source))); +} + +QLatin1String QGtk3Json::fromWidgetType(QGtk3Interface::QGtkWidget widgetType) +{ + return QLatin1String(QMetaEnum::fromType<QGtk3Interface::QGtkWidget>().valueToKey(static_cast<int>(widgetType))); +} + +QLatin1String QGtk3Json::fromColorScheme(Qt::ColorScheme app) +{ + return QLatin1String(QMetaEnum::fromType<Qt::ColorScheme>().valueToKey(static_cast<int>(app))); +} + +#define CONVERT(type, key, def)\ + bool ok;\ + const int intVal = QMetaEnum::fromType<type>().keyToValue(key.toLatin1().constData(), &ok);\ + return ok ? static_cast<type>(intVal) : type::def + +Qt::ColorScheme QGtk3Json::toColorScheme(const QString &colorScheme) +{ + CONVERT(Qt::ColorScheme, colorScheme, Unknown); +} + +QPlatformTheme::Palette QGtk3Json::toPalette(const QString &palette) +{ + CONVERT(QPlatformTheme::Palette, palette, NPalettes); +} + +GtkStateFlags QGtk3Json::toGtkState(const QString &type) +{ + int i = QGtk3Interface::toGtkState(type); + if (i < 0) + return GTK_STATE_FLAG_NORMAL; + return static_cast<GtkStateFlags>(i); +} + +QColor toColor(const QStringView &color) +{ + return QColor::fromString(color); +} + +QPalette::ColorRole QGtk3Json::toColorRole(const QString &role) +{ + CONVERT(QPalette::ColorRole, role, NColorRoles); +} + +QPalette::ColorGroup QGtk3Json::toColorGroup(const QString &group) +{ + CONVERT(QPalette::ColorGroup, group, NColorGroups); +} + +QGtk3Interface::QGtkColorSource QGtk3Json::toGdkSource(const QString &source) +{ + CONVERT(QGtk3Interface::QGtkColorSource, source, Background); +} + +QLatin1String QGtk3Json::fromSourceType(QGtk3Storage::SourceType sourceType) +{ + return QLatin1String(QMetaEnum::fromType<QGtk3Storage::SourceType>().valueToKey(static_cast<int>(sourceType))); +} + +QGtk3Storage::SourceType QGtk3Json::toSourceType(const QString &sourceType) +{ + CONVERT(QGtk3Storage::SourceType, sourceType, Invalid); +} + +QGtk3Interface::QGtkWidget QGtk3Json::toWidgetType(const QString &widgetType) +{ + CONVERT(QGtk3Interface::QGtkWidget, widgetType, gtk_offscreen_window); +} + +#undef CONVERT + +bool QGtk3Json::save(const QGtk3Storage::PaletteMap &map, const QString &fileName, + QJsonDocument::JsonFormat format) +{ + QJsonDocument doc = save(map); + if (doc.isEmpty()) { + qWarning() << "Nothing to save to" << fileName; + return false; + } + + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + qWarning() << "Unable to open file" << fileName << "for writing."; + return false; + } + + if (!file.write(doc.toJson(format))) { + qWarning() << "Unable to serialize Json document."; + return false; + } + + file.close(); + qInfo() << "Saved mapping data to" << fileName; + return true; +} + +const QJsonDocument QGtk3Json::save(const QGtk3Storage::PaletteMap &map) +{ + QJsonObject paletteObject; + for (auto paletteIterator = map.constBegin(); paletteIterator != map.constEnd(); + ++paletteIterator) { + const QGtk3Storage::BrushMap &bm = paletteIterator.value(); + QFlatMap<QPalette::ColorRole, QGtk3Storage::BrushMap> brushMaps; + for (auto brushIterator = bm.constBegin(); brushIterator != bm.constEnd(); + ++brushIterator) { + const QPalette::ColorRole role = brushIterator.key().colorRole; + if (brushMaps.contains(role)) { + brushMaps.value(role).insert(brushIterator.key(), brushIterator.value()); + } else { + QGtk3Storage::BrushMap newMap; + newMap.insert(brushIterator.key(), brushIterator.value()); + brushMaps.insert(role, newMap); + } + } + + QJsonObject brushArrayObject; + for (auto brushMapIterator = brushMaps.constBegin(); + brushMapIterator != brushMaps.constEnd(); ++brushMapIterator) { + + QJsonArray brushArray; + int brushIndex = 0; + const QGtk3Storage::BrushMap &bm = brushMapIterator.value(); + for (auto brushIterator = bm.constBegin(); brushIterator != bm.constEnd(); + ++brushIterator) { + QJsonObject brushObject; + const QGtk3Storage::TargetBrush tb = brushIterator.key(); + QGtk3Storage::Source s = brushIterator.value(); + brushObject.insert(ceColorGroup, fromColorGroup(tb.colorGroup)); + brushObject.insert(ceColorScheme, fromColorScheme(tb.colorScheme)); + brushObject.insert(ceSourceType, fromSourceType(s.sourceType)); + + QJsonObject sourceObject; + switch (s.sourceType) { + case QGtk3Storage::SourceType::Gtk: { + sourceObject.insert(ceGtkWidget, fromWidgetType(s.gtk3.gtkWidgetType)); + sourceObject.insert(ceGdkSource, fromGdkSource(s.gtk3.source)); + sourceObject.insert(ceGtkState, fromGtkState(s.gtk3.state)); + sourceObject.insert(ceWidth, s.gtk3.width); + sourceObject.insert(ceHeight, s.gtk3.height); + } + break; + + case QGtk3Storage::SourceType::Fixed: { + QJsonObject fixedObject; + fixedObject.insert(ceColor, s.fix.fixedBrush.color().name()); + fixedObject.insert(ceWidth, s.fix.fixedBrush.texture().width()); + fixedObject.insert(ceHeight, s.fix.fixedBrush.texture().height()); + sourceObject.insert(ceBrush, fixedObject); + } + break; + + case QGtk3Storage::SourceType::Modified:{ + sourceObject.insert(ceColorGroup, fromColorGroup(s.rec.colorGroup)); + sourceObject.insert(ceColorRole, fromColorRole(s.rec.colorRole)); + sourceObject.insert(ceColorScheme, fromColorScheme(s.rec.colorScheme)); + sourceObject.insert(ceRed, s.rec.deltaRed); + sourceObject.insert(ceGreen, s.rec.deltaGreen); + sourceObject.insert(ceBlue, s.rec.deltaBlue); + sourceObject.insert(ceWidth, s.rec.width); + sourceObject.insert(ceHeight, s.rec.height); + sourceObject.insert(ceLighter, s.rec.lighter); + } + break; + + case QGtk3Storage::SourceType::Invalid: + break; + } + + brushObject.insert(ceData, sourceObject); + brushArray.insert(brushIndex, brushObject); + ++brushIndex; + } + brushArrayObject.insert(fromColorRole(brushMapIterator.key()), brushArray); + } + paletteObject.insert(fromPalette(paletteIterator.key()), brushArrayObject); + } + + QJsonObject top; + top.insert(cePalettes, paletteObject); + return paletteObject.keys().isEmpty() ? QJsonDocument() : QJsonDocument(top); +} + +bool QGtk3Json::load(QGtk3Storage::PaletteMap &map, const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + qCWarning(lcQGtk3Interface) << "Unable to open file:" << fileName; + return false; + } + + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err); + if (err.error != QJsonParseError::NoError) { + qWarning(lcQGtk3Interface) << "Unable to parse Json document from" << fileName + << err.error << err.errorString(); + return false; + } + + if (Q_LIKELY(load(map, doc))) { + qInfo() << "GTK mapping successfully imported from" << fileName; + return true; + } + + qWarning() << "File" << fileName << "could not be loaded."; + return false; +} + +bool QGtk3Json::load(QGtk3Storage::PaletteMap &map, const QJsonDocument &doc) +{ +#define GETSTR(obj, key)\ + if (!obj.contains(key)) {\ + qCInfo(lcQGtk3Interface) << key << "missing for palette" << paletteName\ + << ", Brush" << colorRoleName;\ + return false;\ + }\ + value = obj[key].toString() + +#define GETINT(obj, key, var) GETSTR(obj, key);\ + if (!obj[key].isDouble()) {\ + qCInfo(lcQGtk3Interface) << key << "type mismatch" << value\ + << "is not an integer!"\ + << "(Palette" << paletteName << "), Brush" << colorRoleName;\ + return false;\ + }\ + const int var = obj[key].toInt() + + map.clear(); + const QJsonObject top(doc.object()); + if (doc.isEmpty() || top.isEmpty() || !top.contains(cePalettes)) { + qCInfo(lcQGtk3Interface) << "Document does not contain Palettes."; + return false; + } + + const QStringList &paletteList = top[cePalettes].toObject().keys(); + for (const QString &paletteName : paletteList) { + bool ok; + const int intVal = QMetaEnum::fromType<QPlatformTheme::Palette>().keyToValue(paletteName + .toLatin1().constData(), &ok); + if (!ok) { + qCInfo(lcQGtk3Interface) << "Invalid Palette name:" << paletteName; + return false; + } + const QJsonObject &paletteObject = top[cePalettes][paletteName].toObject(); + const QStringList &brushList = paletteObject.keys(); + if (brushList.isEmpty()) { + qCInfo(lcQGtk3Interface) << "Palette" << paletteName << "does not contain brushes"; + return false; + } + + const QPlatformTheme::Palette paletteType = static_cast<QPlatformTheme::Palette>(intVal); + QGtk3Storage::BrushMap brushes; + const QStringList &colorRoles = paletteObject.keys(); + for (const QString &colorRoleName : colorRoles) { + const int intVal = QMetaEnum::fromType<QPalette::ColorRole>().keyToValue(colorRoleName + .toLatin1().constData(), &ok); + if (!ok) { + qCInfo(lcQGtk3Interface) << "Palette" << paletteName + << "contains invalid color role" << colorRoleName; + return false; + } + const QPalette::ColorRole colorRole = static_cast<QPalette::ColorRole>(intVal); + const QJsonArray &brushArray = paletteObject[colorRoleName].toArray(); + for (int brushIndex = 0; brushIndex < brushArray.size(); ++brushIndex) { + const QJsonObject brushObject = brushArray.at(brushIndex).toObject(); + if (brushObject.isEmpty()) { + qCInfo(lcQGtk3Interface) << "Brush specification missing at for palette" + << paletteName << ", Brush" << colorRoleName; + return false; + } + + QString value; + GETSTR(brushObject, ceSourceType); + const QGtk3Storage::SourceType sourceType = toSourceType(value); + GETSTR(brushObject, ceColorGroup); + const QPalette::ColorGroup colorGroup = toColorGroup(value); + GETSTR(brushObject, ceColorScheme); + const Qt::ColorScheme colorScheme = toColorScheme(value); + QGtk3Storage::TargetBrush tb(colorGroup, colorRole, colorScheme); + QGtk3Storage::Source s; + + if (!brushObject.contains(ceData) || !brushObject[ceData].isObject()) { + qCInfo(lcQGtk3Interface) << "Source specification missing for palette" << paletteName + << "Brush" << colorRoleName; + return false; + } + const QJsonObject &sourceObject = brushObject[ceData].toObject(); + + switch (sourceType) { + case QGtk3Storage::SourceType::Gtk: { + GETSTR(sourceObject, ceGdkSource); + const QGtk3Interface::QGtkColorSource gtkSource = toGdkSource(value); + GETSTR(sourceObject, ceGtkState); + const GtkStateFlags gtkState = toGtkState(value); + GETSTR(sourceObject, ceGtkWidget); + const QGtk3Interface::QGtkWidget widgetType = toWidgetType(value); + GETINT(sourceObject, ceHeight, height); + GETINT(sourceObject, ceWidth, width); + s = QGtk3Storage::Source(widgetType, gtkSource, gtkState, width, height); + } + break; + + case QGtk3Storage::SourceType::Fixed: { + if (!sourceObject.contains(ceBrush)) { + qCInfo(lcQGtk3Interface) << "Fixed brush specification missing for palette" << paletteName + << "Brush" << colorRoleName; + return false; + } + const QJsonObject &fixedSource = sourceObject[ceBrush].toObject(); + GETINT(fixedSource, ceWidth, width); + GETINT(fixedSource, ceHeight, height); + GETSTR(fixedSource, ceColor); + const QColor color(value); + if (!color.isValid()) { + qCInfo(lcQGtk3Interface) << "Color" << value << "can't be parsed for:" << paletteName + << "Brush" << colorRoleName; + return false; + } + const QBrush fixedBrush = (width < 0 && height < 0) + ? QBrush(color, QPixmap(width, height)) + : QBrush(color); + s = QGtk3Storage::Source(fixedBrush); + } + break; + + case QGtk3Storage::SourceType::Modified: { + GETSTR(sourceObject, ceColorGroup); + const QPalette::ColorGroup colorGroup = toColorGroup(value); + GETSTR(sourceObject, ceColorRole); + const QPalette::ColorRole colorRole = toColorRole(value); + GETSTR(sourceObject, ceColorScheme); + const Qt::ColorScheme colorScheme = toColorScheme(value); + GETINT(sourceObject, ceLighter, lighter); + GETINT(sourceObject, ceRed, red); + GETINT(sourceObject, ceBlue, blue); + GETINT(sourceObject, ceGreen, green); + s = QGtk3Storage::Source(colorGroup, colorRole, colorScheme, + lighter, red, green, blue); + } + break; + + case QGtk3Storage::SourceType::Invalid: + qInfo(lcQGtk3Interface) << "Invalid source type for palette" << paletteName + << "Brush." << colorRoleName; + return false; + } + brushes.insert(tb, s); + } + } + map.insert(paletteType, brushes); + } + return true; +} + +QT_END_NAMESPACE + |