1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4//
5// W A R N I N G
6// -------------
7//
8// This file is not part of the Qt API. It exists purely as an
9// implementation detail. This header file may change from version to
10// version without notice, or even be removed.
11//
12// We mean it.
13//
14
15#include "qgtk3json_p.h"
16#include <QtCore/QFile>
17#include <QMetaEnum>
18
19QT_BEGIN_NAMESPACE
20
21QLatin1String QGtk3Json::fromPalette(QPlatformTheme::Palette palette)
22{
23 return QLatin1String(QMetaEnum::fromType<QPlatformTheme::Palette>().valueToKey(value: static_cast<int>(palette)));
24}
25
26QLatin1String QGtk3Json::fromGtkState(GtkStateFlags state)
27{
28 return QGtk3Interface::fromGtkState(state);
29}
30
31QLatin1String fromColor(const QColor &color)
32{
33 return QLatin1String(QByteArray(color.name(format: QColor::HexRgb).toLatin1()));
34}
35
36QLatin1String QGtk3Json::fromColorRole(QPalette::ColorRole role)
37{
38 return QLatin1String(QMetaEnum::fromType<QPalette::ColorRole>().valueToKey(value: static_cast<int>(role)));
39}
40
41QLatin1String QGtk3Json::fromColorGroup(QPalette::ColorGroup group)
42{
43 return QLatin1String(QMetaEnum::fromType<QPalette::ColorGroup>().valueToKey(value: static_cast<int>(group)));
44}
45
46QLatin1String QGtk3Json::fromGdkSource(QGtk3Interface::QGtkColorSource source)
47{
48 return QLatin1String(QMetaEnum::fromType<QGtk3Interface::QGtkColorSource>().valueToKey(value: static_cast<int>(source)));
49}
50
51QLatin1String QGtk3Json::fromWidgetType(QGtk3Interface::QGtkWidget widgetType)
52{
53 return QLatin1String(QMetaEnum::fromType<QGtk3Interface::QGtkWidget>().valueToKey(value: static_cast<int>(widgetType)));
54}
55
56QLatin1String QGtk3Json::fromColorScheme(Qt::ColorScheme app)
57{
58 return QLatin1String(QMetaEnum::fromType<Qt::ColorScheme>().valueToKey(value: static_cast<int>(app)));
59}
60
61#define CONVERT(type, key, def)\
62 bool ok;\
63 const int intVal = QMetaEnum::fromType<type>().keyToValue(key.toLatin1().constData(), &ok);\
64 return ok ? static_cast<type>(intVal) : type::def
65
66Qt::ColorScheme QGtk3Json::toColorScheme(const QString &colorScheme)
67{
68 CONVERT(Qt::ColorScheme, colorScheme, Unknown);
69}
70
71QPlatformTheme::Palette QGtk3Json::toPalette(const QString &palette)
72{
73 CONVERT(QPlatformTheme::Palette, palette, NPalettes);
74}
75
76GtkStateFlags QGtk3Json::toGtkState(const QString &type)
77{
78 int i = QGtk3Interface::toGtkState(state: type);
79 if (i < 0)
80 return GTK_STATE_FLAG_NORMAL;
81 return static_cast<GtkStateFlags>(i);
82}
83
84QColor toColor(const QStringView &color)
85{
86 return QColor::fromString(name: color);
87}
88
89QPalette::ColorRole QGtk3Json::toColorRole(const QString &role)
90{
91 CONVERT(QPalette::ColorRole, role, NColorRoles);
92}
93
94QPalette::ColorGroup QGtk3Json::toColorGroup(const QString &group)
95{
96 CONVERT(QPalette::ColorGroup, group, NColorGroups);
97}
98
99QGtk3Interface::QGtkColorSource QGtk3Json::toGdkSource(const QString &source)
100{
101 CONVERT(QGtk3Interface::QGtkColorSource, source, Background);
102}
103
104QLatin1String QGtk3Json::fromSourceType(QGtk3Storage::SourceType sourceType)
105{
106 return QLatin1String(QMetaEnum::fromType<QGtk3Storage::SourceType>().valueToKey(value: static_cast<int>(sourceType)));
107}
108
109QGtk3Storage::SourceType QGtk3Json::toSourceType(const QString &sourceType)
110{
111 CONVERT(QGtk3Storage::SourceType, sourceType, Invalid);
112}
113
114QGtk3Interface::QGtkWidget QGtk3Json::toWidgetType(const QString &widgetType)
115{
116 CONVERT(QGtk3Interface::QGtkWidget, widgetType, gtk_offscreen_window);
117}
118
119#undef CONVERT
120
121bool QGtk3Json::save(const QGtk3Storage::PaletteMap &map, const QString &fileName,
122 QJsonDocument::JsonFormat format)
123{
124 QJsonDocument doc = save(map);
125 if (doc.isEmpty()) {
126 qWarning() << "Nothing to save to" << fileName;
127 return false;
128 }
129
130 QFile file(fileName);
131 if (!file.open(flags: QIODevice::WriteOnly)) {
132 qWarning() << "Unable to open file" << fileName << "for writing.";
133 return false;
134 }
135
136 if (!file.write(data: doc.toJson(format))) {
137 qWarning() << "Unable to serialize Json document.";
138 return false;
139 }
140
141 file.close();
142 qInfo() << "Saved mapping data to" << fileName;
143 return true;
144}
145
146const QJsonDocument QGtk3Json::save(const QGtk3Storage::PaletteMap &map)
147{
148 QJsonObject paletteObject;
149 for (auto paletteIterator = map.constBegin(); paletteIterator != map.constEnd();
150 ++paletteIterator) {
151 const QGtk3Storage::BrushMap &bm = paletteIterator.value();
152 QFlatMap<QPalette::ColorRole, QGtk3Storage::BrushMap> brushMaps;
153 for (auto brushIterator = bm.constBegin(); brushIterator != bm.constEnd();
154 ++brushIterator) {
155 const QPalette::ColorRole role = brushIterator.key().colorRole;
156 if (brushMaps.contains(key: role)) {
157 brushMaps[role].insert(key: brushIterator.key(), value: brushIterator.value());
158 } else {
159 QGtk3Storage::BrushMap newMap;
160 newMap.insert(key: brushIterator.key(), value: brushIterator.value());
161 brushMaps.insert(key: role, value: newMap);
162 }
163 }
164
165 QJsonObject brushArrayObject;
166 for (auto brushMapIterator = brushMaps.constBegin();
167 brushMapIterator != brushMaps.constEnd(); ++brushMapIterator) {
168
169 QJsonArray brushArray;
170 int brushIndex = 0;
171 const QGtk3Storage::BrushMap &bm = brushMapIterator.value();
172 for (auto brushIterator = bm.constBegin(); brushIterator != bm.constEnd();
173 ++brushIterator) {
174 QJsonObject brushObject;
175 const QGtk3Storage::TargetBrush tb = brushIterator.key();
176 QGtk3Storage::Source s = brushIterator.value();
177 brushObject.insert(key: ceColorGroup, value: fromColorGroup(group: tb.colorGroup));
178 brushObject.insert(key: ceColorScheme, value: fromColorScheme(app: tb.colorScheme));
179 brushObject.insert(key: ceSourceType, value: fromSourceType(sourceType: s.sourceType));
180
181 QJsonObject sourceObject;
182 switch (s.sourceType) {
183 case QGtk3Storage::SourceType::Gtk: {
184 sourceObject.insert(key: ceGtkWidget, value: fromWidgetType(widgetType: s.gtk3.gtkWidgetType));
185 sourceObject.insert(key: ceGdkSource, value: fromGdkSource(source: s.gtk3.source));
186 sourceObject.insert(key: ceGtkState, value: fromGtkState(state: s.gtk3.state));
187 sourceObject.insert(key: ceWidth, value: s.gtk3.width);
188 sourceObject.insert(key: ceHeight, value: s.gtk3.height);
189 }
190 break;
191
192 case QGtk3Storage::SourceType::Fixed: {
193 QJsonObject fixedObject;
194 fixedObject.insert(key: ceColor, value: s.fix.fixedBrush.color().name());
195 fixedObject.insert(key: ceWidth, value: s.fix.fixedBrush.texture().width());
196 fixedObject.insert(key: ceHeight, value: s.fix.fixedBrush.texture().height());
197 sourceObject.insert(key: ceBrush, value: fixedObject);
198 }
199 break;
200
201 case QGtk3Storage::SourceType::Modified:{
202 sourceObject.insert(key: ceColorGroup, value: fromColorGroup(group: s.rec.colorGroup));
203 sourceObject.insert(key: ceColorRole, value: fromColorRole(role: s.rec.colorRole));
204 sourceObject.insert(key: ceColorScheme, value: fromColorScheme(app: s.rec.colorScheme));
205 sourceObject.insert(key: ceRed, value: s.rec.deltaRed);
206 sourceObject.insert(key: ceGreen, value: s.rec.deltaGreen);
207 sourceObject.insert(key: ceBlue, value: s.rec.deltaBlue);
208 sourceObject.insert(key: ceWidth, value: s.rec.width);
209 sourceObject.insert(key: ceHeight, value: s.rec.height);
210 sourceObject.insert(key: ceLighter, value: s.rec.lighter);
211 }
212 break;
213
214 case QGtk3Storage::SourceType::Mixed: {
215 sourceObject.insert(key: ceColorGroup, value: fromColorGroup(group: s.mix.sourceGroup));
216 QJsonArray colorRoles;
217 colorRoles << fromColorRole(role: s.mix.colorRole1)
218 << fromColorRole(role: s.mix.colorRole2);
219 sourceObject.insert(key: ceColorRole, value: colorRoles);
220 }
221 break;
222
223 case QGtk3Storage::SourceType::Invalid:
224 break;
225 }
226
227 brushObject.insert(key: ceData, value: sourceObject);
228 brushArray.insert(i: brushIndex, value: brushObject);
229 ++brushIndex;
230 }
231 brushArrayObject.insert(key: fromColorRole(role: brushMapIterator.key()), value: brushArray);
232 }
233 paletteObject.insert(key: fromPalette(palette: paletteIterator.key()), value: brushArrayObject);
234 }
235
236 QJsonObject top;
237 top.insert(key: cePalettes, value: paletteObject);
238 return paletteObject.keys().isEmpty() ? QJsonDocument() : QJsonDocument(top);
239}
240
241bool QGtk3Json::load(QGtk3Storage::PaletteMap &map, const QString &fileName)
242{
243 QFile file(fileName);
244 if (!file.open(flags: QIODevice::ReadOnly)) {
245 qCWarning(lcQGtk3Interface) << "Unable to open file:" << fileName;
246 return false;
247 }
248
249 QJsonParseError err;
250 QJsonDocument doc = QJsonDocument::fromJson(json: file.readAll(), error: &err);
251 if (err.error != QJsonParseError::NoError) {
252 qCWarning(lcQGtk3Interface) << "Unable to parse Json document from" << fileName
253 << err.error << err.errorString();
254 return false;
255 }
256
257 if (Q_LIKELY(load(map, doc))) {
258 qInfo() << "GTK mapping successfully imported from" << fileName;
259 return true;
260 }
261
262 qWarning() << "File" << fileName << "could not be loaded.";
263 return false;
264}
265
266bool QGtk3Json::load(QGtk3Storage::PaletteMap &map, const QJsonDocument &doc)
267{
268#define GETSTR(obj, key)\
269 if (!obj.contains(key)) {\
270 qCInfo(lcQGtk3Interface) << key << "missing for palette" << paletteName\
271 << ", Brush" << colorRoleName;\
272 return false;\
273 }\
274 value = obj[key].toString()
275
276#define GETINT(obj, key, var) GETSTR(obj, key);\
277 if (!obj[key].isDouble()) {\
278 qCInfo(lcQGtk3Interface) << key << "type mismatch" << value\
279 << "is not an integer!"\
280 << "(Palette" << paletteName << "), Brush" << colorRoleName;\
281 return false;\
282 }\
283 const int var = obj[key].toInt()
284
285 map.clear();
286 const QJsonObject top(doc.object());
287 if (doc.isEmpty() || top.isEmpty() || !top.contains(key: cePalettes)) {
288 qCInfo(lcQGtk3Interface) << "Document does not contain Palettes.";
289 return false;
290 }
291
292 const QStringList &paletteList = top[cePalettes].toObject().keys();
293 for (const QString &paletteName : paletteList) {
294 bool ok;
295 const int intVal = QMetaEnum::fromType<QPlatformTheme::Palette>().keyToValue(key: paletteName
296 .toLatin1().constData(), ok: &ok);
297 if (!ok) {
298 qCInfo(lcQGtk3Interface) << "Invalid Palette name:" << paletteName;
299 return false;
300 }
301 const QJsonObject &paletteObject = top[cePalettes][paletteName].toObject();
302 const QStringList &brushList = paletteObject.keys();
303 if (brushList.isEmpty()) {
304 qCInfo(lcQGtk3Interface) << "Palette" << paletteName << "does not contain brushes";
305 return false;
306 }
307
308 const QPlatformTheme::Palette paletteType = static_cast<QPlatformTheme::Palette>(intVal);
309 QGtk3Storage::BrushMap brushes;
310 const QStringList &colorRoles = paletteObject.keys();
311 for (const QString &colorRoleName : colorRoles) {
312 const int intVal = QMetaEnum::fromType<QPalette::ColorRole>().keyToValue(key: colorRoleName
313 .toLatin1().constData(), ok: &ok);
314 if (!ok) {
315 qCInfo(lcQGtk3Interface) << "Palette" << paletteName
316 << "contains invalid color role" << colorRoleName;
317 return false;
318 }
319 const QPalette::ColorRole colorRole = static_cast<QPalette::ColorRole>(intVal);
320 const QJsonArray &brushArray = paletteObject[colorRoleName].toArray();
321 for (int brushIndex = 0; brushIndex < brushArray.size(); ++brushIndex) {
322 const QJsonObject brushObject = brushArray.at(i: brushIndex).toObject();
323 if (brushObject.isEmpty()) {
324 qCInfo(lcQGtk3Interface) << "Brush specification missing at for palette"
325 << paletteName << ", Brush" << colorRoleName;
326 return false;
327 }
328
329 QString value;
330 GETSTR(brushObject, ceSourceType);
331 const QGtk3Storage::SourceType sourceType = toSourceType(sourceType: value);
332 GETSTR(brushObject, ceColorGroup);
333 const QPalette::ColorGroup colorGroup = toColorGroup(group: value);
334 GETSTR(brushObject, ceColorScheme);
335 const Qt::ColorScheme colorScheme = toColorScheme(colorScheme: value);
336 QGtk3Storage::TargetBrush tb(colorGroup, colorRole, colorScheme);
337 QGtk3Storage::Source s;
338
339 if (!brushObject.contains(key: ceData) || !brushObject[ceData].isObject()) {
340 qCInfo(lcQGtk3Interface) << "Source specification missing for palette" << paletteName
341 << "Brush" << colorRoleName;
342 return false;
343 }
344 const QJsonObject &sourceObject = brushObject[ceData].toObject();
345
346 switch (sourceType) {
347 case QGtk3Storage::SourceType::Gtk: {
348 GETSTR(sourceObject, ceGdkSource);
349 const QGtk3Interface::QGtkColorSource gtkSource = toGdkSource(source: value);
350 GETSTR(sourceObject, ceGtkState);
351 const GtkStateFlags gtkState = toGtkState(type: value);
352 GETSTR(sourceObject, ceGtkWidget);
353 const QGtk3Interface::QGtkWidget widgetType = toWidgetType(widgetType: value);
354 GETINT(sourceObject, ceHeight, height);
355 GETINT(sourceObject, ceWidth, width);
356 s = QGtk3Storage::Source(widgetType, gtkSource, gtkState, width, height);
357 }
358 break;
359
360 case QGtk3Storage::SourceType::Fixed: {
361 if (!sourceObject.contains(key: ceBrush)) {
362 qCInfo(lcQGtk3Interface) << "Fixed brush specification missing for palette" << paletteName
363 << "Brush" << colorRoleName;
364 return false;
365 }
366 const QJsonObject &fixedSource = sourceObject[ceBrush].toObject();
367 GETINT(fixedSource, ceWidth, width);
368 GETINT(fixedSource, ceHeight, height);
369 GETSTR(fixedSource, ceColor);
370 const QColor color(value);
371 if (!color.isValid()) {
372 qCInfo(lcQGtk3Interface) << "Color" << value << "can't be parsed for:" << paletteName
373 << "Brush" << colorRoleName;
374 return false;
375 }
376 const QBrush fixedBrush = (width < 0 && height < 0)
377 ? QBrush(color, QPixmap(width, height))
378 : QBrush(color);
379 s = QGtk3Storage::Source(fixedBrush);
380 }
381 break;
382
383 case QGtk3Storage::SourceType::Modified: {
384 GETSTR(sourceObject, ceColorGroup);
385 const QPalette::ColorGroup colorGroup = toColorGroup(group: value);
386 GETSTR(sourceObject, ceColorRole);
387 const QPalette::ColorRole colorRole = toColorRole(role: value);
388 GETSTR(sourceObject, ceColorScheme);
389 const Qt::ColorScheme colorScheme = toColorScheme(colorScheme: value);
390 GETINT(sourceObject, ceLighter, lighter);
391 GETINT(sourceObject, ceRed, red);
392 GETINT(sourceObject, ceBlue, blue);
393 GETINT(sourceObject, ceGreen, green);
394 s = QGtk3Storage::Source(colorGroup, colorRole, colorScheme,
395 lighter, red, green, blue);
396 }
397 break;
398
399 case QGtk3Storage::SourceType::Mixed: {
400 if (!sourceObject[ceColorRole].isArray()) {
401 qCInfo(lcQGtk3Interface) << "Mixed brush missing the array of color roles for palette:" << paletteName
402 << "Brush" << colorRoleName;
403 return false;
404 }
405 QJsonArray colorRoles = sourceObject[ceColorRole].toArray();
406 if (colorRoles.size() < 2) {
407 qCInfo(lcQGtk3Interface) << "Mixed brush missing enough color roles for palette" << paletteName
408 << "Brush" << colorRoleName;
409 return false;
410 }
411 const QPalette::ColorRole colorRole1 = toColorRole(role: colorRoles[0].toString());
412 const QPalette::ColorRole colorRole2 = toColorRole(role: colorRoles[1].toString());
413 GETSTR(sourceObject, ceColorGroup);
414 const QPalette::ColorGroup sourceGroup = toColorGroup(group: value);
415 s = QGtk3Storage::Source(sourceGroup, colorRole1, colorRole2);
416 }
417 break;
418
419 case QGtk3Storage::SourceType::Invalid:
420 qCInfo(lcQGtk3Interface) << "Invalid source type for palette" << paletteName
421 << "Brush." << colorRoleName;
422 return false;
423 }
424 brushes.insert(key: tb, value: s);
425 }
426 }
427 map.insert(key: paletteType, value: brushes);
428 }
429 return true;
430}
431
432QT_END_NAMESPACE
433
434

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/plugins/platformthemes/gtk3/qgtk3json.cpp