Fraxinus  17.12-rc4
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) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 
34 /*
35  * sscXmlOptionItem.cpp
36  *
37  * Created on: May 28, 2010
38  * Author: christiana
39  */
40 #include "cxXmlOptionItem.h"
41 
42 #include <map>
43 #include <iostream>
44 #include <QFile>
45 #include <QDir>
46 #include <QFileInfo>
47 #include <QTextStream>
48 #include <QDomElement>
49 #include <QDataStream>
50 #include <QStringList>
51 #include <QMutex>
52 #include <QBuffer>
53 #include "cxLogger.h"
54 #include "cxTypeConversions.h"
55 
56 namespace cx
57 {
58 
63 {
64 public:
66  {
67  if (!mInstance)
68  mInstance = new SharedDocuments();
69  return mInstance;
70  }
71 
75  QDomDocument loadDocument(const QString& filename)
76  {
77  QDomDocument retval;
78  retval = this->getDocument(filename);
79  if (retval.isNull())
80  {
81  retval = this->readFromFile(filename);
82  this->addDocument(filename, retval);
83  }
84  return retval;
85  }
86 
87 private:
88  SharedDocuments() : mDocumentMutex(QMutex::Recursive) {}
89 
90  QDomDocument getDocument(const QString& filename)
91  {
92  QMutexLocker lock(&mDocumentMutex);
93  DocumentMap::iterator iter = mDocuments.find(filename);
94  // if filename found, attempt to retrieve document from node.
95  if (iter != mDocuments.end())
96  {
97  return iter->second.ownerDocument();
98  }
99  return QDomDocument(); // null node
100  }
101 
102  void addDocument(const QString& filename, QDomDocument document)
103  {
104  QMutexLocker lock(&mDocumentMutex);
105  mDocuments[filename] = document.documentElement();
106  }
107 
108  QDomDocument readFromFile(QString filename)
109  {
110  QFile file(filename);
111  if (!file.open(QIODevice::ReadOnly))
112  {
113  QDomDocument doc;
114  doc.appendChild(doc.createElement("root"));
115  return doc;
116  }
117 
118  QDomDocument loadedDoc;
119  QString error;
120  int line, col;
121  if (!loadedDoc.setContent(&file, &error, &line, &col))
122  {
123  QString msg = QString("error setting xml content [%1,%2] %3").arg(line).arg(col).arg(error);
124  reportWarning(msg);
125  }
126  file.close();
127  return loadedDoc;
128  }
129 
130  static SharedDocuments* mInstance;
131  typedef std::map<QString, QDomElement> DocumentMap;
132  QMutex mDocumentMutex;
133  DocumentMap mDocuments;
134 };
136 SharedDocuments* SharedDocuments::mInstance = NULL;
138 
142 
143 QString XmlOptionItem::SerializeDataToB64String(const QVariant& data)
144 {
145  QByteArray byteArray;
146  QBuffer writeBuffer(&byteArray);
147  writeBuffer.open(QIODevice::WriteOnly);
148  QDataStream out(&writeBuffer);
149 
150  out << data;
151 
152  writeBuffer.close();
153 
154  QString s = QString(byteArray.toBase64());
155 
156 // qDebug() << "array size when written:" << byteArray.size();
157 
158  return s;
159 }
160 
161 
162 QVariant XmlOptionItem::DeserializeB64String(const QString& serializedVariant)
163 {
164  QByteArray readArr = QByteArray::fromBase64(serializedVariant.toUtf8());
165  QBuffer readBuffer(&readArr);
166  readBuffer.open(QIODevice::ReadOnly);
167  QDataStream in(&readBuffer);
168 
169  QVariant data;
170 
171  in >> data;
172 
173 // qDebug() << "array size when read:" << readArr.size();
174 
175  return data;
176 }
177 
178 XmlOptionItem::XmlOptionItem(const QString& uid, QDomElement root) :
179  mUid(uid), mRoot(root)
180 {
181 
182 }
183 
184 QVariant XmlOptionItem::readVariant(const QVariant& defval) const
185 {
186  QString text = this->readValue("");
187  if (text.isEmpty())
188  return defval;
189  QVariant val = DeserializeB64String(text);
190  return val;
191 }
192 
193 void XmlOptionItem::writeVariant(const QVariant& val)
194 {
195  QString text = SerializeDataToB64String(val);
196  this->writeValue(text);
197 }
198 
199 QString XmlOptionItem::readValue(const QString& defval) const
200 {
201  // read value is present
202  QDomElement item = this->findElemFromUid(mUid, mRoot);
203  if (!item.isNull() && item.hasAttribute("value"))
204  {
205  return item.attribute("value");
206  }
207  return defval;
208 }
209 
210 void XmlOptionItem::writeValue(const QString& val)
211 {
212  if (mRoot.isNull())
213  return;
214  QDomElement item = findElemFromUid(mUid, mRoot);
215  // create option if not present
216  if (item.isNull())
217  {
218  item = mRoot.ownerDocument().createElement("option");
219  item.setAttribute("id", mUid);
220  mRoot.appendChild(item);
221  }
222  item.setAttribute("value", val);
223 }
224 
225 QDomElement XmlOptionItem::findElemFromUid(const QString& uid, QDomNode root) const
226 {
227  QDomNodeList settings = root.childNodes();
228  for (int i = 0; i < settings.size(); ++i)
229  {
230  QDomElement item = settings.item(i).toElement();
231  if (item.attribute("id") == uid)
232  return item;
233  }
234  return QDomElement();
235 }
236 
240 
242 {
243  XmlOptionFile retval;
244  retval.mDocument = QDomDocument();
245  retval.mCurrentElement = QDomElement();
246  return retval;
247 }
248 
250 {
251  mDocument.appendChild(mDocument.createElement("root"));
252  mCurrentElement = mDocument.documentElement();
253 }
254 
255 XmlOptionFile::XmlOptionFile(QString filename) :
256  mFilename(filename)
257 {
258  mDocument = SharedDocuments::getInstance()->loadDocument(filename);
259 
260  mCurrentElement = mDocument.documentElement();
261 
262  if (mCurrentElement.isNull())
263  {
264  mDocument.appendChild(mDocument.createElement("root"));
265  mCurrentElement = mDocument.documentElement();
266  }
267 }
268 
270 {
271 }
272 
274 {
275  return mFilename;
276 }
277 
279 {
280  if(mCurrentElement.isNull() || mDocument.isNull())
281  return true;
282  return false;
283 }
284 
286 {
287  XmlOptionFile retval = *this;
288  retval.mCurrentElement = mDocument.documentElement();
289  return retval;
290 }
291 
292 XmlOptionFile XmlOptionFile::descend(QString element) const
293 {
294  XmlOptionFile retval = *this;
295  retval.mCurrentElement = retval.getElement(element);
296  return retval;
297 }
298 
299 XmlOptionFile XmlOptionFile::descend(QString element, QString attributeName, QString attributeValue) const
300 {
301  XmlOptionFile retval = this->tryDescend(element, attributeName, attributeValue);
302  if (!retval.getDocument().isNull())
303  return retval;
304 
305  // create a new element if not found
306  retval = *this;
307  QDomElement current = retval.getDocument().createElement(element);
308  current.setAttribute(attributeName, attributeValue);
309  retval.mCurrentElement.appendChild(current);
310  retval.mCurrentElement = current;
311  return retval;
312 }
313 
314 XmlOptionFile XmlOptionFile::tryDescend(QString element, QString attributeName, QString attributeValue) const
315 {
316  XmlOptionFile retval = *this;
317 
318  QDomNodeList presetNodeList = retval.getElement().elementsByTagName(element);
319  for (int i = 0; i < presetNodeList.count(); ++i)
320  {
321  QDomElement current = presetNodeList.item(i).toElement();
322  QString name = current.attribute(attributeName);
323  if (attributeValue == name)
324  {
325  retval.mCurrentElement = current;
326  return retval;
327  }
328  }
329 
330  return XmlOptionFile::createNull();
331 }
332 
334 {
335  XmlOptionFile retval = *this;
336  retval.mCurrentElement = mCurrentElement.parentNode().toElement();
337  if (retval.mCurrentElement.isNull())
338  return *this;
339  return retval;
340 }
341 
344 QDomElement XmlOptionFile::safeGetElement(QDomElement parent, QString childName)
345 {
346  QDomElement child = parent.namedItem(childName).toElement();
347 
348  if (child.isNull())
349  {
350  child = mDocument.createElement(childName);
351  parent.appendChild(child);
352  }
353 
354  return child;
355 }
356 
358 {
359  printDocument(mDocument);
360 }
361 
363 {
364  printElement(mCurrentElement);
365 }
366 
367 void XmlOptionFile::printDocument(QDomDocument document)
368 {
369  QTextStream stream(stdout);
370  stream << "\nTEST" << document.toString(4) << "\n";
371 }
372 
373 void XmlOptionFile::printElement(QDomElement element)
374 {
375  QTextStream stream(stdout);
376  stream << "\n";
377  element.save(stream, 4);
378  stream << "\n";
379 }
380 
382 {
383  return mDocument;
384 }
385 
387 {
388  return mCurrentElement;
389 }
390 
391 QDomElement XmlOptionFile::getElement(QString level1)
392 {
393  QDomElement elem1 = this->safeGetElement(mCurrentElement, level1);
394  return elem1;
395 }
396 
397 QDomElement XmlOptionFile::getElement(QString level1, QString level2)
398 {
399  QDomElement elem1 = this->safeGetElement(mCurrentElement, level1);
400  QDomElement elem2 = this->safeGetElement(elem1, level2);
401  return elem2;
402 }
403 
405 {
406  while (mCurrentElement.hasChildNodes())
407  mCurrentElement.removeChild(mCurrentElement.firstChild());
408 }
409 
411 {
412  QDomNode parentNode = mCurrentElement.parentNode();
413  parentNode.removeChild(mCurrentElement);
414  mCurrentElement = QDomElement();// Create null element
415 }
416 
418 {
419  if (mFilename.isEmpty())
420  {
421  reportWarning("XmlOptionFile::save() No file name");
422  return; //Don't do anything if on filename isn't supplied
423  }
424 
425  QString path = QFileInfo(mFilename).absolutePath();
426  QDir().mkpath(path);
427  QFile file(mFilename);
428  if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
429  {
430  QTextStream stream(&file);
431  stream << mDocument.toString(4);
432  file.close();
433 // report("Created " + file.fileName());
434  }
435  else
436  {
437  reportError("XmlOptionFile::save() Could not open " + file.fileName() + " Error: "
438  + file.errorString());
439  }
440 }
441 
442 
443 } // namespace cx
void reportError(QString msg)
Definition: cxLogger.cpp:92
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:91
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:42
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.