dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
xmlconfig.cpp
Go to the documentation of this file.
1 
15 /*
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.
20  *
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
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, see <http://www.gnu.org/licenses/>
28  */
29 /* Nokia Corporation */
30 #include "xmlconfig.h"
31 
32 #include <QtDebug>
33 #include <QStringList>
34 #include <QRegExp>
35 
36 #include <QVariant>
37 #include <QRect>
38 #include <QSize>
39 #include <QPoint>
40 #include <QtCore/QUrl>
41 #include <QDataStream>
42 
43 #define NUM_PREFIX "arr_"
44 
45 QString XmlConfig::rootName = "gcs";
46 
47 const QSettings::Format XmlConfig::XmlSettingsFormat =
48  QSettings::registerFormat("xml", XmlConfig::readXmlFile, XmlConfig::writeXmlFile);
49 
50 
51 bool XmlConfig::readXmlFile(QIODevice &device, QSettings::SettingsMap &map)
52 {
53  QDomDocument domDoc;
54  QDomElement root;
55  QString errorStr;
56  int errorLine;
57  int errorColumn;
58 
59  if (!domDoc.setContent(&device, true, &errorStr, &errorLine,
60  &errorColumn)) {
61  QString err = QString(tr("GCS config")) +
62  tr("Parse error at line %1, column %2:\n%3")
63  .arg(errorLine)
64  .arg(errorColumn)
65  .arg(errorStr);
66  qFatal("%s",err.toLatin1().data());
67  return false;
68  }
69  root = domDoc.documentElement();
70  handleNode(&root, map);
71 
72  return true;
73 }
74 
75 void XmlConfig::handleNode(QDomElement* node, QSettings::SettingsMap &map, QString path)
76 {
77  if ( !node ){
78  return;
79  }
80  // qDebug() << "XmlConfig::handleNode start";
81 
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, "");
87  }
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());
92 
93  if ( nodeName == XmlConfig::rootName )
94  ;
95  else if ( path == "" )
96  path = nodeName;
97  else
98  path += "/" + nodeName;
99 
100 // qDebug() << "Node: " << ": " << path << " Children: " << node->childNodes().length();
101  for ( int i = 0; i < node->childNodes().length(); ++i ){
102  QDomNode child = node->childNodes().item(i);
103  if ( child.isElement() ){
104  handleNode( static_cast<QDomElement*>(&child), map, path);
105  }
106  else if ( child.isText() ){
107 // qDebug() << "Key: " << path << " Value:" << node->text();
108  map.insert(path, stringToVariant(node->text()));
109  }
110  else{
111  qDebug() << "Child not Element or text!" << child.nodeType();
112  }
113  }
114 // qDebug() << "XmlConfig::handleNode end";
115 }
116 
117 bool XmlConfig::writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map)
118 {
119  QDomDocument outDocument;
120 // qDebug() << "writeXmlFile start";
121  outDocument.appendChild( outDocument.createElement(XmlConfig::rootName));
122  QMapIterator<QString, QVariant> iter(map);
123  while (iter.hasNext()) {
124  iter.next();
125 // qDebug() << "Entry: " << iter.key() << ": " << iter.value().toString() << endl;
126  QDomNode node = outDocument.firstChild();
127  foreach ( QString elem, iter.key().split('/')){
128  if ( elem == "" ){
129  continue;
130  }
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();
140  }
141  if ( QRegExp("[0-9]").exactMatch(elem.left(1)) ){
142  elem.prepend(NUM_PREFIX);
143  }
144  if ( node.firstChildElement(elem).isNull() ){
145  node.appendChild(outDocument.createElement(elem));
146  }
147  node = node.firstChildElement(elem);
148  }
149  node.appendChild(outDocument.createTextNode(variantToString(iter.value())));
150  }
151  device.write(outDocument.toByteArray(2).constData());
152 // qDebug() << "Dokument:\n" << outDocument.toByteArray(2).constData();
153 // qDebug() << "writeXmlFile end";
154  return true;
155 }
156 
157 
158 QSettings::SettingsMap XmlConfig::settingsToMap(QSettings& qs){
159  qDebug() << "settingsToMap:---------------";
160  QSettings::SettingsMap map;
161  QStringList keys = qs.allKeys();
162  foreach (QString key, keys) {
163  QVariant val = qs.value(key);
164  qDebug() << key << val.toString();
165  map.insert(key, val);
166  }
167  qDebug() << "settingsToMap End --------";
168  return map;
169 }
170 
171 QString XmlConfig::variantToString(const QVariant &v)
172 {
173  QString result;
174 
175  switch (v.type()) {
176  case QVariant::Invalid:
177  result = QLatin1String("@Invalid()");
178  break;
179 
180  case QVariant::ByteArray: {
181  QByteArray a = v.toByteArray().toBase64();
182  result = QLatin1String("@ByteArray(");
183  result += QString::fromLatin1(a.constData(), a.size());
184  result += QLatin1Char(')');
185  break;
186  }
187 
188  case QVariant::String:
189  case QVariant::LongLong:
190  case QVariant::ULongLong:
191  case QVariant::Int:
192  case QVariant::UInt:
193  case QVariant::Bool:
194  case QVariant::Double:
195  case QVariant::KeySequence:
196  case QVariant::Color: {
197  result = v.toString();
198  if (result.startsWith(QLatin1Char('@')))
199  result.prepend(QLatin1Char('@'));
200  break;
201  }
202 #ifndef QT_NO_GEOM_VARIANT
203  case QVariant::Rect: {
204  QRect r = qvariant_cast<QRect>(v);
205  result += QLatin1String("@Rect(");
206  result += QString::number(r.x());
207  result += QLatin1Char(' ');
208  result += QString::number(r.y());
209  result += QLatin1Char(' ');
210  result += QString::number(r.width());
211  result += QLatin1Char(' ');
212  result += QString::number(r.height());
213  result += QLatin1Char(')');
214  break;
215  }
216  case QVariant::Size: {
217  QSize s = qvariant_cast<QSize>(v);
218  result += QLatin1String("@Size(");
219  result += QString::number(s.width());
220  result += QLatin1Char(' ');
221  result += QString::number(s.height());
222  result += QLatin1Char(')');
223  break;
224  }
225  case QVariant::Point: {
226  QPoint p = qvariant_cast<QPoint>(v);
227  result += QLatin1String("@Point(");
228  result += QString::number(p.x());
229  result += QLatin1Char(' ');
230  result += QString::number(p.y());
231  result += QLatin1Char(')');
232  break;
233  }
234 #endif // !QT_NO_GEOM_VARIANT
235 
236  default: {
237 #ifndef QT_NO_DATASTREAM
238  QByteArray a;
239  {
240  QDataStream s(&a, QIODevice::WriteOnly);
241  s.setVersion(QDataStream::Qt_4_0);
242  s << v;
243  }
244 
245  result = QLatin1String("@Variant(");
246  result += QString::fromLatin1(a.toBase64().constData());
247  result += QLatin1Char(')');
248  // These were being much too noisy!!
249  //qDebug() << "Variant Type: " << v.type();
250  //qDebug()<< "Variant: " << result;
251 #else
252  Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
253 #endif
254  break;
255  }
256 }
257 
258 return result;
259 }
260 
261 QVariant XmlConfig::stringToVariant(const QString &s)
262 {
263  if (s.startsWith(QLatin1Char('@'))) {
264  if (s.endsWith(QLatin1Char(')'))) {
265  if (s.startsWith(QLatin1String("@ByteArray("))) {
266  return QVariant(QByteArray::fromBase64(s.toLatin1().mid(11, s.size() - 12)));
267  } else if (s.startsWith(QLatin1String("@Variant("))) {
268 #ifndef QT_NO_DATASTREAM
269  QByteArray a(QByteArray::fromBase64(s.toLatin1().mid(9)));
270  QDataStream stream(&a, QIODevice::ReadOnly);
271  stream.setVersion(QDataStream::Qt_4_0);
272  QVariant result;
273  stream >> result;
274  return result;
275 #else
276  Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
277 #endif
278 #ifndef QT_NO_GEOM_VARIANT
279  } else if (s.startsWith(QLatin1String("@Rect("))) {
280  QStringList args = splitArgs(s, 5);
281  if (args.size() == 4)
282  return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
283  } else if (s.startsWith(QLatin1String("@Size("))) {
284  QStringList args = splitArgs(s, 5);
285  if (args.size() == 2)
286  return QVariant(QSize(args[0].toInt(), args[1].toInt()));
287  } else if (s.startsWith(QLatin1String("@Point("))) {
288  QStringList args = splitArgs(s, 6);
289  if (args.size() == 2)
290  return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
291 #endif
292  } else if (s == QLatin1String("@Invalid()")) {
293  return QVariant();
294  }
295 
296  }
297  if (s.startsWith(QLatin1String("@@")))
298  return QVariant(s.mid(1));
299  }
300 
301  return QVariant(s);
302 }
303 
304 QStringList XmlConfig::splitArgs(const QString &s, int idx)
305 {
306  int l = s.length();
307  Q_ASSERT(l > 0);
308  Q_ASSERT(s.at(idx) == QLatin1Char('('));
309  Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
310 
311  QStringList result;
312  QString item;
313 
314  for (++idx; idx < l; ++idx) {
315  QChar c = s.at(idx);
316  if (c == QLatin1Char(')')) {
317  Q_ASSERT(idx == l - 1);
318  result.append(item);
319  } else if (c == QLatin1Char(' ')) {
320  result.append(item);
321  item.clear();
322  } else {
323  item.append(c);
324  }
325  }
326 
327  return result;
328 }
329 
iter
Definition: OPPlots.m:115
for i
Definition: OPPlots.m:140
end a
Definition: OPPlots.m:98
static bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map)
Definition: xmlconfig.cpp:51
static bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map)
Definition: xmlconfig.cpp:117
static const QSettings::Format XmlSettingsFormat
Definition: xmlconfig.h:43