Fraxinus  18.10
An IGT application
cxToolConfigurationParser.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 <QFile>
15 #include <QDir>
16 #include <QFileInfo>
17 #include <QTextStream>
18 #include "cxLogger.h"
19 #include "cxTypeConversions.h"
20 #include "cxEnumConverter.h"
21 #include "cxDataLocations.h"
22 #include "cxProfile.h"
23 #include "cxFrame3D.h"
24 #include "cxTransformFile.h"
25 
26 namespace cx
27 {
28 
29 // names of necessary tags in the configuration file
30 #define CONFIG_TAG "configuration"
31 #define CONFIG_TRACKER_TAG "tracker"
32 #define CONFIG_TRACKER_TOOL_FILE "toolfile"
33 #define CONFIG_TRACKINGSYSTEMIMPLEMENTATION_TAG "trackingsystemimplementation"
34 
35 // names of necessary attributes in the configuration file
36 #define TYPE_ATTRIBUTE "type"
37 #define CLINICAL_APP_ATTRIBUTE "clinical_app"
38 #define REFERENCE_ATTRIBUTE "reference"
39 #define OPENIGTLINK_TRANSFORM_ID_ATTRIBUTE "openigtlinktransformid"
40 #define OPENIGTLINK_IMAGE_ID_ATTRIBUTE "openigtlinkimageid"
41 
42 ConfigurationFileParser::ConfigurationFileParser(QString absoluteConfigFilePath, QString loggingFolder) :
43  mConfigurationFilePath(absoluteConfigFilePath), mLoggingFolder(loggingFolder)
44 {
45  this->setConfigDocument(mConfigurationFilePath);
46 }
47 
49 {
50 }
51 
53 {
54  if (!this->isConfigFileValid())
55  return "";
56 
57  QDomNode configNode = mConfigureDoc.elementsByTagName(CONFIG_TAG).at(0);
58  QString retval = configNode.toElement().attribute(CLINICAL_APP_ATTRIBUTE);
59  return retval;
60 }
61 
63 {
64  QString retval;
65 
66  QDomNodeList trackingsystemImplementationNodes = mConfigureDoc.elementsByTagName(CONFIG_TRACKINGSYSTEMIMPLEMENTATION_TAG);
67  for (int i = 0; i < trackingsystemImplementationNodes.count(); ++i)
68  {
69  retval = trackingsystemImplementationNodes.at(i).toElement().attribute(TYPE_ATTRIBUTE);
70  }
71 
72  if (trackingsystemImplementationNodes.count() == 0)
73  {
74  retval = TRACKING_SYSTEM_IMPLEMENTATION_IGSTK;//Revert to igstk implementation for old config files
75  }
76  else if(trackingsystemImplementationNodes.count() > 1)
77  {
78  CX_LOG_ERROR() << "ConfigurationFileParser::getTrackingSystemImplementation(): Config file: " << mConfigurationFilePath
79  << " has more the one tracking system implementation. Only one is currently supported.";
80  }
81 
82  return retval;
83 }
84 
85 std::vector<ToolFileParser::TrackerInternalStructure> ConfigurationFileParser::getTrackers()
86 {
87  std::vector<ToolFileParser::TrackerInternalStructure> retval;
88 
89  if (!this->isConfigFileValid())
90  return retval;
91 
92  QDomNodeList trackerNodes = mConfigureDoc.elementsByTagName(CONFIG_TRACKER_TAG);
93  for (int i = 0; i < trackerNodes.count(); ++i)
94  {
96  QString trackerType = trackerNodes.at(i).toElement().attribute(TYPE_ATTRIBUTE);
97  internalStructure.mType = string2enum<TRACKING_SYSTEM>(trackerType);
98  internalStructure.mLoggingFolderName = mLoggingFolder;
99 
100  retval.push_back(internalStructure);
101  }
102 
103  if (retval.size() > 1)
104  reportError(
105  "Config file " + mConfigurationFilePath
106  + " has a invalid number of tracking systems, we only support 1 tracking system atm!");
107 
108  return retval;
109 }
110 
112 {
113  std::vector<QString> retval;
114 
115  if (!this->isConfigFileValid())
116  return retval;
117 
118  QDomNodeList toolFileNodes = mConfigureDoc.elementsByTagName(CONFIG_TRACKER_TOOL_FILE);
119  for (int i = 0; i < toolFileNodes.count(); ++i)
120  {
121  QString absoluteToolFilePath = this->getAbsoluteToolFilePath(toolFileNodes.at(i).toElement());
122  if (absoluteToolFilePath.isEmpty())
123  continue;
124 
125  retval.push_back(absoluteToolFilePath);
126  }
127 
128  return retval;
129 }
130 
132 {
133  QString retval;
134 
135  if (!this->isConfigFileValid())
136  return retval;
137 
138 // QFile configFile(mConfigurationFilePath);
139 // QString configFolderAbsolutePath = QFileInfo(configFile).dir().absolutePath()+"/";
140 // std::cout << "configFolderAbsolutePath " << configFolderAbsolutePath << std::endl;
141 
142  QDomNodeList toolFileNodes = mConfigureDoc.elementsByTagName(CONFIG_TRACKER_TOOL_FILE);
143  for (int i = 0; i < toolFileNodes.count(); ++i)
144  {
145  QString reference = toolFileNodes.at(i).toElement().attribute(REFERENCE_ATTRIBUTE);
146  if (reference.contains("yes", Qt::CaseInsensitive))
147  {
148 // std::cout << "Found yes..." << std::endl;
149  retval = this->getAbsoluteToolFilePath(toolFileNodes.at(i).toElement());
150  }
151  }
152  return retval;
153 }
154 
155 std::vector<ConfigurationFileParser::ToolStructure> ConfigurationFileParser::getToolListWithMetaInformation()
156 {
157  std::vector<ToolStructure> retval;
158 
159  if (!this->isConfigFileValid())
160  return retval;
161 
162  QDomNodeList toolFileNodes = mConfigureDoc.elementsByTagName(CONFIG_TRACKER_TOOL_FILE);
163  for (int i = 0; i < toolFileNodes.count(); ++i)
164  {
165  ToolStructure toolStructure;
166  toolStructure.mAbsoluteToolFilePath = this->getAbsoluteToolFilePath(toolFileNodes.at(i).toElement());
167  toolStructure.mOpenIGTLinkTransformId = toolFileNodes.at(i).toElement().attribute(OPENIGTLINK_TRANSFORM_ID_ATTRIBUTE);
168  toolStructure.mOpenIGTLinkImageId = toolFileNodes.at(i).toElement().attribute(OPENIGTLINK_IMAGE_ID_ATTRIBUTE);
169 
170  QString reference = toolFileNodes.at(i).toElement().attribute(REFERENCE_ATTRIBUTE);
171  if (reference.contains("yes", Qt::CaseInsensitive))
172  toolStructure.mReference = true;
173  else
174  toolStructure.mReference = false;
175  retval.push_back(toolStructure);
176  }
177  return retval;
178 }
179 
181 {
182  QString retval = DataLocations::getRootConfigPath() + "/tool/TEMPLATE_configuration.xml";
183  return retval;
184 }
185 
186 QString ConfigurationFileParser::convertToRelativeToolFilePath(QString configFilename, QString absoluteToolFilePath)
187 {
188  foreach (QString root, profile()->getAllRootConfigPaths())
189  {
190  QString configPath = getToolPathFromRoot(root);
191  if (!absoluteToolFilePath.contains(configPath))
192  continue;
193  absoluteToolFilePath.replace(configPath, "");
194  if (absoluteToolFilePath.startsWith("/"))
195  absoluteToolFilePath.remove(0, 1);
196  return absoluteToolFilePath;
197  }
198 
199  // file not in any of the standard locations: return absolute
200  return absoluteToolFilePath;
201 }
202 
203 QString ConfigurationFileParser::getToolPathFromRoot(QString root)
204 {
205  return root + "/tool/Tools/";
206 }
207 
209 {
210  bool doSaveFile = true;
211  QDomDocument doc;
212  doc.appendChild(doc.createProcessingInstruction("xml version =", "\"1.0\""));
213 
214  QDomElement configNode = doc.createElement(CONFIG_TAG);
215  configNode.setAttribute(CLINICAL_APP_ATTRIBUTE, config.mClinical_app);
216 
217  QDomElement trackingsystemImplementationNode = doc.createElement(CONFIG_TRACKINGSYSTEMIMPLEMENTATION_TAG);
218  trackingsystemImplementationNode.setAttribute(TYPE_ATTRIBUTE, config.mTrackingSystemImplementation);
219 
220  configNode.appendChild(trackingsystemImplementationNode);
221 
222  TrackersAndToolsMap::iterator it1 = config.mTrackersAndTools.begin();
223  for (; it1 != config.mTrackersAndTools.end(); ++it1)
224  {
225  QString trackingSystemName = enum2string(it1->first);
226  if(trackingSystemName.isEmpty())
227  {
228  CX_LOG_WARNING() << "trackingSystemName is empty.";
229  trackingSystemName="";
230  }
231  QDomElement trackerTagNode = doc.createElement(CONFIG_TRACKER_TAG);
232  trackerTagNode.setAttribute(TYPE_ATTRIBUTE, trackingSystemName);
233 
234  ToolStructureVector::iterator it2 = it1->second.begin();
235  for (; it2 != it1->second.end(); ++it2)
236  {
237  QString absoluteToolFilePath = it2->mAbsoluteToolFilePath;
238  QString relativeToolFilePath = convertToRelativeToolFilePath(config.mFileName, absoluteToolFilePath);
239 
240  ToolFileParser toolparser(absoluteToolFilePath);
241  QString toolTrackerType = enum2string(toolparser.getTool()->mTrackerType);
242 
243  if (config.mTrackingSystemImplementation.contains(TRACKING_SYSTEM_IMPLEMENTATION_IGTLINK, Qt::CaseInsensitive))
244  {
245  doSaveFile = false;
246  }
247 
248  if (!trackingSystemName.contains(enum2string(toolparser.getTool()->mTrackerType), Qt::CaseInsensitive))
249  {
250  reportWarning("When saving configuration, skipping tool " + relativeToolFilePath + " of type "
251  + toolTrackerType + " because trackingSystemName is set to " + trackingSystemName);
252  continue;
253  }
254 
255  QDomElement toolFileNode = doc.createElement(CONFIG_TRACKER_TOOL_FILE);
256  toolFileNode.appendChild(doc.createTextNode(relativeToolFilePath));
257  toolFileNode.setAttribute(REFERENCE_ATTRIBUTE, (it2->mReference ? "yes" : "no"));
258  //These are not saved correctly yet. See comment in ToolConfigureGroupBox::getCurrentConfiguration()
259  toolFileNode.setAttribute(OPENIGTLINK_TRANSFORM_ID_ATTRIBUTE, it2->mOpenIGTLinkTransformId);// These are not saved correctly yet.
260  toolFileNode.setAttribute(OPENIGTLINK_IMAGE_ID_ATTRIBUTE, it2->mOpenIGTLinkImageId);// These are not saved correctly yet.
261  trackerTagNode.appendChild(toolFileNode);
262  }
263  trackingsystemImplementationNode.appendChild(trackerTagNode);
264  }
265 
266  doc.appendChild(configNode);
267 
268  //write to file
269  QFile file(config.mFileName);
270  if(doSaveFile)
271  {
272  QDir().mkpath(QFileInfo(config.mFileName).absolutePath());
273 
274  if (!file.open(QIODevice::WriteOnly))
275  {
276  reportWarning("Could not open file " + file.fileName() + ", aborting writing of config.");
277  return;
278  }
279 
280  QTextStream stream(&file);
281  doc.save(stream, 4);
282  reportSuccess("Configuration file " + file.fileName() + " is written.");
283  }
284  else
285  CX_LOG_INFO() << "Changing OpenIGTLink tool files not supported. Not overwriting config file: " << file.fileName();
286 }
287 
288 void ConfigurationFileParser::setConfigDocument(QString configAbsoluteFilePath)
289 {
290  QFile configFile(configAbsoluteFilePath);
291  if (!configFile.exists())
292  {
293 // reportDebug("Configfile "+configAbsoluteFilePath+" does not exist.");
294  return;
295  }
296 
297  QString errorMessage;
298  int errorInLine = 0;
299  if (!mConfigureDoc.setContent(&configFile, &errorMessage, &errorInLine))
300  {
301  reportError("Could not set the xml content of the config file " + configAbsoluteFilePath);
302  CX_LOG_ERROR() << "Qt error message: " << errorMessage << " in line: " << errorInLine;
303  return;
304  }
305 }
306 
307 bool ConfigurationFileParser::isConfigFileValid()
308 {
309  //there can only be one config defined in every config.xml-file, that's why we say ...item(0)
310  QDomNode configNode = mConfigureDoc.elementsByTagName(CONFIG_TAG).item(0);
311  if (configNode.isNull())
312  {
313  //reportDebug("Configuration file \""+mConfigurationFilePath+"\" does not contain the tag <"+mConfigTag+">.");
314  return false;
315  }
316  return true;
317 }
318 
319 QString ConfigurationFileParser::findXmlFileWithDirNameInPath(QString path)
320 {
321  QDir dir(path);
322  QStringList filter;
323  filter << dir.dirName() + ".xml";
324  QStringList filepaths = dir.entryList(filter);
325  if (!filepaths.isEmpty())
326  return dir.absoluteFilePath(filter[0]);
327  return "";
328 }
329 
330 QString ConfigurationFileParser::searchForExistingToolFilePath(QString relativeToolFilePath)
331 {
332  // remove old-style paths (<= v3.7.0)
333  relativeToolFilePath.replace("../Tools/", "");
334 
335  foreach (QString root, profile()->getAllRootConfigPaths())
336  {
337  QString configPath = this->getToolPathFromRoot(root);
338  QFileInfo guess(configPath + "/" + relativeToolFilePath);
339  if (guess.exists())
340  return guess.canonicalFilePath();
341  }
342  return "";
343 }
344 
345 QString ConfigurationFileParser::getAbsoluteToolFilePath(QDomElement toolfileelement)
346 {
347  QString relativeToolFilePath = toolfileelement.text();
348  if (relativeToolFilePath.isEmpty())
349  return "";
350 
351  QString absoluteToolFilePath = this->searchForExistingToolFilePath(relativeToolFilePath);
352 
353  QFileInfo info(absoluteToolFilePath);
354  if (!info.exists())
355  reportError(QString("Tool file %1 in configuration %2 not found. Skipping.")
356  .arg(relativeToolFilePath)
357  .arg(mConfigurationFilePath));
358 
359  if (info.isDir())
360  absoluteToolFilePath = this->findXmlFileWithDirNameInPath(absoluteToolFilePath);
361  return absoluteToolFilePath;
362 }
363 //----------------------------------------------------------------------------------------------------------------------
364 
365 
366 //----------------------------------------------------------------------------------------------------------------------
367 
368 }//namespace cx
TrackersAndToolsMap mTrackersAndTools
the trackers and tools (relative path) that should be used in the config
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:160
QString mLoggingFolderName
path to where log should be saved
#define REFERENCE_ATTRIBUTE
void reportError(QString msg)
Definition: cxLogger.cpp:71
TRACKING_SYSTEM mType
the trackers type
#define CX_LOG_INFO
Definition: cxLogger.h:96
QString mFileName
absolute path and filename for the new config file
ConfigurationFileParser(QString absoluteConfigFilePath, QString loggingFolder="")
static void saveConfiguration(Configuration &config)
#define CONFIG_TRACKINGSYSTEMIMPLEMENTATION_TAG
#define OPENIGTLINK_TRANSFORM_ID_ATTRIBUTE
#define TRACKING_SYSTEM_IMPLEMENTATION_IGSTK
Definition: cxDefinitions.h:25
#define TRACKING_SYSTEM_IMPLEMENTATION_IGTLINK
Definition: cxDefinitions.h:26
#define CONFIG_TAG
virtual ToolInternalStructurePtr getTool()
void reportWarning(QString msg)
Definition: cxLogger.cpp:70
#define TYPE_ATTRIBUTE
#define CX_LOG_ERROR
Definition: cxLogger.h:99
#define CONFIG_TRACKER_TOOL_FILE
void reportSuccess(QString msg)
Definition: cxLogger.cpp:72
static QString getRootConfigPath()
return path to root config folder. May be replaced with getExistingConfigPath()
std::vector< QString > getAbsoluteToolFilePaths()
#define CX_LOG_WARNING
Definition: cxLogger.h:98
QString mClinical_app
the clinical application this config is made for
std::vector< ToolFileParser::TrackerInternalStructure > getTrackers()
Class for reading the files defining a CustusX tool.
#define CLINICAL_APP_ATTRIBUTE
QString enum2string(const ENUM &val)
std::vector< ConfigurationFileParser::ToolStructure > getToolListWithMetaInformation()
#define CONFIG_TRACKER_TAG
#define OPENIGTLINK_IMAGE_ID_ATTRIBUTE
Namespace for all CustusX production code.