// 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 #include QT_BEGIN_NAMESPACE QLatin1String QGtk3Json::fromPalette(QPlatformTheme::Palette palette) { return QLatin1String(QMetaEnum::fromType().valueToKey(static_cast(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().valueToKey(static_cast(role))); } QLatin1String QGtk3Json::fromColorGroup(QPalette::ColorGroup group) { return QLatin1String(QMetaEnum::fromType().valueToKey(static_cast(group))); } QLatin1String QGtk3Json::fromGdkSource(QGtk3Interface::QGtkColorSource source) { return QLatin1String(QMetaEnum::fromType().valueToKey(static_cast(source))); } QLatin1String QGtk3Json::fromWidgetType(QGtk3Interface::QGtkWidget widgetType) { return QLatin1String(QMetaEnum::fromType().valueToKey(static_cast(widgetType))); } QLatin1String QGtk3Json::fromColorScheme(Qt::ColorScheme app) { return QLatin1String(QMetaEnum::fromType().valueToKey(static_cast(app))); } #define CONVERT(type, key, def)\ bool ok;\ const int intVal = QMetaEnum::fromType().keyToValue(key.toLatin1().constData(), &ok);\ return ok ? static_cast(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(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().valueToKey(static_cast(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 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().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(intVal); QGtk3Storage::BrushMap brushes; const QStringList &colorRoles = paletteObject.keys(); for (const QString &colorRoleName : colorRoles) { const int intVal = QMetaEnum::fromType().keyToValue(colorRoleName .toLatin1().constData(), &ok); if (!ok) { qCInfo(lcQGtk3Interface) << "Palette" << paletteName << "contains invalid color role" << colorRoleName; return false; } const QPalette::ColorRole colorRole = static_cast(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