CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxXmlOptionItem.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 
13 /*
14  * sscXmlOptionItem.cpp
15  *
16  * Created on: May 28, 2010
17  * Author: christiana
18  */
19 #include "cxXmlOptionItem.h"
20 
21 #include <map>
22 #include <iostream>
23 #include <QFile>
24 #include <QDir>
25 #include <QFileInfo>
26 #include <QTextStream>
27 #include <QDomElement>
28 #include <QDataStream>
29 #include <QStringList>
30 #include <QMutex>
31 #include <QBuffer>
32 #include "cxLogger.h"
33 #include "cxTypeConversions.h"
34 
35 namespace cx
36 {
37 
42 {
43 public:
45  {
46  if (!mInstance)
47  mInstance = new SharedDocuments();
48  return mInstance;
49  }
50 
54  QDomDocument loadDocument(const QString& filename)
55  {
56  QDomDocument retval;
57  retval = this->getDocument(filename);
58  if (retval.isNull())
59  {
60  retval = this->readFromFile(filename);
61  this->addDocument(filename, retval);
62  }
63  return retval;
64  }
65 
66 private:
67  SharedDocuments() : mDocumentMutex(QMutex::Recursive) {}
68 
69  QDomDocument getDocument(const QString& filename)
70  {
71  QMutexLocker lock(&mDocumentMutex);
72  DocumentMap::iterator iter = mDocuments.find(filename);
73  // if filename found, attempt to retrieve document from node.
74  if (iter != mDocuments.end())
75  {
76  return iter->second.ownerDocument();
77  }
78  return QDomDocument(); // null node
79  }
80 
81  void addDocument(const QString& filename, QDomDocument document)
82  {
83  QMutexLocker lock(&mDocumentMutex);
84  mDocuments[filename] = document.documentElement();
85  }
86 
87  QDomDocument readFromFile(QString filename)
88  {
89  QFile file(filename);
90  if (!file.open(QIODevice::ReadOnly))
91  {
92  QDomDocument doc;
93  doc.appendChild(doc.createElement("root"));
94  return doc;
95  }
96 
97  QDomDocument loadedDoc;
98  QString error;
99  int line, col;
100  if (!loadedDoc.setContent(&file, &error, &line, &col))
101  {
102  QString msg = QString("error setting xml content [%1,%2] %3").arg(line).arg(col).arg(error);
103  reportWarning(msg);
104  }
105  file.close();
106  return loadedDoc;
107  }
108 
109  static SharedDocuments* mInstance;
110  typedef std::map<QString, QDomElement> DocumentMap;
111  QMutex mDocumentMutex;
112  DocumentMap mDocuments;
113 };
115 SharedDocuments* SharedDocuments::mInstance = NULL;
117 
121 
122 QString XmlOptionItem::SerializeDataToB64String(const QVariant& data)
123 {
124  QByteArray byteArray;
125  QBuffer writeBuffer(&byteArray);
126  writeBuffer.open(QIODevice::WriteOnly);
127  QDataStream out(&writeBuffer);
128 
129  out << data;
130 
131  writeBuffer.close();
132 
133  QString s = QString(byteArray.toBase64());
134 
135 // qDebug() << "array size when written:" << byteArray.size();
136 
137  return s;
138 }
139 
140 
141 QVariant XmlOptionItem::DeserializeB64String(const QString& serializedVariant)
142 {
143  QByteArray readArr = QByteArray::fromBase64(serializedVariant.toUtf8());
144  QBuffer readBuffer(&readArr);
145  readBuffer.open(QIODevice::ReadOnly);
146  QDataStream in(&readBuffer);
147 
148  QVariant data;
149 
150  in >> data;
151 
152 // qDebug() << "array size when read:" << readArr.size();
153 
154  return data;
155 }
156 
157 XmlOptionItem::XmlOptionItem(const QString& uid, QDomElement root) :
158  mUid(uid), mRoot(root)
159 {
160 
161 }
162 
163 QVariant XmlOptionItem::readVariant(const QVariant& defval) const
164 {
165  QString text = this->readValue("");
166  if (text.isEmpty())
167  return defval;
168  QVariant val = DeserializeB64String(text);
169  return val;
170 }
171 
172 void XmlOptionItem::writeVariant(const QVariant& val)
173 {
174  QString text = SerializeDataToB64String(val);
175  this->writeValue(text);
176 }
177 
178 QString XmlOptionItem::readValue(const QString& defval) const
179 {
180  // read value is present
181  QDomElement item = this->findElemFromUid(mUid, mRoot);
182  if (!item.isNull() && item.hasAttribute("value"))
183  {
184  return item.attribute("value");
185  }
186  return defval;
187 }
188 
189 void XmlOptionItem::writeValue(const QString& val)
190 {
191  if (mRoot.isNull())
192  return;
193  QDomElement item = findElemFromUid(mUid, mRoot);
194  // create option if not present
195  if (item.isNull())
196  {
197  item = mRoot.ownerDocument().createElement("option");
198  item.setAttribute("id", mUid);
199  mRoot.appendChild(item);
200  }
201  item.setAttribute("value", val);
202 }
203 
204 QDomElement XmlOptionItem::findElemFromUid(const QString& uid, QDomNode root) const
205 {
206  QDomNodeList settings = root.childNodes();
207  for (int i = 0; i < settings.size(); ++i)
208  {
209  QDomElement item = settings.item(i).toElement();
210  if (item.attribute("id") == uid)
211  return item;
212  }
213  return QDomElement();
214 }
215 
219 
221 {
222  XmlOptionFile retval;
223  retval.mDocument = QDomDocument();
224  retval.mCurrentElement = QDomElement();
225  return retval;
226 }
227 
229 {
230  mDocument.appendChild(mDocument.createElement("root"));
231  mCurrentElement = mDocument.documentElement();
232 }
233 
234 XmlOptionFile::XmlOptionFile(QString filename) :
235  mFilename(filename)
236 {
237  mDocument = SharedDocuments::getInstance()->loadDocument(filename);
238 
239  mCurrentElement = mDocument.documentElement();
240 
241  if (mCurrentElement.isNull())
242  {
243  mDocument.appendChild(mDocument.createElement("root"));
244  mCurrentElement = mDocument.documentElement();
245  }
246 }
247 
249 {
250 }
251 
253 {
254  return mFilename;
255 }
256 
258 {
259  if(mCurrentElement.isNull() || mDocument.isNull())
260  return true;
261  return false;
262 }
263 
265 {
266  XmlOptionFile retval = *this;
267  retval.mCurrentElement = mDocument.documentElement();
268  return retval;
269 }
270 
271 XmlOptionFile XmlOptionFile::descend(QString element) const
272 {
273  XmlOptionFile retval = *this;
274  retval.mCurrentElement = retval.getElement(element);
275  return retval;
276 }
277 
278 XmlOptionFile XmlOptionFile::descend(QString element, QString attributeName, QString attributeValue) const
279 {
280  XmlOptionFile retval = this->tryDescend(element, attributeName, attributeValue);
281  if (!retval.getDocument().isNull())
282  return retval;
283 
284  // create a new element if not found
285  retval = *this;
286  QDomElement current = retval.getDocument().createElement(element);
287  current.setAttribute(attributeName, attributeValue);
288  retval.mCurrentElement.appendChild(current);
289  retval.mCurrentElement = current;
290  return retval;
291 }
292 
293 XmlOptionFile XmlOptionFile::tryDescend(QString element, QString attributeName, QString attributeValue) const
294 {
295  XmlOptionFile retval = *this;
296 
297  QDomNodeList presetNodeList = retval.getElement().elementsByTagName(element);
298  for (int i = 0; i < presetNodeList.count(); ++i)
299  {
300  QDomElement current = presetNodeList.item(i).toElement();
301  QString name = current.attribute(attributeName);
302  if (attributeValue == name)
303  {
304  retval.mCurrentElement = current;
305  return retval;
306  }
307  }
308 
309  return XmlOptionFile::createNull();
310 }
311 
313 {
314  XmlOptionFile retval = *this;
315  retval.mCurrentElement = mCurrentElement.parentNode().toElement();
316  if (retval.mCurrentElement.isNull())
317  return *this;
318  return retval;
319 }
320 
323 QDomElement XmlOptionFile::safeGetElement(QDomElement parent, QString childName)
324 {
325  QDomElement child = parent.namedItem(childName).toElement();
326 
327  if (child.isNull())
328  {
329  child = mDocument.createElement(childName);
330  parent.appendChild(child);
331  }
332 
333  return child;
334 }
335 
337 {
338  printDocument(mDocument);
339 }
340 
342 {
343  printElement(mCurrentElement);
344 }
345 
346 void XmlOptionFile::printDocument(QDomDocument document)
347 {
348  QTextStream stream(stdout);
349  stream << "\nTEST" << document.toString(4) << "\n";
350 }
351 
352 void XmlOptionFile::printElement(QDomElement element)
353 {
354  QTextStream stream(stdout);
355  stream << "\n";
356  element.save(stream, 4);
357  stream << "\n";
358 }
359 
361 {
362  return mDocument;
363 }
364 
366 {
367  return mCurrentElement;
368 }
369 
370 QDomElement XmlOptionFile::getElement(QString level1)
371 {
372  QDomElement elem1 = this->safeGetElement(mCurrentElement, level1);
373  return elem1;
374 }
375 
376 QDomElement XmlOptionFile::getElement(QString level1, QString level2)
377 {
378  QDomElement elem1 = this->safeGetElement(mCurrentElement, level1);
379  QDomElement elem2 = this->safeGetElement(elem1, level2);
380  return elem2;
381 }
382 
384 {
385  while (mCurrentElement.hasChildNodes())
386  mCurrentElement.removeChild(mCurrentElement.firstChild());
387 }
388 
390 {
391  QDomNode parentNode = mCurrentElement.parentNode();
392  parentNode.removeChild(mCurrentElement);
393  mCurrentElement = QDomElement();// Create null element
394 }
395 
397 {
398  if (mFilename.isEmpty())
399  {
400  reportWarning("XmlOptionFile::save() No file name");
401  return; //Don't do anything if on filename isn't supplied
402  }
403 
404  QString path = QFileInfo(mFilename).absolutePath();
405  QDir().mkpath(path);
406  QFile file(mFilename);
407  if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
408  {
409  QTextStream stream(&file);
410  stream << mDocument.toString(4);
411  file.close();
412 // report("Created " + file.fileName());
413  }
414  else
415  {
416  reportError("XmlOptionFile::save() Could not open " + file.fileName() + " Error: "
417  + file.errorString());
418  }
419 }
420 
421 
422 } // namespace cx
void reportError(QString msg)
Definition: cxLogger.cpp:71
void writeVariant(const QVariant &val)
QDomElement getElement()
return the current element
QDomDocument loadDocument(const QString &filename)
void printDocument()
print the entire document
void reportWarning(QString msg)
Definition: cxLogger.cpp:70
static XmlOptionFile createNull()
create an empty document
QDomElement safeGetElement(QDomElement parent, QString childName)
XmlOptionFile ascend() const
step one level up in the xml tree
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:21
void printElement()
print just the current element
static SharedDocuments * getInstance()
void writeValue(const QString &val)
QDomDocument getDocument()
returns the document
void deleteNode()
Delete the current node.
void removeChildren()
remove all child nodes of the current element.
void save()
save entire document.
QVariant readVariant(const QVariant &defval=QVariant()) const
bool isNull() const
checks if this is null
XmlOptionFile root() const
set the current element to root
XmlOptionFile tryDescend(QString element, QString attributeName, QString attributeValue) const
Helper class for xml files used to store ssc/cx data.
QString readValue(const QString &defval) const
XmlOptionFile descend(QString element) const
step one level down in the xml tree
Namespace for all CustusX production code.