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