2 ******************************************************************************
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @see The GNU Public License (GPL) Version 3
8 * @brief Widget for Import/Export Plugin
9 * @addtogroup GCSPlugins GCS Plugins
11 * @addtogroup importexportplugin
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 /* Nokia Corporation */
31 #include "xmlconfig.h"
34 #include <QStringList>
41 #include <QtCore/QUrl>
43 #define NUM_PREFIX "arr_"
45 QString
XmlConfig::rootName
= "gcs";
47 const QSettings::Format
XmlConfig::XmlSettingsFormat
=
48 QSettings::registerFormat("xml", XmlConfig::readXmlFile
, XmlConfig::writeXmlFile
);
51 bool XmlConfig::readXmlFile(QIODevice
&device
, QSettings::SettingsMap
&map
)
59 if (!domDoc
.setContent(&device
, true, &errorStr
, &errorLine
,
61 QString err
= QString(tr("GCS config")) +
62 tr("Parse error at line %1, column %2:\n%3")
66 qFatal("%s", err
.toLatin1().data());
69 root
= domDoc
.documentElement();
70 handleNode(&root
, map
);
75 void XmlConfig::handleNode(QDomElement
*node
, QSettings::SettingsMap
&map
, QString path
)
80 // qDebug() << "XmlConfig::handleNode start";
82 QString nodeName
= node
->nodeName();
83 // For arrays, QT will use simple numbers as keys, which is not a valid element in XML.
84 // Therefore we prefixed these.
85 if (nodeName
.startsWith(NUM_PREFIX
)) {
86 nodeName
.replace(NUM_PREFIX
, "");
88 // Xml tags are restrictive with allowed characters,
89 // so we urlencode and replace % with __PCT__ on file
90 nodeName
= nodeName
.replace("__PCT__", "%");
91 nodeName
= QUrl::fromPercentEncoding(nodeName
.toLatin1());
93 if (nodeName
== XmlConfig::rootName
) {
95 } else if (path
== "") {
98 path
+= "/" + nodeName
;
101 // qDebug() << "Node: " << ": " << path << " Children: " << node->childNodes().length();
102 for (int i
= 0; i
< node
->childNodes().length(); ++i
) {
103 QDomNode child
= node
->childNodes().item(i
);
104 if (child
.isElement()) {
105 handleNode(static_cast<QDomElement
*>(&child
), map
, path
);
106 } else if (child
.isText()) {
107 // qDebug() << "Key: " << path << " Value:" << node->text();
108 map
.insert(path
, stringToVariant(node
->text()));
110 qDebug() << "Child not Element or text!" << child
.nodeType();
113 // qDebug() << "XmlConfig::handleNode end";
116 bool XmlConfig::writeXmlFile(QIODevice
&device
, const QSettings::SettingsMap
&map
)
118 QDomDocument outDocument
;
120 // qDebug() << "writeXmlFile start";
121 outDocument
.appendChild(outDocument
.createElement(XmlConfig::rootName
));
122 QMapIterator
<QString
, QVariant
> iter(map
);
123 while (iter
.hasNext()) {
125 // qDebug() << "Entry: " << iter.key() << ": " << iter.value().toString() << endl;
126 QDomNode node
= outDocument
.firstChild();
127 foreach(QString elem
, iter
.key().split('/')) {
131 // Xml tags are restrictive with allowed characters,
132 // so we urlencode and replace % with __PCT__ on file
133 elem
= QString(QUrl::toPercentEncoding(elem
));
134 elem
= elem
.replace("%", "__PCT__");
135 // For arrays, QT will use simple numbers as keys, which is not a valid element in XML.
136 // Therefore we prefixed these.
137 if (elem
.startsWith(NUM_PREFIX
)) {
138 qWarning() << "ERROR: Settings must not start with " << NUM_PREFIX
139 << " in: " + iter
.key();
141 if (QRegExp("[0-9]").exactMatch(elem
.left(1))) {
142 elem
.prepend(NUM_PREFIX
);
144 if (node
.firstChildElement(elem
).isNull()) {
145 node
.appendChild(outDocument
.createElement(elem
));
147 node
= node
.firstChildElement(elem
);
149 node
.appendChild(outDocument
.createTextNode(variantToString(iter
.value())));
151 device
.write(outDocument
.toByteArray(2).constData());
152 // qDebug() << "Dokument:\n" << outDocument.toByteArray(2).constData();
153 // qDebug() << "writeXmlFile end";
158 QSettings::SettingsMap
XmlConfig::settingsToMap(QSettings
& qs
)
160 qDebug() << "settingsToMap:---------------";
161 QSettings::SettingsMap map
;
162 QStringList keys
= qs
.allKeys();
163 foreach(QString key
, keys
) {
164 QVariant val
= qs
.value(key
);
166 qDebug() << key
<< val
.toString();
167 map
.insert(key
, val
);
169 qDebug() << "settingsToMap End --------";
173 QString
XmlConfig::variantToString(const QVariant
&v
)
178 case QVariant::Invalid
:
179 result
= QLatin1String("@Invalid()");
182 case QVariant::ByteArray
:
184 QByteArray a
= v
.toByteArray().toBase64();
185 result
= QLatin1String("@ByteArray(");
186 result
+= QString::fromLatin1(a
.constData(), a
.size());
187 result
+= QLatin1Char(')');
191 case QVariant::String
:
192 case QVariant::LongLong
:
193 case QVariant::ULongLong
:
197 case QVariant::Double
:
198 case QVariant::KeySequence
:
199 case QVariant::Color
:
201 result
= v
.toString();
202 if (result
.startsWith(QLatin1Char('@'))) {
203 result
.prepend(QLatin1Char('@'));
207 #ifndef QT_NO_GEOM_VARIANT
210 QRect r
= qvariant_cast
<QRect
>(v
);
211 result
+= QLatin1String("@Rect(");
212 result
+= QString::number(r
.x());
213 result
+= QLatin1Char(' ');
214 result
+= QString::number(r
.y());
215 result
+= QLatin1Char(' ');
216 result
+= QString::number(r
.width());
217 result
+= QLatin1Char(' ');
218 result
+= QString::number(r
.height());
219 result
+= QLatin1Char(')');
224 QSize s
= qvariant_cast
<QSize
>(v
);
225 result
+= QLatin1String("@Size(");
226 result
+= QString::number(s
.width());
227 result
+= QLatin1Char(' ');
228 result
+= QString::number(s
.height());
229 result
+= QLatin1Char(')');
232 case QVariant::Point
:
234 QPoint p
= qvariant_cast
<QPoint
>(v
);
235 result
+= QLatin1String("@Point(");
236 result
+= QString::number(p
.x());
237 result
+= QLatin1Char(' ');
238 result
+= QString::number(p
.y());
239 result
+= QLatin1Char(')');
242 #endif // !QT_NO_GEOM_VARIANT
246 #ifndef QT_NO_DATASTREAM
249 QDataStream
s(&a
, QIODevice::WriteOnly
);
250 s
.setVersion(QDataStream::Qt_4_0
);
254 result
= QLatin1String("@Variant(");
255 result
+= QString::fromLatin1(a
.toBase64().constData());
256 result
+= QLatin1Char(')');
257 // These were being much too noisy!!
258 // qDebug() << "Variant Type: " << v.type();
259 // qDebug()<< "Variant: " << result;
261 Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
270 QVariant
XmlConfig::stringToVariant(const QString
&s
)
272 if (s
.startsWith(QLatin1Char('@'))) {
273 if (s
.endsWith(QLatin1Char(')'))) {
274 if (s
.startsWith(QLatin1String("@ByteArray("))) {
275 return QVariant(QByteArray::fromBase64(s
.toLatin1().mid(11, s
.size() - 12)));
276 } else if (s
.startsWith(QLatin1String("@Variant("))) {
277 #ifndef QT_NO_DATASTREAM
278 QByteArray
a(QByteArray::fromBase64(s
.toLatin1().mid(9)));
279 QDataStream
stream(&a
, QIODevice::ReadOnly
);
280 stream
.setVersion(QDataStream::Qt_4_0
);
286 Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
288 #ifndef QT_NO_GEOM_VARIANT
289 } else if (s
.startsWith(QLatin1String("@Rect("))) {
290 QStringList args
= splitArgs(s
, 5);
291 if (args
.size() == 4) {
292 return QVariant(QRect(args
[0].toInt(), args
[1].toInt(), args
[2].toInt(), args
[3].toInt()));
294 } else if (s
.startsWith(QLatin1String("@Size("))) {
295 QStringList args
= splitArgs(s
, 5);
296 if (args
.size() == 2) {
297 return QVariant(QSize(args
[0].toInt(), args
[1].toInt()));
299 } else if (s
.startsWith(QLatin1String("@Point("))) {
300 QStringList args
= splitArgs(s
, 6);
301 if (args
.size() == 2) {
302 return QVariant(QPoint(args
[0].toInt(), args
[1].toInt()));
305 } else if (s
== QLatin1String("@Invalid()")) {
309 if (s
.startsWith(QLatin1String("@@"))) {
310 return QVariant(s
.mid(1));
317 QStringList
XmlConfig::splitArgs(const QString
&s
, int idx
)
322 Q_ASSERT(s
.at(idx
) == QLatin1Char('('));
323 Q_ASSERT(s
.at(l
- 1) == QLatin1Char(')'));
328 for (++idx
; idx
< l
; ++idx
) {
330 if (c
== QLatin1Char(')')) {
331 Q_ASSERT(idx
== l
- 1);
333 } else if (c
== QLatin1Char(' ')) {