1 /*
2  * SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  *
6  */
7 #include "varianthelper.h"
8 #include <QDBusArgument>
9 
10 namespace fcitx {
11 namespace kcm {
12 
toMap(const QVariant & variant)13 QVariantMap toMap(const QVariant &variant) {
14     QVariantMap map;
15     if (variant.canConvert<QDBusArgument>()) {
16         auto argument = qvariant_cast<QDBusArgument>(variant);
17         argument >> map;
18     }
19     if (variant.canConvert<QVariantMap>()) {
20         map = variant.toMap();
21     }
22     return map;
23 }
24 
valueFromVariantMapByPath(const QVariantMap & map,const QStringList & path,int depth)25 QString valueFromVariantMapByPath(const QVariantMap &map,
26                                   const QStringList &path, int depth) {
27     auto iter = map.find(path[depth]);
28     if (iter == map.end()) {
29         return QString();
30     }
31     if (depth + 1 == path.size()) {
32         if (iter->canConvert<QString>()) {
33             return iter->toString();
34         }
35     } else {
36         QVariantMap map = toMap(*iter);
37 
38         if (!map.isEmpty()) {
39             return valueFromVariantMapByPath(map, path, depth + 1);
40         }
41     }
42     return QString();
43 }
44 
valueFromVariantHelper(const QVariant & value,const QStringList & pathList,int depth)45 QVariant valueFromVariantHelper(const QVariant &value,
46                                 const QStringList &pathList, int depth) {
47     if (depth == pathList.size()) {
48         return value;
49     }
50     auto map = toMap(value);
51     // Make it finishes faster.
52     if (map.isEmpty() || !map.contains(pathList[depth])) {
53         return {};
54     }
55     return valueFromVariantHelper(map[pathList[depth]], pathList, depth + 1);
56 }
57 
readVariant(const QVariant & value,const QString & path)58 QVariant readVariant(const QVariant &value, const QString &path) {
59     auto pathList = path.split("/");
60     return valueFromVariantHelper(toMap(value), pathList, 0);
61 }
62 
readString(const QVariantMap & map,const QString & path)63 QString readString(const QVariantMap &map, const QString &path) {
64     auto pathList = path.split("/");
65     if (pathList.empty()) {
66         return QString();
67     }
68     return valueFromVariantMapByPath(map, pathList, 0);
69 }
70 
readBool(const QVariantMap & map,const QString & path)71 bool readBool(const QVariantMap &map, const QString &path) {
72     return readString(map, path) == "True";
73 }
74 
writeVariantHelper(QVariantMap & map,const QStringList & path,const QVariant & value,int depth)75 void writeVariantHelper(QVariantMap &map, const QStringList &path,
76                         const QVariant &value, int depth) {
77     if (depth + 1 == path.size()) {
78         map[path[depth]] = value;
79     } else {
80         auto iter = map.find(path[depth]);
81         if (iter == map.end()) {
82             iter = map.insert(path[depth], QVariantMap());
83         }
84 
85         if (iter->type() != QVariant::Map) {
86             auto oldValue = *iter;
87             *iter = QVariantMap({{"", oldValue}});
88         }
89 
90         auto &nextMap = *static_cast<QVariantMap *>(iter->data());
91         writeVariantHelper(nextMap, path, value, depth + 1);
92     }
93 }
94 
writeVariant(QVariantMap & map,const QString & path,const QVariant & value)95 void writeVariant(QVariantMap &map, const QString &path,
96                   const QVariant &value) {
97     auto pathList = path.split("/");
98     if (pathList.empty()) {
99         return;
100     }
101     writeVariantHelper(map, pathList, value, 0);
102 }
103 
104 } // namespace kcm
105 } // namespace fcitx
106