CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxSessionStorageServiceImpl.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 #include "cxSettings.h"
14 #include "cxReporter.h"
15 #include <QTextStream>
16 #include "cxTime.h"
17 #include <QDir>
18 #include "cxConfig.h"
19 #include "cxFileHelpers.h"
20 #include "cxDataLocations.h"
21 #include <QApplication>
22 #include <QTimer>
23 #include "cxLogger.h"
24 #include "cxProfile.h"
25 #include "cxOrderedQDomDocument.h"
26 #include "cxXmlFileHandler.h"
27 
28 
29 namespace cx
30 {
31 
33 {
34  this->clearCache();
35  mActivePatientFolder = this->getNoPatientFolder();
36  connect(this, &SessionStorageServiceImpl::sessionChanged, this, &SessionStorageServiceImpl::onSessionChanged);
37 
38  QTimer::singleShot(100, this, SLOT(startupLoadPatient())); // make sure this is called after application state change
39 }
40 
42 {
43  this->clearCache();
44 }
45 
47 {
48  return false;
49 }
50 
52 {
53  bool valid = this->isValidSessionFolder(dir);
54  bool exists = this->folderExists(dir);
55 
56  if (valid)
57  {
58  this->loadSession(dir);
59  }
60  else if (!exists)
61  {
62  this->initializeNewSession(dir);
63  }
64  else
65  {
66  reportError(QString("Failed to initialize session in existing folder with no valid session: %1").arg(dir));
67  }
68 }
69 
70 QString SessionStorageServiceImpl::getNoPatientFolder() const
71 {
72  return DataLocations::getCachePath() + "/NoPatient";
73 }
74 
75 
76 bool SessionStorageServiceImpl::isValidSessionFolder(QString dir) const
77 {
78  QString filename = QDir(dir).absoluteFilePath(this->getXmlFileName());
79  return QFileInfo::exists(filename);
80 }
81 
82 bool SessionStorageServiceImpl::folderExists(QString dir) const
83 {
84  return QFileInfo(dir).exists() && QFileInfo(dir).isDir();
85 }
86 
87 void SessionStorageServiceImpl::loadSession(QString dir)
88 {
89  if (this->isActivePatient(dir))
90  return;
91  this->loadPatientSilent(dir);
92  this->reportActivePatient();
93  this->writeRecentPatientData();
94 }
95 
96 void SessionStorageServiceImpl::initializeNewSession(QString dir)
97 {
98  this->clearPatientSilent();
99  dir = this->convertToValidFolderName(dir);
100  this->createPatientFolders(dir);
101  this->setActivePatient(dir);
102  this->save();
103  this->reportActivePatient();
104  this->writeRecentPatientData();
105 }
106 
107 QString SessionStorageServiceImpl::getXmlFileName() const
108 {
109  return "custusdoc.xml";
110 }
111 
113 {
114  if (!this->isValid())
115  return;
116 
117  //Gather all the information that needs to be saved
119  this->generateSaveDoc(doc.doc());
120 
121  QDomElement element = doc.doc().documentElement();
122  emit isSaving(element); // give all listeners a chance to add to the document
123 
124  QString filename = QDir(mActivePatientFolder).absoluteFilePath(this->getXmlFileName());
125  XmlFileHandler::writeXmlFile(doc.doc(), filename);
126  report("Saved patient " + mActivePatientFolder);
127 }
128 
130 {
131  this->clearPatientSilent();
132  this->reportActivePatient();
133  this->writeRecentPatientData();
134 }
135 
137 {
138  return !mActivePatientFolder.isEmpty() &&
139  (mActivePatientFolder != this->getNoPatientFolder());
140 }
141 
143 {
144  return mActivePatientFolder;
145 }
146 
147 void SessionStorageServiceImpl::reportActivePatient()
148 {
149  report("Set Active Patient: " + mActivePatientFolder);
150 }
151 
152 void SessionStorageServiceImpl::setActivePatient(const QString& activePatientFolder)
153 {
154  if (activePatientFolder == mActivePatientFolder)
155  return;
156 
157  mActivePatientFolder = activePatientFolder;
158 
159  emit sessionChanged();
160 }
161 
162 void SessionStorageServiceImpl::onSessionChanged()
163 {
164  reporter()->setLoggingFolder(this->getSubFolder("Logs/"));
165 }
166 
167 void SessionStorageServiceImpl::clearPatientSilent()
168 {
169  this->setActivePatient(this->getNoPatientFolder());
170  emit cleared();
171 }
172 
173 bool SessionStorageServiceImpl::isActivePatient(QString patient) const
174 {
175  return (patient == mActivePatientFolder);
176 }
177 
178 void SessionStorageServiceImpl::loadPatientSilent(QString choosenDir)
179 {
180  if (this->isActivePatient(choosenDir))
181  return;
182  this->clearPatientSilent();
183  if (choosenDir == QString::null)
184  return; // On cancel
185 
186  QString filename = QDir(choosenDir).absoluteFilePath(this->getXmlFileName());
187  QDomDocument doc = XmlFileHandler::readXmlFile(filename);
188  mActivePatientFolder = choosenDir; // must set path before emitting isLoading()
189 
190  if (!doc.isNull())
191  {
192  //Read the xml
193  QDomElement element = doc.documentElement();
194  emit isLoading(element);
195  emit isLoadingSecond(element);
196  }
197 
198  emit sessionChanged();
199 }
200 
204 void SessionStorageServiceImpl::writeRecentPatientData()
205 {
206  settings()->setValue("startup/lastPatient", mActivePatientFolder);
207  settings()->setValue("startup/lastPatientSaveTime", QDateTime::currentDateTime().toString(timestampSecondsFormat()));
208 }
209 
210 void SessionStorageServiceImpl::generateSaveDoc(QDomDocument& doc)
211 {
212  doc.appendChild(doc.createProcessingInstruction("xml version =", "'1.0'"));
213 
214  QDomElement patientNode = doc.createElement("patient");
215 
216  // note: all nodes must be below <patient>. XML requires only one root node per file.
217  QDomElement versionName = doc.createElement("version_name");
218  versionName.appendChild(doc.createTextNode(this->getVersionName()));
219  patientNode.appendChild(versionName);
220 
221  QDomElement activePatientNode = doc.createElement("active_patient");
222  activePatientNode.appendChild(doc.createTextNode(mActivePatientFolder.toStdString().c_str()));
223  patientNode.appendChild(activePatientNode);
224  doc.appendChild(patientNode);
225 }
226 
227 QString SessionStorageServiceImpl::convertToValidFolderName(QString dir) const
228 {
229  if (!dir.endsWith(".cx3"))
230  dir.append(".cx3");
231  return dir;
232 }
233 
234 void SessionStorageServiceImpl::createPatientFolders(QString dir)
235 {
236  QDir().mkpath(dir);
237  QDir().mkpath(dir+"/Images");
238  QDir().mkpath(dir+"/Logs");
239  QDir().mkpath(dir+"/US_Acq");
240 }
241 
242 QString SessionStorageServiceImpl::getVersionName()
243 {
244  return QString("%1").arg(CustusX_VERSION_STRING);
245 }
246 
247 void SessionStorageServiceImpl::clearCache()
248 {
249 // std::cout << "DataLocations::getCachePath() " << DataLocations::getCachePath() << std::endl;
250  // clear the global cache used by app
252 }
253 
257 QString SessionStorageServiceImpl::getCommandLineStartupPatient()
258 {
259  int doLoad = QApplication::arguments().indexOf("--load");
260  if (doLoad < 0)
261  return "";
262  if (doLoad + 1 >= QApplication::arguments().size())
263  return "";
264 
265  QString folder = QApplication::arguments()[doLoad + 1];
266 
267  return folder;
268 }
269 
272 void SessionStorageServiceImpl::startupLoadPatient()
273 {
274  QString folder = this->getCommandLineStartupPatient();
275 
276  if (!folder.isEmpty())
277  {
278  report(QString("Startup Load [%1] from command line").arg(folder));
279  }
280 
281  if (folder.isEmpty() && settings()->value("Automation/autoLoadRecentPatient").toBool())
282  {
283  folder = settings()->value("startup/lastPatient").toString();
284  if(this->isValidSessionFolder(folder))
285  {
286  QDateTime lastSaveTime = QDateTime::fromString(settings()->value("startup/lastPatientSaveTime").toString(), timestampSecondsFormat());
287  double minsSinceLastSave = lastSaveTime.secsTo(QDateTime::currentDateTime())/60;
288  double autoLoadRecentPatientWithinHours = settings()->value("Automation/autoLoadRecentPatientWithinHours").toDouble();
289  int allowedMinsSinceLastSave = autoLoadRecentPatientWithinHours*60;
290  if (minsSinceLastSave > allowedMinsSinceLastSave) // if less than 8 hours, accept
291  {
292  report(
293  QString("Startup Load: Ignored recent patient because %1 hours since last save, limit is %2")
294  .arg(int(minsSinceLastSave/60))
295  .arg(int(allowedMinsSinceLastSave/60)));
296  folder = "";
297  }
298  if (!folder.isEmpty())
299  report(QString("Startup Load [%1] as recent patient").arg(folder));
300  }
301  else
302  {
303  report("Startup Load: Ignored recent patient because it is not valid anymore");
304  folder = "";
305  }
306 
307  }
308 
309  if (folder.isEmpty())
310  return;
311 
312  this->load(folder);
313 }
314 
315 } // namespace cx
static void writeXmlFile(QDomDocument &doc, QString &filename)
void reportError(QString msg)
Definition: cxLogger.cpp:71
void isLoading(QDomElement &root)
emitted while loading a session. Xml storage is available, getRootFolder() is set to loaded value...
ReporterPtr reporter()
Definition: cxReporter.cpp:36
bool removeNonemptyDirRecursively(const QString &dirName)
void isLoadingSecond(QDomElement &root)
Emitted after the isLoading signal, to allow for structures that must be loaded after core structures...
virtual void save()
Save all application data to XML file.
virtual void load(QString dir)
load session from dir, or create new session in this location if none exist
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:66
QString timestampSecondsFormat()
Definition: cxTime.cpp:18
void sessionChanged()
emitted after change to a new session (new or loaded or cleared)
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:58
static QString getCachePath()
return path to a folder that is used during execution, will be cleared at start and stop...
QString getSubFolder(QString relative)
return and create a folder/path relative to root. Created if necessary.
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:21
void cleared()
emitted when session is cleared, before isLoading is called
static QDomDocument readXmlFile(QString &filename)
void report(QString msg)
Definition: cxLogger.cpp:69
SessionStorageServiceImpl(ctkPluginContext *context)
void isSaving(QDomElement &root)
xml storage is available
Namespace for all CustusX production code.