1 #pragma once
2
3 #include <mbgl/style/conversion.hpp>
4 #include <mbgl/style/conversion/geojson.hpp>
5 #include <mbgl/util/optional.hpp>
6
7 #include <QVariant>
8 #include <QColor>
9 #include <QMapbox>
10 #include "qt_geojson.hpp"
11
12 namespace mbgl {
13 namespace style {
14 namespace conversion {
15
16 template <>
17 class ConversionTraits<QVariant> {
18 public:
isUndefined(const QVariant & value)19 static bool isUndefined(const QVariant& value) {
20 return value.isNull() || !value.isValid();
21 }
22
isArray(const QVariant & value)23 static bool isArray(const QVariant& value) {
24 return value.canConvert(QVariant::List);
25 }
26
arrayLength(const QVariant & value)27 static std::size_t arrayLength(const QVariant& value) {
28 return value.toList().size();
29 }
30
arrayMember(const QVariant & value,std::size_t i)31 static QVariant arrayMember(const QVariant& value, std::size_t i) {
32 return value.toList()[i];
33 }
34
isObject(const QVariant & value)35 static bool isObject(const QVariant& value) {
36 return value.canConvert(QVariant::Map)
37 || value.type() == QVariant::ByteArray
38 #if QT_VERSION >= 0x050000
39 || QString(value.typeName()) == QStringLiteral("QMapbox::Feature");
40 #else
41 || QString(value.typeName()) == QString("QMapbox::Feature");
42 #endif
43 }
44
objectMember(const QVariant & value,const char * key)45 static optional<QVariant> objectMember(const QVariant& value, const char* key) {
46 auto map = value.toMap();
47 auto iter = map.constFind(key);
48
49 if (iter != map.constEnd()) {
50 return iter.value();
51 } else {
52 return {};
53 }
54 }
55
56 template <class Fn>
eachMember(const QVariant & value,Fn && fn)57 static optional<Error> eachMember(const QVariant& value, Fn&& fn) {
58 auto map = value.toMap();
59 auto iter = map.constBegin();
60
61 while (iter != map.constEnd()) {
62 optional<Error> result = fn(iter.key().toStdString(), QVariant(iter.value()));
63 if (result) {
64 return result;
65 }
66
67 ++iter;
68 }
69
70 return {};
71 }
72
toBool(const QVariant & value)73 static optional<bool> toBool(const QVariant& value) {
74 if (value.type() == QVariant::Bool) {
75 return value.toBool();
76 } else {
77 return {};
78 }
79 }
80
toNumber(const QVariant & value)81 static optional<float> toNumber(const QVariant& value) {
82 if (value.type() == QVariant::Int || value.type() == QVariant::Double) {
83 return value.toFloat();
84 } else {
85 return {};
86 }
87 }
88
toDouble(const QVariant & value)89 static optional<double> toDouble(const QVariant& value) {
90 if (value.type() == QVariant::Int || value.type() == QVariant::Double) {
91 return value.toDouble();
92 } else {
93 return {};
94 }
95 }
96
toString(const QVariant & value)97 static optional<std::string> toString(const QVariant& value) {
98 if (value.type() == QVariant::String) {
99 return value.toString().toStdString();
100 } else if (value.type() == QVariant::Color) {
101 return value.value<QColor>().name().toStdString();
102 } else {
103 return {};
104 }
105 }
106
toValue(const QVariant & value)107 static optional<Value> toValue(const QVariant& value) {
108 if (value.type() == QVariant::Bool) {
109 return { value.toBool() };
110 } else if (value.type() == QVariant::String) {
111 return { value.toString().toStdString() };
112 } else if (value.type() == QVariant::Color) {
113 return { value.value<QColor>().name().toStdString() };
114 } else if (value.type() == QVariant::Int) {
115 return { int64_t(value.toInt()) };
116 } else if (value.canConvert(QVariant::Double)) {
117 return { value.toDouble() };
118 } else {
119 return {};
120 }
121 }
122
toGeoJSON(const QVariant & value,Error & error)123 static optional<GeoJSON> toGeoJSON(const QVariant& value, Error& error) {
124 #if QT_VERSION >= 0x050000
125 if (value.typeName() == QStringLiteral("QMapbox::Feature")) {
126 #else
127 if (value.typeName() == QString("QMapbox::Feature")) {
128 #endif
129 return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) };
130 } else if (value.type() != QVariant::ByteArray) {
131 error = { "JSON data must be in QByteArray" };
132 return {};
133 }
134
135 QByteArray data = value.toByteArray();
136 return parseGeoJSON(std::string(data.constData(), data.size()), error);
137 }
138 };
139
140 template <class T, class...Args>
convert(const QVariant & value,Error & error,Args &&...args)141 optional<T> convert(const QVariant& value, Error& error, Args&&...args) {
142 return convert<T>(Convertible(value), error, std::forward<Args>(args)...);
143 }
144
145 } // namespace conversion
146 } // namespace style
147 } // namespace mbgl
148