Fraxinus  16.5.0-fx-rc1
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxRegistrationHistoryWidget.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 <QTreeWidget>
36 #include <QTreeWidgetItem>
37 #include <QStringList>
38 #include <QVBoxLayout>
39 #include "cxImage.h"
40 
41 #include "cxTime.h"
42 #include "cxTypeConversions.h"
43 #include "cxPatientModelService.h"
44 #include "cxLogger.h"
45 #include "cxTrackingService.h"
46 
47 namespace cx
48 {
49 RegistrationHistoryWidget::RegistrationHistoryWidget(RegServicesPtr servicesPtr, QWidget* parent, bool compact) :
50  BaseWidget(parent, "RegistrationHistoryWidget", "Registration History"),
51  mServices(servicesPtr)
52 {
53  this->setWhatsThis(this->defaultWhatsThis());
54  this->setToolTip(this->defaultWhatsThis());
55 
56  mGroup = new QFrame;
57  mTextEdit = NULL;
58 
59  QVBoxLayout* toptopLayout = new QVBoxLayout(this);
60  QHBoxLayout* topLayout = new QHBoxLayout;
61  this->createControls(topLayout);
62 
63  toptopLayout->addWidget(mGroup);
64  mGroup->setLayout(topLayout);
65  if (!compact)
66  {
67  mTextEdit = new QTextEdit;
68  mTextEdit->setLineWrapMode(QTextEdit::NoWrap);
69 // mTextEdit->setVisible(true);
70  toptopLayout->addWidget(mTextEdit, 1);
71  toptopLayout->addStretch();
72  topLayout->addStretch();
73  }else
74  {
75  toptopLayout->setContentsMargins(QMargins(0,0,0,0));
76  topLayout->setContentsMargins(QMargins(0,0,0,0));
77  }
78 
79 }
80 
82 {
83 }
84 
86 {
87  return "<html>"
88  "<h3>Registration history.</h3>"
89  "<p>"
90  "Use the registration history to rewind the system to previous time. When history is rewinded, "
91  "all registrations performed after the active time is ignored by the system."
92  "</p>"
93  "<p>"
94  "<b>NB:</b> While a previous time is active, <em>no new registrations or adding of data</em> should be performed. "
95  "This will lead to undefined behaviour!</b>"
96  "</p>"
97  "</html>";
98 }
99 
100 void RegistrationHistoryWidget::createControls(QHBoxLayout* layout)
101 {
102  mRemoveAction = this->createAction(layout, ":/icons/open_icon_library/dialog-close.png", "Remove",
103  "Delete all registrations after the active time", SLOT(removeSlot()));
104 
105  mBehindLabel = new QLabel(this);
106  mBehindLabel->setToolTip("Number of registrations before the active time");
107  layout->addWidget(mBehindLabel);
108 
109  mRewindAction = this->createAction(layout, ":/icons/open_icon_library/arrow-left-3.png", "Rewind",
110  "One step back in registration history, changing active time.\nThis enables looking at a previous system state,\nbut take care to not add more registrations while this state.",
111  SLOT(rewindSlot()));
112 
113  mForwardAction = this->createAction(layout, ":/icons/open_icon_library/arrow-right-3.png",
114  "Rewind", "One step forward in registration history", SLOT(forwardSlot()));
115 
116  mInFrontLabel = new QLabel(this);
117  mInFrontLabel->setToolTip("Number of registrations after active time");
118  layout->addWidget(mInFrontLabel);
119 
120  mFastForwardAction = this->createAction(layout,
121  ":/icons/open_icon_library/arrow-right-double-3.png", "Fast Forward",
122  "Step to latest registration", SLOT(fastForwardSlot()));
123 }
124 
126 {
127  QWidget::showEvent(event);
128 
129  this->reconnectSlot();
130  connect(mServices->patient().get(), &PatientModelService::dataAddedOrRemoved, this, &RegistrationHistoryWidget::reconnectSlot);
131  connect(mServices->patient().get(), &PatientModelService::dataAddedOrRemoved, this, &RegistrationHistoryWidget::setModified);
132 
133  setModified();
134 }
135 
136 void RegistrationHistoryWidget::hideEvent(QCloseEvent* event)
137 {
138  QWidget::closeEvent(event);
139 
140  for (unsigned i = 0; i < mHistories.size(); ++i)
141  {
142  disconnect(mHistories[i].get(), &RegistrationHistory::currentChanged, this, &RegistrationHistoryWidget::setModified);
143  }
144  disconnect(mServices->patient().get(), &PatientModelService::dataAddedOrRemoved, this, &RegistrationHistoryWidget::reconnectSlot);
145  disconnect(mServices->patient().get(), &PatientModelService::dataAddedOrRemoved, this, &RegistrationHistoryWidget::setModified);
146 }
147 
149 {
150  for (unsigned i = 0; i < mHistories.size(); ++i)
151  {
152  disconnect(mHistories[i].get(), &RegistrationHistory::currentChanged, this, &RegistrationHistoryWidget::setModified);
153  }
154 
155  mHistories = this->getAllRegistrationHistories();
156 
157  for (unsigned i = 0; i < mHistories.size(); ++i)
158  {
160  }
161 }
162 
166 std::map<QDateTime, QString> RegistrationHistoryWidget::getRegistrationTimes()
167 {
168  TimeMap retval;
169 
170  std::vector<RegistrationHistoryPtr> allHistories = this->getAllRegistrationHistories();
171 
172  retval[QDateTime(QDate(2000, 1, 1))] = "initial";
173 
174  for (unsigned i = 0; i < allHistories.size(); ++i)
175  {
176  std::vector<RegistrationTransform> current = allHistories[i]->getData();
177  for (unsigned j = 0; j < current.size(); ++j)
178  {
179  retval[current[j].mTimestamp] = QString("%1 [f=%2, m=%3]").arg(current[j].mType).arg(current[j].mFixed).arg(
180  current[j].mMoving);
181  }
182  std::vector<ParentSpace> frames = allHistories[i]->getParentSpaces();
183  for (unsigned j = 0; j < frames.size(); ++j)
184  {
185  retval[frames[j].mTimestamp] = QString("%1 [val=%2]").arg(frames[j].mType).arg(frames[j].mValue);
186  }
187  }
188 
189  retval.erase(QDateTime());
190 
191  return retval;
192 }
193 
194 RegistrationHistoryWidget::TimeMap::iterator RegistrationHistoryWidget::findCurrentActiveIter(TimeMap& times)
195 {
196  QDateTime active = this->getActiveTime();
197 
198  if (!active.isValid())
199  return times.end();
200 
201  for (TimeMap::iterator iter = times.begin(); iter != times.end(); ++iter)
202  {
203  if (iter->first >= active)
204  return iter;
205  }
206  return times.end();
207 }
208 
209 QDateTime RegistrationHistoryWidget::getActiveTime()
210 {
211  std::vector<RegistrationHistoryPtr> raw = getAllRegistrationHistories();
212 
213  for (unsigned i = 0; i < raw.size(); ++i)
214  {
215  if (raw[i]->isNull())
216  continue;
217  return raw[i]->getActiveTime();
218  }
219 
220  return QDateTime();
221 }
222 
223 void RegistrationHistoryWidget::setActiveTime(QDateTime active)
224 {
225  std::vector<RegistrationHistoryPtr> raw = getAllRegistrationHistories();
226  for (unsigned i = 0; i < raw.size(); ++i)
227  {
228  raw[i]->setActiveTime(active);
229  }
230 }
231 
235 std::vector<RegistrationHistoryPtr> RegistrationHistoryWidget::getAllRegistrationHistories()
236 {
237  std::vector<RegistrationHistoryPtr> retval;
238  retval.push_back(mServices->patient()->get_rMpr_History());
239 
240  std::map<QString, DataPtr> data = mServices->patient()->getData();
241  for (std::map<QString, DataPtr>::iterator iter = data.begin(); iter != data.end(); ++iter)
242  {
243  retval.push_back(iter->second->get_rMd_History());
244  }
245 
246  return retval;
247 }
248 
252 {
253  debugDump();
254 
255  QDateTime active = this->getActiveTime();
256  if (!active.isValid()) // if invalid: we are already at head
257  return;
258 
259  report(
260  "Removing all registration performed later than " + active.toString(timestampSecondsFormatNice()) + ".");
261 
262  std::vector<RegistrationHistoryPtr> raw = getAllRegistrationHistories();
263  for (unsigned i = 0; i < raw.size(); ++i)
264  {
265  raw[i]->removeNewerThan(active);
266  }
267 
268  debugDump();
269 }
270 
271 std::vector<RegistrationTransform> RegistrationHistoryWidget::mergeHistory(const std::vector<RegistrationHistoryPtr>& allHistories)
272 {
273  std::vector<RegistrationTransform> history;
274  for (unsigned i = 0; i < allHistories.size(); ++i)
275  {
276  std::vector<RegistrationTransform> current = allHistories[i]->getData();
277  std::copy(current.begin(), current.end(), std::back_inserter(history));
278  }
279  std::sort(history.begin(), history.end());
280 
281  return history;
282 }
283 
288 {
289 
290  TimeMap times = this->getRegistrationTimes();
291 
292  if (times.size() <= 1)
293  return;
294 
295  // current points to the timestamp currently in use. end() is current time.
296  std::map<QDateTime, QString>::iterator current = this->findCurrentActiveIter(times);
297 
298  if (current == times.begin())
299  return;
300 
301  if (current == times.end())
302  --current; // ignore the last entry
303 
304  --current;
305  report(
306  "Rewind: Setting registration time to " + current->first.toString(timestampSecondsFormatNice()) + ", ["
307  + current->second + "]");
308  this->setActiveTime(current->first);
309 }
310 
311 QString RegistrationHistoryWidget::debugDump()
312 {
313  TimeMap times = this->getRegistrationTimes();
314  bool addedBreak = false;
315  std::stringstream ss;
316  ss << "<html>";
317  ss << "<p><i>";
318  if (!this->getActiveTime().isValid())
319  ss << "Active time: Current \n";
320  else
321  ss << "Active time: " << this->getActiveTime().toString(timestampSecondsFormatNice()) << "\n";
322  ss << "</i></p>";
323 
324  ss << "<p><span style=\"color:blue\">";
325  for (TimeMap::iterator iter = times.begin(); iter != times.end(); ++iter)
326  {
327  if (iter->first > this->getActiveTime() && !addedBreak && this->getActiveTime().isValid())
328  {
329  ss << "</span> <span style=\"color:gray\">";
330  addedBreak = true;
331  }
332  //else
333  {
334  ss << "<br />";
335  }
336  ss << iter->first.toString(timestampSecondsFormatNice()) << "\t" << iter->second;
337  }
338  ss << "</span></p>";
339 
340  return qstring_cast(ss.str());
341 }
342 
343 template<class T>
344 QAction* RegistrationHistoryWidget::createAction(QLayout* layout, QString iconName, QString text, QString tip, T slot)
345 {
346  QAction* action = new QAction(QIcon(iconName), text, this);
347  action->setToolTip(tip);
348  connect(action, SIGNAL(triggered()), this, slot);
349 
350  QToolButton* button = new QToolButton();
351  button->setDefaultAction(action);
352  layout->addWidget(button);
353 
354  return action;
355 }
356 
360 {
361  std::map<QDateTime, QString> times = this->getRegistrationTimes();
362 
363  if (times.empty())
364  return;
365 
366  // current points to the timestamp currently in use. end() is current time.
367  TimeMap::iterator current = this->findCurrentActiveIter(times);
368 
369  if (current == times.end()) // already at end, ignore
370  return;
371  ++current;
372 
373  if (current == times.end() || times.rbegin()->first == current->first) // if at end or at the last position, interpret as end
374  {
375  report("Forward: Setting registration time to current, [" + times.rbegin()->second + "]");
376  this->setActiveTime(QDateTime());
377  }
378  else
379  {
380  report("Forward: Setting registration time to " + current->first.toString(timestampSecondsFormatNice()) + ", ["+ current->second + "]");
381  this->setActiveTime(current->first);
382  }
383 }
384 
389 {
390  std::vector<RegistrationHistoryPtr> raw = getAllRegistrationHistories();
391  report("Fast Forward: Setting registration time to current.");
392 
393  for (unsigned i = 0; i < raw.size(); ++i)
394  {
395  raw[i]->setActiveTime(QDateTime());
396  }
397 }
398 
400 {
401  //Not used?
402 // std::vector<RegistrationHistoryPtr> raw = getAllRegistrationHistories();
403 // std::vector<RegistrationTransform> history = mergeHistory(raw);
404 
405  TimeMap times = this->getRegistrationTimes();
406  std::map<QDateTime, QString>::iterator current = this->findCurrentActiveIter(times);
407  size_t behind = std::min<int>(distance(times.begin(), current), times.size() - 1);
408  size_t infront = times.size() - 1 - behind;
409 
410  mRewindAction->setText("Rewind (" + qstring_cast(behind) + ")");
411  mForwardAction->setText("Forward (" + qstring_cast(infront) + ")");
412 
413  mBehindLabel->setText("(" + qstring_cast(behind) + ")");
414  mInFrontLabel->setText("(" + qstring_cast(infront) + ")");
415 
416  mRewindAction->setEnabled(behind > 0);
417  mRewindAction->setEnabled(behind > 0);
418  mRemoveAction->setEnabled(infront != 0);
419  mForwardAction->setEnabled(infront != 0);
420  mFastForwardAction->setEnabled(infront != 0);
421 
422  QString color;
423  if (infront == 0)
424  {
425  color = "";
426  }
427  else
428  {
429  color = QString("QFrame {background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 rgb(255,30,0), stop:0.8 rgb(255,50,0), stop:1 transparent) }");
430  color += QString("QLabel {background-color: transparent }");
431  }
432 
433  mGroup->setStyleSheet(color);
434 
435  if (mTextEdit)
436  mTextEdit->setText(debugDump());
437 }
438 
439 } //end namespace cx
QString qstring_cast(const T &val)
boost::shared_ptr< class RegServices > RegServicesPtr
Definition: cxRegServices.h:41
QString timestampSecondsFormatNice()
Definition: cxTime.cpp:47
virtual void hideEvent(QCloseEvent *event)
disconnects stuff
virtual void showEvent(QShowEvent *event)
updates internal info before showing the widget
Interface for QWidget which handles widgets uniformly for the system.
Definition: cxBaseWidget.h:108
void report(QString msg)
Definition: cxLogger.cpp:90