CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 <QStringList>
50 #include <QMutex>
51 #include <QBuffer>
52 #include "cxLogger.h"
53 #include "cxTypeConversions.h"
54 
55 namespace cx
56 {
57 
62 {
63 public:
65  {
66  if (!mInstance)
67  mInstance = new SharedDocuments();
68  return mInstance;
69  }
70 
74  QDomDocument loadDocument(const QString& filename)
75  {
76  QDomDocument retval;
77  retval = this->getDocument(filename);
78  if (retval.isNull())
79  {
80  retval = this->readFromFile(filename);
81  this->addDocument(filename, retval);
82  }
83  return retval;
84  }
85 
86 private:
87  SharedDocuments() : mDocumentMutex(QMutex::Recursive) {}
88 
89  QDomDocument getDocument(const QString& filename)
90  {
91  QMutexLocker lock(&mDocumentMutex);
92  DocumentMap::iterator iter = mDocuments.find(filename);
93  // if filename found, attempt to retrieve document from node.
94  if (iter != mDocuments.end())
95  {
96  return iter->second.ownerDocument();
97  }
98  return QDomDocument(); // null node
99  }
100 
101  void addDocument(const QString& filename, QDomDocument document)
102  {
103  QMutexLocker lock(&mDocumentMutex);
104  mDocuments[filename] = document.documentElement();
105  }
106 
107  QDomDocument readFromFile(QString filename)
108  {
109  QFile file(filename);
110  if (!file.open(QIODevice::ReadOnly))
111  {
112  QDomDocument doc;
113  doc.appendChild(doc.createElement("root"));
114  return doc;
115  }
116 
117  QDomDocument loadedDoc;
118  QString error;
119  int line, col;
120  if (!loadedDoc.setContent(&file, &error, &line, &col))
121  {
122  QString msg = QString("error setting xml content [%1,%2] %3").arg(line).arg(col).arg(error);
123  reportWarning(msg);
124  }
125  file.close();
126  return loadedDoc;
127  }
128 
129  static SharedDocuments* mInstance;
130  typedef std::map<QString, QDomElement> DocumentMap;
131  QMutex mDocumentMutex;
132  DocumentMap mDocuments;
133 };
135 SharedDocuments* SharedDocuments::mInstance = NULL;
137 
141 
142 QString XmlOptionItem::SerializeDataToB64String(const QVariant& data)
143 {
144  QByteArray byteArray;
145  QBuffer writeBuffer(&byteArray);
146  writeBuffer.open(QIODevice::WriteOnly);
147  QDataStream out(&writeBuffer);
148 
149  out << data;
150 
151  writeBuffer.close();
152 
153  QString s = QString(byteArray.toBase64());
154 
155 // qDebug() << "array size when written:" << byteArray.size();
156 
157  return s;
158 }
159 
160 
161 QVariant XmlOptionItem::DeserializeB64String(const QString& serializedVariant)
162 {
163  QByteArray readArr = QByteArray::fromBase64(serializedVariant.toUtf8());
164  QBuffer readBuffer(&readArr);
165  readBuffer.open(QIODevice::ReadOnly);
166  QDataStream in(&readBuffer);
167 
168  QVariant data;
169 
170  in >> data;
171 
172 // qDebug() << "array size when read:" << readArr.size();
173 
174  return data;
175 }
176 
177 XmlOptionItem::XmlOptionItem(const QString& uid, QDomElement root) :
178  mUid(uid), mRoot(root)
179 {
180 
181 }
182 
183 QVariant XmlOptionItem::readVariant(const QVariant& defval) const
184 {
185  QString text = this->readValue("");
186  if (text.isEmpty())
187  return defval;
188  QVariant val = DeserializeB64String(text);
189  return val;
190 }
191 
192 void XmlOptionItem::writeVariant(const QVariant& val)
193 {
194  QString text = SerializeDataToB64String(val);
195  this->writeValue(text);
196 }
197 
198 QString XmlOptionItem::readValue(const QString& defval) const
199 {
200  // read value is present
201  QDomElement item = this->findElemFromUid(mUid, mRoot);
202  if (!item.isNull() && item.hasAttribute("value"))
203  {
204  return item.attribute("value");
205  }
206  return defval;
207 }
208 
209 void XmlOptionItem::writeValue(const QString& val)
210 {
211  if (mRoot.isNull())
212  return;
213  QDomElement item = findElemFromUid(mUid, mRoot);
214  // create option if not present
215  if (item.isNull())
216  {
217  item = mRoot.ownerDocument().createElement("option");
218  item.setAttribute("id", mUid);
219  mRoot.appendChild(item);
220  }
221  item.setAttribute("value", val);
222 }
223 
224 QDomElement XmlOptionItem::findElemFromUid(const QString& uid, QDomNode root) const
225 {
226  QDomNodeList settings = root.childNodes();
227  for (int i = 0; i < settings.size(); ++i)
228  {
229  QDomElement item = settings.item(i).toElement();
230  if (item.attribute("id") == uid)
231  return item;
232  }
233  return QDomElement();
234 }
235 
239 
241 {
242  XmlOptionFile retval;
243  retval.mDocument = QDomDocument();
244  retval.mCurrentElement = QDomElement();
245  return retval;
246 }
247 
249 {
250  mDocument.appendChild(mDocument.createElement("root"));
251  mCurrentElement = mDocument.documentElement();
252 }
253 
254 XmlOptionFile::XmlOptionFile(QString filename) :
255  mFilename(filename)
256 {
257  mDocument = SharedDocuments::getInstance()->loadDocument(filename);
258 
259  mCurrentElement = mDocument.documentElement();
260 
261  if (mCurrentElement.isNull())
262  {
263  mDocument.appendChild(mDocument.createElement("root"));
264  mCurrentElement = mDocument.documentElement();
265  }
266 }
267 
269 {
270 }
271 
273 {
274  return mFilename;
275 }
276 
278 {
279  if(mCurrentElement.isNull() || mDocument.isNull())
280  return true;
281  return false;
282 }
283 
285 {
286  XmlOptionFile retval = *this;
287  retval.mCurrentElement = mDocument.documentElement();
288  return retval;
289 }
290 
291 XmlOptionFile XmlOptionFile::descend(QString element) const
292 {
293  XmlOptionFile retval = *this;
294  retval.mCurrentElement = retval.getElement(element);
295  return retval;
296 }
297 
298 XmlOptionFile XmlOptionFile::descend(QString element, QString attributeName, QString attributeValue) const
299 {
300  XmlOptionFile retval = this->tryDescend(element, attributeName, attributeValue);
301  if (!retval.getDocument().isNull())
302  return retval;
303 
304  // create a new element if not found
305  retval = *this;
306  QDomElement current = retval.getDocument().createElement(element);
307  current.setAttribute(attributeName, attributeValue);
308  retval.mCurrentElement.appendChild(current);
309  retval.mCurrentElement = current;
310  return retval;
311 }
312 
313 XmlOptionFile XmlOptionFile::tryDescend(QString element, QString attributeName, QString attributeValue) const
314 {
315  XmlOptionFile retval = *this;
316 
317  QDomNodeList presetNodeList = retval.getElement().elementsByTagName(element);
318  for (int i = 0; i < presetNodeList.count(); ++i)
319  {
320  QDomElement current = presetNodeList.item(i).toElement();
321  QString name = current.attribute(attributeName);
322  if (attributeValue == name)
323  {
324  retval.mCurrentElement = current;
325  return retval;
326  }
327  }
328 
329  return XmlOptionFile::createNull();
330 }
331 
333 {
334  XmlOptionFile retval = *this;
335  retval.mCurrentElement = mCurrentElement.parentNode().toElement();
336  if (retval.mCurrentElement.isNull())
337  return *this;
338  return retval;
339 }
340 
343 QDomElement XmlOptionFile::safeGetElement(QDomElement parent, QString childName)
344 {
345  QDomElement child = parent.namedItem(childName).toElement();
346 
347  if (child.isNull())
348  {
349  child = mDocument.createElement(childName);
350  parent.appendChild(child);
351  }
352 
353  return child;
354 }
355 
357 {
358  QTextStream stream(stdout);
359  stream << "\n" << mDocument.toString(4) << "\n";
360 }
361 
363 {
364  QTextStream stream(stdout);
365  stream << "\n";
366  mCurrentElement.save(stream, 4);
367  stream << "\n";
368 }
369 
371 {
372  return mDocument;
373 }
374 
376 {
377  return mCurrentElement;
378 }
379 
380 QDomElement XmlOptionFile::getElement(QString level1)
381 {
382  QDomElement elem1 = this->safeGetElement(mCurrentElement, level1);
383  return elem1;
384 }
385 
386 QDomElement XmlOptionFile::getElement(QString level1, QString level2)
387 {
388  QDomElement elem1 = this->safeGetElement(mCurrentElement, level1);
389  QDomElement elem2 = this->safeGetElement(elem1, level2);
390  return elem2;
391 }
392 
394 {
395  while (mCurrentElement.hasChildNodes())
396  mCurrentElement.removeChild(mCurrentElement.firstChild());
397 }
398 
400 {
401  QDomNode parentNode = mCurrentElement.parentNode();
402  parentNode.removeChild(mCurrentElement);
403  mCurrentElement = QDomElement();// Create null element
404 }
405 
407 {
408  if (mFilename.isEmpty())
409  {
410  reportWarning("XmlOptionFile::save() No file name");
411  return; //Don't do anything if on filename isn't supplied
412  }
413 
414  QString path = QFileInfo(mFilename).absolutePath();
415  QDir().mkpath(path);
416  QFile file(mFilename);
417  if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
418  {
419  QTextStream stream(&file);
420  stream << mDocument.toString(4);
421  file.close();
422 // report("Created " + file.fileName());
423  }
424  else
425  {
426  reportError("XmlOptionFile::save() Could not open " + file.fileName() + " Error: "
427  + file.errorString());
428  }
429 }
430 
431 
432 } // 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