2 ******************************************************************************
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
8 * @see The GNU Public License (GPL) Version 3
9 * @brief Widget for Import/Export Plugin
10 * @addtogroup GCSPlugins GCS Plugins
15 *****************************************************************************/
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 /* Nokia Corporation */
32 #include "xmlconfig.h"
35 #include <QStringList>
37 #include <QDataStream>
43 #include <QDomElement>
45 #define NUM_PREFIX "arr_"
47 const QString
XmlConfig::RootName
= "gcs";
49 const QSettings::Format
XmlConfig::XmlFormat
=
50 QSettings::registerFormat("xml", XmlConfig::readXmlFile
, XmlConfig::writeXmlFile
);
52 bool XmlConfig::readXmlFile(QIODevice
&device
, QSettings::SettingsMap
&map
)
60 if (!domDoc
.setContent(&device
, true, &errorStr
, &errorLine
,
62 QString err
= QString(tr("GCS config")) +
63 tr("Parse error at line %1, column %2:\n%3")
67 qFatal("%s", err
.toLatin1().data());
70 root
= domDoc
.documentElement();
71 handleNode(&root
, map
);
76 void XmlConfig::handleNode(QDomElement
*node
, QSettings::SettingsMap
&map
, QString path
)
81 // qDebug() << "XmlConfig::handleNode start";
83 QString nodeName
= node
->nodeName();
84 // For arrays, QT will use simple numbers as keys, which is not a valid element in XML.
85 // Therefore we prefixed these.
86 if (nodeName
.startsWith(NUM_PREFIX
)) {
87 nodeName
.replace(NUM_PREFIX
, "");
89 // Xml tags are restrictive with allowed characters,
90 // so we urlencode and replace % with __PCT__ on file
91 nodeName
= nodeName
.replace("__PCT__", "%");
92 nodeName
= QUrl::fromPercentEncoding(nodeName
.toLatin1());
94 if (nodeName
== XmlConfig::RootName
) {
96 } else if (path
== "") {
99 path
+= "/" + nodeName
;
102 // qDebug() << "Node: " << ": " << path << " Children: " << node->childNodes().length();
103 for (int i
= 0; i
< node
->childNodes().length(); ++i
) {
104 QDomNode child
= node
->childNodes().item(i
);
105 if (child
.isElement()) {
106 handleNode(static_cast<QDomElement
*>(&child
), map
, path
);
107 } else if (child
.isText()) {
108 // qDebug() << "Key: " << path << " Value:" << node->text();
109 map
.insert(path
, stringToVariant(node
->text()));
111 qDebug() << "Child not Element or text!" << child
.nodeType();
114 // qDebug() << "XmlConfig::handleNode end";
117 bool XmlConfig::writeXmlFile(QIODevice
&device
, const QSettings::SettingsMap
&map
)
119 QDomDocument outDocument
;
121 // qDebug() << "writeXmlFile start";
122 outDocument
.appendChild(outDocument
.createElement(XmlConfig::RootName
));
123 QMapIterator
<QString
, QVariant
> iter(map
);
124 while (iter
.hasNext()) {
126 // qDebug() << "Entry: " << iter.key() << ": " << iter.value().toString() << endl;
127 QDomNode node
= outDocument
.firstChild();
128 foreach(QString elem
, iter
.key().split('/')) {
132 // Xml tags are restrictive with allowed characters,
133 // so we urlencode and replace % with __PCT__ on file
134 elem
= QString(QUrl::toPercentEncoding(elem
));
135 elem
= elem
.replace("%", "__PCT__");
136 // For arrays, QT will use simple numbers as keys, which is not a valid element in XML.
137 // Therefore we prefixed these.
138 if (elem
.startsWith(NUM_PREFIX
)) {
139 qWarning() << "ERROR: Settings must not start with " << NUM_PREFIX
140 << " in: " + iter
.key();
142 if (QRegExp("[0-9]").exactMatch(elem
.left(1))) {
143 elem
.prepend(NUM_PREFIX
);
145 if (node
.firstChildElement(elem
).isNull()) {
146 node
.appendChild(outDocument
.createElement(elem
));
148 node
= node
.firstChildElement(elem
);
150 node
.appendChild(outDocument
.createTextNode(variantToString(iter
.value())));
152 device
.write(outDocument
.toByteArray(2).constData());
153 // qDebug() << "Document:\n" << outDocument.toByteArray(2).constData();
154 // qDebug() << "writeXmlFile end";
158 QString
XmlConfig::variantToString(const QVariant
&v
)
163 case QVariant::Invalid
:
164 result
= QLatin1String("@Invalid()");
167 case QVariant::ByteArray
:
169 QByteArray a
= v
.toByteArray().toBase64();
170 result
= QLatin1String("@ByteArray(");
171 result
+= QString::fromLatin1(a
.constData(), a
.size());
172 result
+= QLatin1Char(')');
176 case QVariant::String
:
177 case QVariant::LongLong
:
178 case QVariant::ULongLong
:
182 case QVariant::Double
:
183 case QVariant::KeySequence
:
184 case QVariant::Color
:
186 result
= v
.toString();
187 if (result
.startsWith(QLatin1Char('@'))) {
188 result
.prepend(QLatin1Char('@'));
192 #ifndef QT_NO_GEOM_VARIANT
195 QRect r
= qvariant_cast
<QRect
>(v
);
196 result
+= QLatin1String("@Rect(");
197 result
+= QString::number(r
.x());
198 result
+= QLatin1Char(' ');
199 result
+= QString::number(r
.y());
200 result
+= QLatin1Char(' ');
201 result
+= QString::number(r
.width());
202 result
+= QLatin1Char(' ');
203 result
+= QString::number(r
.height());
204 result
+= QLatin1Char(')');
209 QSize s
= qvariant_cast
<QSize
>(v
);
210 result
+= QLatin1String("@Size(");
211 result
+= QString::number(s
.width());
212 result
+= QLatin1Char(' ');
213 result
+= QString::number(s
.height());
214 result
+= QLatin1Char(')');
217 case QVariant::Point
:
219 QPoint p
= qvariant_cast
<QPoint
>(v
);
220 result
+= QLatin1String("@Point(");
221 result
+= QString::number(p
.x());
222 result
+= QLatin1Char(' ');
223 result
+= QString::number(p
.y());
224 result
+= QLatin1Char(')');
227 #endif // !QT_NO_GEOM_VARIANT
231 #ifndef QT_NO_DATASTREAM
234 QDataStream
s(&a
, QIODevice::WriteOnly
);
235 s
.setVersion(QDataStream::Qt_4_0
);
239 result
= QLatin1String("@Variant(");
240 result
+= QString::fromLatin1(a
.toBase64().constData());
241 result
+= QLatin1Char(')');
242 // These were being much too noisy!!
243 // qDebug() << "Variant Type: " << v.type();
244 // qDebug()<< "Variant: " << result;
246 Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
255 QVariant
XmlConfig::stringToVariant(const QString
&s
)
257 if (s
.startsWith(QLatin1Char('@'))) {
258 if (s
.endsWith(QLatin1Char(')'))) {
259 if (s
.startsWith(QLatin1String("@ByteArray("))) {
260 return QVariant(QByteArray::fromBase64(s
.toLatin1().mid(11, s
.size() - 12)));
261 } else if (s
.startsWith(QLatin1String("@Variant("))) {
262 #ifndef QT_NO_DATASTREAM
263 QByteArray
a(QByteArray::fromBase64(s
.toLatin1().mid(9)));
264 QDataStream
stream(&a
, QIODevice::ReadOnly
);
265 stream
.setVersion(QDataStream::Qt_4_0
);
271 Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
273 #ifndef QT_NO_GEOM_VARIANT
274 } else if (s
.startsWith(QLatin1String("@Rect("))) {
275 QStringList args
= splitArgs(s
, 5);
276 if (args
.size() == 4) {
277 return QVariant(QRect(args
[0].toInt(), args
[1].toInt(), args
[2].toInt(), args
[3].toInt()));
279 } else if (s
.startsWith(QLatin1String("@Size("))) {
280 QStringList args
= splitArgs(s
, 5);
281 if (args
.size() == 2) {
282 return QVariant(QSize(args
[0].toInt(), args
[1].toInt()));
284 } else if (s
.startsWith(QLatin1String("@Point("))) {
285 QStringList args
= splitArgs(s
, 6);
286 if (args
.size() == 2) {
287 return QVariant(QPoint(args
[0].toInt(), args
[1].toInt()));
290 } else if (s
== QLatin1String("@Invalid()")) {
294 if (s
.startsWith(QLatin1String("@@"))) {
295 return QVariant(s
.mid(1));
302 QStringList
XmlConfig::splitArgs(const QString
&s
, int idx
)
307 Q_ASSERT(s
.at(idx
) == QLatin1Char('('));
308 Q_ASSERT(s
.at(l
- 1) == QLatin1Char(')'));
313 for (++idx
; idx
< l
; ++idx
) {
315 if (c
== QLatin1Char(')')) {
316 Q_ASSERT(idx
== l
- 1);
318 } else if (c
== QLatin1Char(' ')) {