Fraxinus  16.5.0-fx-rc1
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ProbeXmlConfigParserImpl.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 
34 
35 #include <iostream>
36 #include <QFile>
37 #include <QStringList>
38 #include <algorithm>
39 #include <qfileinfo.h>
40 
41 #include "cxTypeConversions.h"
42 #include "cxLogger.h"
43 
44 
46 {
47  if (!QFileInfo(pathToXml).exists())
48  {
49  cx::reportError(QString("Cannot find probe config file [%1]").arg(pathToXml));
50  }
51 
52  mFile = cx::XmlOptionFile(pathToXml);
53 }
54 
56 {}
57 
59 {
60  QStringList retval;
61  QList<QDomNode> scannerNodes = this->getScannerNodes();
62  QDomNode node;
63  foreach(node, scannerNodes)
64  {
65  retval << node.firstChildElement("Name").text();
66  }
67  return retval;
68 }
69 
71 {
72  return mFile.getFileName();
73 }
74 
75 QStringList ProbeXmlConfigParserImpl::getProbeList(QString scanner)
76 {
77  QStringList retval;
78  QList<QDomNode> probeNodes = this->getProbeNodes(scanner);
79  QDomNode node;
80  foreach(node, probeNodes)
81  {
82  retval << node.firstChildElement("Name").text();
83  }
84  return retval;
85 }
86 
87 QStringList ProbeXmlConfigParserImpl::getRtSourceList(QString scanner, QString probe)
88 {
89  QStringList retval;
90  QList<QDomNode> rtSourceNodes = this->getRTSourceNodes(scanner, probe);
91  QDomNode node;
92  foreach(node, rtSourceNodes)
93  {
94  retval << node.firstChildElement("Name").text();
95  }
96  return retval;
97 }
98 
99 QStringList ProbeXmlConfigParserImpl::getConfigIdList(QString scanner, QString probe, QString rtSource)
100 {
101  QStringList retval;
102  QList<QDomNode> configNodes = this->getConfigNodes(scanner, probe, rtSource);
103  QDomNode node;
104  foreach(node, configNodes)
105  {
106  retval << node.firstChildElement("ID").text();
107  }
108  return retval;
109 }
110 
111 namespace
112 {
113  QDomElement findElement(QDomNode parent, QString name)
114  {
115  QDomNode node = parent.namedItem(name);
116  QDomElement element = node.toElement();
117  if(element.isNull())
118  cx::reportWarning(QString("Cannot find node %2/%1").arg(name).arg(parent.toElement().tagName()));
119  return element;
120  }
121 
122 
126  template<class TYPE> bool readTextNode(TYPE* retval, QDomNode parent, QString name);
127 
128  template<>
129  bool readTextNode<QString>(QString* retval, QDomNode parent, QString name)
130  {
131  QDomElement element = parent.namedItem(name).toElement();
132  bool found = !element.isNull() && !element.text().isNull();
133  if(found)
134  *retval = element.text();
135  if (!found)
136  cx::reportWarning(QString("Cannot find node %2/%1").arg(name).arg(parent.toElement().tagName()));
137  return found;
138  }
139  template<>
140  bool readTextNode<int>(int* retval, QDomNode parent, QString name)
141  {
142  bool ok = false;
143  QDomElement element = parent.namedItem(name).toElement();
144  bool found = !element.isNull() && !element.text().isNull();
145  if(found)
146  *retval = element.text().toInt(&ok);
147  if (!found)
148  {
149  cx::reportWarning(QString("Cannot find node %2/%1").arg(name).arg(parent.toElement().tagName()));
150  }
151  else
152  {
153  found = found && ok;
154  if (!found)
155  cx::reportWarning(QString("Cannot convert node %2/%1 to int").arg(name).arg(parent.toElement().tagName()));
156  }
157  return found;
158  }
159  template<>
160  bool readTextNode<double>(double* retval, QDomNode parent, QString name)
161  {
162  bool ok = false;
163  QDomElement element = parent.namedItem(name).toElement();
164  bool found = !element.isNull() && !element.text().isNull();
165  if(found)
166  *retval = element.text().toDouble(&ok);
167  if (!found)
168  {
169  cx::reportWarning(QString("Cannot find node %2/%1").arg(name).arg(parent.toElement().tagName()));
170  }
171  else
172  {
173  found = found && ok;
174  if (!found)
175  cx::reportWarning(QString("Cannot convert node %2/%1 to double").arg(name).arg(parent.toElement().tagName()));
176  }
177  return found;
178  }
179 } // unnamed namespace
180 
181 ProbeXmlConfigParser::Configuration ProbeXmlConfigParserImpl::getConfiguration(QString scanner, QString probe, QString rtsource, QString configId)
182 {
183  Configuration retval;
184 // std::cout << QString("===getConfiguration %1, %2, %3, %4").arg(scanner).arg(probe).arg(rtsource).arg(configId) << std::endl;
185 
186  retval.mUsScanner = scanner;
187  retval.mUsProbe = probe;
188  retval.mRtSource = rtsource;
189  retval.mConfigId = configId;
190  retval.mNotes = "Found no notes.";
191 
192  QList<QDomNode> currentScannerNodeList = this->getScannerNodes(scanner);
193  if(currentScannerNodeList.isEmpty())
194  {
195  //cx::reportWarning(QString("No scanners found [%1]").arg(scanner));
196  return retval;
197  }
198  QDomNode scannerNode = currentScannerNodeList.first();
199 
200  QList<QDomNode> probeList = this->getProbeNodes(scanner, probe);
201  if(probeList.isEmpty())
202  {
203  cx::reportWarning(QString("No probes found [%1/%2]").arg(scanner, probe));
204  return retval;
205  }
206  QDomNode probeNode = probeList.first();
207 
208 // QDomElement element;
209 // readTextNode(&retval.mNotes, probeNode, "Notes");
210 // std::cout << "Notes : " << retval.mNotes << std::endl;
211 
212  QList<QDomNode> currentRtSourceNodeList = this->getRTSourceNodes(scanner, probe, rtsource);
213  if(currentRtSourceNodeList.isEmpty())
214  {
215  cx::reportWarning(QString("No rtsources found (Missing temporal calibration) [%1/%2/%3]").arg(scanner).arg(probe).arg(rtsource));
216  return retval;
217  }
218  QDomNode rtSourceNode = currentRtSourceNodeList.first();
219 
220  // read temporal calibration. Accept platform-specific overrides as well.
221  retval.mTemporalCalibration = 0;
222 
223  readTextNode(&retval.mTemporalCalibration, rtSourceNode, "TemporalCalibration");
224  QString tempCalPlatformName = "None";
225 // std::cout << "Base tc: " << retval.mTemporalCalibration << std::endl;
226 #ifdef WIN32
227  tempCalPlatformName = "TemporalCalibrationWindows";
228 #elif __APPLE__
229  tempCalPlatformName = "TemporalCalibrationApple";
230 #else
231  tempCalPlatformName = "TemporalCalibrationLinux";
232 #endif
233  QDomNode node = rtSourceNode.namedItem(tempCalPlatformName);
234  if(!node.isNull())
235  readTextNode(&retval.mTemporalCalibration, rtSourceNode, tempCalPlatformName);
236 
237 // std::cout << "Platform tc: " << retval.mTemporalCalibration << std::endl;
238 
239  if(rtsource.compare("Digital")!=0)//No more details are required for digital sources
240  {
241  QDomElement sizeNode = findElement(rtSourceNode, "ImageSize");
242  readTextNode(&retval.mImageWidth, sizeNode, "Width");
243  readTextNode(&retval.mImageHeight, sizeNode, "Height");
244  readTextNode(&retval.mHorizontalOffset, rtSourceNode, "HorizontalOffset");
245  }
246 
247  QList<QDomNode> currentConfigNodeList = this->getConfigNodes(scanner, probe, rtsource, configId);
248  if(currentConfigNodeList.isEmpty())
249  {
250  cx::reportWarning(QString("No nodes found in config [%1/%2/%3/%4]").arg(scanner).arg(probe).arg(rtsource).arg(configId));
251  return retval;
252  }
253  QDomNode configNode = currentConfigNodeList.first();
254 
255  readTextNode(&retval.mName, configNode, "Name");
256  if(rtsource.compare("Digital")!=0)//No more details are required for digital sources
257  {
258  readTextNode(&retval.mWidthDeg, configNode, "WidthDeg");
259  if (retval.mWidthDeg > 1.0E-6)
260  {
261  readTextNode(&retval.mDepth, configNode, "Depth");
262  readTextNode(&retval.mOffset, configNode, "Offset");
263  }
264  QDomElement originElement = findElement(configNode, "Origin");
265  readTextNode(&retval.mOriginCol, originElement, "Col");
266  readTextNode(&retval.mOriginRow, originElement, "Row");
267 
268  QDomElement edgesElement = findElement(configNode, "CroppingEdges");
269  readTextNode(&retval.mLeftEdge, edgesElement, "Left");
270  readTextNode(&retval.mRightEdge, edgesElement, "Right");
271  readTextNode(&retval.mTopEdge, edgesElement, "Top");
272  readTextNode(&retval.mBottomEdge, edgesElement, "Bottom");
273 
274  QDomElement pixelSizeElement = findElement(configNode, "PixelSize");
275  readTextNode(&retval.mPixelWidth, pixelSizeElement, "Width");
276  readTextNode(&retval.mPixelHeight, pixelSizeElement, "Height");
277  }
278 
279 // std::cout << "FERDIG" << std::endl;
280  retval.mEmpty = false;
281  return retval;
282 }
283 
284 QList<QDomNode> ProbeXmlConfigParserImpl::getScannerNodes(QString scanner)
285 {
286  QList<QDomNode> retval;
287  if(scanner == "ALL")
288  {
289  retval = this->nodeListToListOfNodes(mFile.getDocument().elementsByTagName("USScanner"));
290  }
291  else
292  {
293  QList<QDomNode> temp = this->nodeListToListOfNodes(mFile.getDocument().elementsByTagName("USScanner"));
294  QDomNode node;
295  foreach(node, temp)
296  {
297  if(node.firstChildElement("Name").text() == scanner)
298  retval.append(node);
299  }
300  }
301  return retval;
302 }
303 
304 QList<QDomNode> ProbeXmlConfigParserImpl::getProbeNodes(QString scanner, QString probe)
305 {
306  QList<QDomNode> retval;
307  if(probe == "ALL")
308  {
309  QList<QDomNode> temp = this->getScannerNodes(scanner);
310  QDomNode scannerNode;
311  foreach(scannerNode, temp)
312  {
313  retval.append(this->nodeListToListOfNodes(scannerNode.toElement().elementsByTagName("USProbe")));
314  }
315  }
316  else
317  {
318  QList<QDomNode> temp = this->getScannerNodes(scanner);
319  QDomNode scannerNode;
320  foreach(scannerNode, temp)
321  {
322  QList<QDomNode> temp2 = this->nodeListToListOfNodes(scannerNode.toElement().elementsByTagName("USProbe"));
323  QDomNode probeNode;
324  foreach(probeNode, temp2)
325  {
326  if(probeNode.firstChildElement("Name").text() == probe)
327  retval.append(probeNode);
328  }
329  }
330  }
331  return retval;
332 }
333 
334 QList<QDomNode> ProbeXmlConfigParserImpl::getRTSourceNodes(QString scanner, QString probe, QString rtSource)
335 {
336  QList<QDomNode> retval;
337  if(rtSource == "ALL")
338  {
339  QList<QDomNode> temp = this->getProbeNodes(scanner, probe);
340  QDomNode probeNode;
341  foreach(probeNode, temp)
342  {
343  retval.append(this->nodeListToListOfNodes(probeNode.toElement().elementsByTagName("RTSource")));
344  }
345  }
346  else
347  {
348  QList<QDomNode> temp = this->getProbeNodes(scanner, probe);
349  QDomNode probeNode;
350  foreach(probeNode, temp)
351  {
352  QList<QDomNode> temp2 = this->nodeListToListOfNodes(probeNode.toElement().elementsByTagName("RTSource"));
353  QDomNode rtSourceNode;
354  foreach(rtSourceNode, temp2)
355  {
356  if(rtSourceNode.firstChildElement("Name").text() == rtSource)
357  retval.append(rtSourceNode);
358  }
359  }
360  }
361  return retval;
362 }
363 
364 QList<QDomNode> ProbeXmlConfigParserImpl::getConfigNodes(QString scanner, QString probe, QString rtsource, QString config)
365 {
366  QList<QDomNode> retval;
367  if(config == "ALL")
368  {
369  QList<QDomNode> temp = this->getRTSourceNodes(scanner, probe, rtsource);
370  QDomNode rtSourceNode;
371  foreach(rtSourceNode, temp)
372  {
373  retval.append(this->nodeListToListOfNodes(rtSourceNode.toElement().elementsByTagName("Config")));
374  }
375  }
376  else
377  {
378  QList<QDomNode> temp = this->getRTSourceNodes(scanner, probe, rtsource);
379  QDomNode rtSourceNode;
380  foreach(rtSourceNode, temp)
381  {
382  QList<QDomNode> temp2 = this->nodeListToListOfNodes(rtSourceNode.toElement().elementsByTagName("Config"));
383  QDomNode configNode;
384  foreach(configNode, temp2)
385  {
386  if(configNode.firstChildElement("ID").text() == config)
387  retval.append(configNode);
388  }
389  }
390  }
391  return retval;
392 }
393 
394 QList<QDomNode> ProbeXmlConfigParserImpl::nodeListToListOfNodes(QDomNodeList list)
395 {
396  QList<QDomNode> retval;
397  for(int i=0; i < list.count(); ++i)
398  {
399  retval.append(list.item(i));
400  }
401  return retval;
402 }
403 
404 void ProbeXmlConfigParserImpl::removeConfig(QString scanner, QString probe, QString rtsource, QString configId)
405 {
406  QList<QDomNode> configNodes = this->getConfigNodes(scanner, probe, rtsource, configId);
407  if (configNodes.empty())
408  {
410  QString("Failed to remove probe config: No such path %1/%2/%3/%4")
411  .arg(scanner)
412  .arg(probe)
413  .arg(rtsource)
414  .arg(configId));
415  return;
416  }
417  QDomNode victim = configNodes.first();
418 
419  QDomNode parentNode = victim.parentNode();
420  parentNode.removeChild(victim);
421  victim = QDomElement();// Create null element (redundant?)
422 
423  mFile.save();
424 }
425 
430 void ProbeXmlConfigParserImpl::addTextElement(QDomElement parent, QString element, QString text)
431 {
432  QDomElement node = mFile.safeGetElement(parent, element);
433 
434  while (node.hasChildNodes())
435  node.removeChild(node.firstChild());
436 
437  node.appendChild(mFile.getDocument().createTextNode(text));
438  mFile.save();
439 }
440 
442 {
443  QList<QDomNode> rtNodes = this->getRTSourceNodes(config.mUsScanner, config.mUsProbe, config.mRtSource);
444  if (rtNodes.empty())
445  {
446  cx::reportWarning(QString("Failed to save probe config: No such path %1/%2/%3").arg(config.mUsScanner).arg(config.mUsProbe).arg(config.mRtSource));
447  return;
448  }
449  QDomElement rtSourceNode = rtNodes.first().toElement();
450  if (rtSourceNode.isNull())
451  return;
452 
453  QList<QDomNode> configNodes = this->getConfigNodes(config.mUsScanner, config.mUsProbe, config.mRtSource, config.mConfigId);
454  QDomElement configNode;
455  if (!configNodes.empty())
456  {
457  configNode = configNodes.first().toElement();
458  }
459  else
460  {
461  configNode = mFile.getDocument().createElement("Config");
462  rtSourceNode.appendChild(configNode);
463  }
464 
465  this->addTextElement(configNode, "ID", config.mConfigId);
466  this->addTextElement(configNode, "Name", config.mName);
467 
468  this->addTextElement(configNode, "WidthDeg", qstring_cast(config.mWidthDeg));
469  if (config.mWidthDeg>0)
470  {
471  this->addTextElement(configNode, "Depth", qstring_cast(config.mDepth));
472  this->addTextElement(configNode, "Offset", qstring_cast(config.mOffset));
473  }
474 
475  QDomElement originNode = mFile.safeGetElement(configNode, "Origin");
476  this->addTextElement(originNode, "Col", qstring_cast(config.mOriginCol));
477  this->addTextElement(originNode, "Row", qstring_cast(config.mOriginRow));
478 
479  QDomElement edgesNode = mFile.safeGetElement(configNode, "CroppingEdges");
480  this->addTextElement(edgesNode, "Left", qstring_cast(config.mLeftEdge));
481  this->addTextElement(edgesNode, "Right", qstring_cast(config.mRightEdge));
482  this->addTextElement(edgesNode, "Top", qstring_cast(config.mTopEdge));
483  this->addTextElement(edgesNode, "Bottom", qstring_cast(config.mBottomEdge));
484 
485  QDomElement pixelSizeNode = mFile.safeGetElement(configNode, "PixelSize");
486  this->addTextElement(pixelSizeNode, "Width", qstring_cast(config.mPixelWidth));
487  this->addTextElement(pixelSizeNode, "Height", qstring_cast(config.mPixelHeight));
488 
489  mFile.save();
490 }
QString qstring_cast(const T &val)
< a easy-to-work-with struct for a specific xml configuration
QList< QDomNode > getConfigNodes(QString scanner, QString probe, QString rtsource, QString config="ALL")
get a list of ALL confignodes for that scanner/probe/rtsource combo, or just the one you are looking ...
void reportError(QString msg)
Definition: cxLogger.cpp:92
virtual QStringList getConfigIdList(QString scanner, QString probe, QString rtSource)
get a list of config ids for that scanner/probe/rsource combo
QList< QDomNode > nodeListToListOfNodes(QDomNodeList list)
converts a QDomNodeList to a QList<QDomNode>
void addTextElement(QDomElement parent, QString element, QString text)
ProbeXmlConfigParserImpl(QString &pathToXml)
opens the file and reads it onto the QDomDocument
virtual QStringList getProbeList(QString scanner)
get a list of all probes for that scanner
virtual void saveCurrentConfig(Configuration config)
int mHorizontalOffset
parameter for the grabber
virtual void removeConfig(QString scanner, QString probe, QString rtsource, QString configId)
QList< QDomNode > getRTSourceNodes(QString scanner, QString probe, QString rtSource="ALL")
get a list of ALL rtsourcenodes for that scanner/probe combo, or just the one you are looking for ...
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
QDomElement safeGetElement(QDomElement parent, QString childName)
QList< QDomNode > getScannerNodes(QString scanner="ALL")
get a list of ALL scanner nodes or just the one you are looking for
int mImageWidth
Width of the used image format (x dim)
QDomDocument getDocument()
returns the document
virtual QStringList getRtSourceList(QString scanner, QString probe)
get a list of rt sources for that scanner/probe combo
int mImageHeight
Height of the used image format (y dim)
double mTemporalCalibration
delay in timestamping in grabber source relative to master clock.
QString mName
Name of config set.
virtual QStringList getScannerList()
get a list of all scanner in the xml
void save()
save entire document.
virtual Configuration getConfiguration(QString scanner, QString probe, QString rtsource, QString configId)
get a easy-to-work-with struct of a specific config
QList< QDomNode > getProbeNodes(QString scanner, QString probe="ALL")
get a list of ALL probenodes for that scanner, or just the one you are looking for ...
Helper class for xml files used to store ssc/cx data.