MythTV master
mythxmlplistserialiser.cpp
Go to the documentation of this file.
1// Qt
2#include <QMetaProperty>
3#include <QSequentialIterable>
4
5// MythTV
6#include "mythdate.h"
7#include "http/mythhttpdata.h"
9
10MythXMLPListSerialiser::MythXMLPListSerialiser(const QString& Name, const QVariant& Value)
11{
12 m_writer.setDevice(&m_buffer);
13 m_writer.setAutoFormatting(true);
14 m_writer.setAutoFormattingIndent(4);
15 m_writer.writeStartDocument("1.0");
16 m_writer.writeDTD(R"(<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">)");
17 m_writer.writeStartElement("plist");
18 m_writer.writeAttribute("version", "1.0");
19 m_writer.writeStartElement("dict");
20 m_writer.writeTextElement("key", "serializerversion");
21 m_writer.writeTextElement("string", XML_PLIST_SERIALIZER_VERSION);
22 QString name = Name;
23 if (name.startsWith("V2"))
24 name.remove(0,2);
25 AddObject(name, Value);
26 m_writer.writeEndElement();
27 m_writer.writeEndElement();
28 m_writer.writeEndDocument();
29}
30
31void MythXMLPListSerialiser::AddObject(const QString& Name, const QVariant& Value)
32{
33 auto * object = Value.value<QObject*>();
34 AddValue(object ? GetContentName(Name, object->metaObject()) : Name, Value);
35}
36
37void MythXMLPListSerialiser::AddValue(const QString& Name, const QVariant& Value, bool NeedKey)
38{
39 auto * object = Value.value<QObject*>();
40 if (object)
41 {
42 QVariant isNull = object->property("isNull");
43 if (isNull.value<bool>())
44 return;
45 AddQObject(Name, object);
46 return;
47 }
48
49 switch (
50#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
51 static_cast<QMetaType::Type>(Value.type())
52#else
53 static_cast<QMetaType::Type>(Value.typeId())
54#endif
55 )
56 {
57 case QMetaType::QStringList: AddStringList(Name, Value); break;
58 case QMetaType::QVariantList: AddList(Name, Value.toList()); break;
59 case QMetaType::QVariantMap: AddMap(Name, Value.toMap()); break;
60 case QMetaType::UInt:
61 case QMetaType::ULongLong:
62 {
63 if (NeedKey)
64 m_writer.writeTextElement("key", Name);
65 m_writer.writeTextElement("integer", QString::number(Value.toULongLong()));
66 break;
67 }
68
69 case QMetaType::Int:
70 case QMetaType::LongLong:
71 case QMetaType::Double:
72 {
73 if (NeedKey)
74 m_writer.writeTextElement("key", Name);
75 m_writer.writeTextElement("real", QString("%1").arg(Value.toDouble(), 0, 'f', 6));
76 break;
77 }
78 case QMetaType::Float:
79 {
80 if (NeedKey)
81 m_writer.writeTextElement("key", Name);
82 m_writer.writeTextElement("real", QString("%1").arg(Value.toFloat(), 0, 'f', 6));
83 break;
84 }
85 case QMetaType::QByteArray:
86 {
87 if (!Value.toByteArray().isNull())
88 {
89 if (NeedKey)
90 m_writer.writeTextElement("key", Name);
91 m_writer.writeTextElement("data", Value.toByteArray().toBase64().data());
92 }
93 break;
94 }
95 case QMetaType::Bool:
96 {
97 if (NeedKey)
98 m_writer.writeTextElement("key", Name);
99 m_writer.writeEmptyElement(Value.toBool() ? "true" : "false");
100 break;
101 }
102 case QMetaType::QDateTime:
103 if (Value.toDateTime().isValid())
104 {
105 if (NeedKey)
106 m_writer.writeTextElement("key", Name);
107 m_writer.writeTextElement("date", Value.toDateTime().toUTC().toString("yyyy-MM-ddThh:mm:ssZ"));
108 }
109 break;
110 case QMetaType::QString:
111 default:
112 if (NeedKey)
113 m_writer.writeTextElement("key", Name);
114 m_writer.writeTextElement("string", Value.toString());
115 }
116}
117
118void MythXMLPListSerialiser::AddQObject(const QString &Name, const QObject* Object)
119{
120 if (!Object)
121 return;
122
123 m_writer.writeTextElement("key", Name);
124 m_writer.writeStartElement("dict");
125
126 const auto * meta = Object->metaObject();
127 if (int index = meta->indexOfClassInfo("Version"); index >= 0)
128 {
129 m_writer.writeTextElement("key", "version");
130 m_writer.writeTextElement("string", meta->classInfo(index).value());
131 }
132
133 int count = meta->propertyCount();
134 for (int index = 0; index < count; ++index )
135 {
136 QMetaProperty metaproperty = meta->property(index);
137 if (
138#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
139 metaproperty.isUser(Object)
140#else
141 metaproperty.isUser()
142#endif
143 )
144 {
145 const char *rawname = metaproperty.name();
146 QString name(rawname);
147 if (name.compare("objectName") == 0)
148 continue;
149 AddProperty(name, Object->property(rawname), meta, &metaproperty);
150 }
151 }
152
153 m_writer.writeEndElement();
154}
155
156void MythXMLPListSerialiser::AddProperty(const QString& Name, const QVariant& Value,
157 const QMetaObject* MetaObject, const QMetaProperty *MetaProperty)
158{
159 QString value;
160 // Enum ?
161 if (MetaProperty && (MetaProperty->isEnumType() || MetaProperty->isFlagType()))
162 {
163 QMetaEnum metaEnum = MetaProperty->enumerator();
164 value = MetaProperty->isFlagType() ? metaEnum.valueToKeys(Value.toInt()).constData() :
165 metaEnum.valueToKey(Value.toInt());
166 }
167 AddValue(GetContentName(Name, MetaObject), value.isEmpty() ? Value : value);
168}
169
170void MythXMLPListSerialiser::AddStringList(const QString& Name, const QVariant& Values)
171{
172 m_writer.writeTextElement("key", Name);
173 m_writer.writeStartElement("array");
174 auto values = Values.value<QSequentialIterable>();
175 for (const auto & value : values)
176 m_writer.writeTextElement("string", value.toString());
177 m_writer.writeEndElement();
178}
179
180void MythXMLPListSerialiser::AddList(const QString& Name, const QVariantList &Values)
181{
182 bool array = true;
183 if (!Values.isEmpty())
184 {
185#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
186 auto type = static_cast<QMetaType::Type>(Values.front().type());
187 auto typesEqual = [type](const QVariant& value)
188 { return (static_cast<QMetaType::Type>(value.type()) == type); };
189#else
190 auto type = static_cast<QMetaType::Type>(Values.front().typeId());
191 auto typesEqual = [type](const QVariant& value)
192 { return (static_cast<QMetaType::Type>(value.typeId()) == type); };
193#endif
194 array = std::all_of(Values.cbegin(), Values.cend(), typesEqual);
195 }
196
197 QString name = GetItemName(Name);
198 m_writer.writeTextElement("key", name);
199 m_writer.writeStartElement(array ? "array" : "dict");
200
201 QListIterator<QVariant> it(Values);
202 while (it.hasNext())
203 AddValue(name, it.next(), !array);
204 m_writer.writeEndElement();
205}
206
207void MythXMLPListSerialiser::AddMap(const QString& Name, const QVariantMap& Map)
208{
209 QString itemname = GetItemName(Name);
210 m_writer.writeTextElement("key", itemname);
211 m_writer.writeStartElement("dict");
212 for (auto it = Map.cbegin(); it != Map.cend(); ++it)
213 AddValue(it.key(), it.value());
214 m_writer.writeEndElement();
215}
216
218{
219 QString name = Name.startsWith("Q") ? Name.mid(1) : Name;
220 name.remove("DTC::");
221 if (name.startsWith("V2"))
222 name.remove(0,2);
223 name.remove(QChar('*'));
224 return name;
225}
226
228QString MythXMLPListSerialiser::GetContentName(const QString& Name, const QMetaObject* MetaObject)
229{
230 // Try to read Name or TypeName from classinfo metadata.
231 if (int index = MetaObject ? MetaObject->indexOfClassInfo(Name.toLatin1()) : -1; index >= 0)
232 {
233 QStringList infos = QString(MetaObject->classInfo(index).value()).split(';', Qt::SkipEmptyParts);
234 QString type; // fallback
235 foreach (const QString &info, infos)
236 {
237 if (info.startsWith(QStringLiteral("name=")))
238 if (auto name = info.mid(5).trimmed(); !name.isEmpty())
239 return GetItemName(name);
240 if (info.startsWith(QStringLiteral("type=")))
241 type = info.mid(5).trimmed();
242 }
243 if (!type.isEmpty())
244 return GetItemName(type);
245 }
246
247 // Neither found, so lets use the type name (slightly modified).
248 return GetItemName(Name);
249}
250
void AddProperty(const QString &Name, const QVariant &Value, const QMetaObject *MetaObject, const QMetaProperty *MetaProperty)
static QString GetItemName(const QString &Name)
void AddStringList(const QString &Name, const QVariant &Values)
void AddList(const QString &Name, const QVariantList &Values)
void AddQObject(const QString &Name, const QObject *Object)
void AddObject(const QString &Name, const QVariant &Value)
MythXMLPListSerialiser(const QString &Name, const QVariant &Value)
void AddValue(const QString &Name, const QVariant &Value, bool NeedKey=true)
static QString GetContentName(const QString &Name, const QMetaObject *MetaObject)
FIXME We shouldn't be doing this on the fly.
void AddMap(const QString &Name, const QVariantMap &Map)
#define XML_PLIST_SERIALIZER_VERSION
dictionary info
Definition: azlyrics.py:7