Medical Imaging Interaction Toolkit  2018.4.99-a3d2e8fb
Medical Imaging Interaction Toolkit
QmitkPointListWidget.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 #include "QmitkPointListWidget.h"
13 #include "QmitkPointListView.h"
14 #include "QmitkPointListModel.h"
15 
16 #include <QDir>
17 #include <QFileDialog>
18 #include <QHBoxLayout>
19 #include <QMessageBox>
20 #include <mitkIOUtil.h>
21 
22 
23 #include <QmitkEditPointDialog.h>
24 #include <QmitkStyleManager.h>
25 
27 
28 #include <mitkDataInteractor.h>
29 
30 QmitkPointListWidget::QmitkPointListWidget(QWidget *parent, int orientation)
31  : QWidget(parent),
32  m_PointListView(nullptr),
33  m_PointSetNode(nullptr),
34  m_Orientation(0),
35  m_MovePointUpBtn(nullptr),
36  m_MovePointDownBtn(nullptr),
37  m_RemovePointBtn(nullptr),
38  m_SavePointsBtn(nullptr),
39  m_LoadPointsBtn(nullptr),
40  m_ToggleAddPoint(nullptr),
41  m_AddPoint(nullptr),
42  m_TimeStepDisplay(nullptr),
43  m_DataInteractor(nullptr),
44  m_TimeStep(0),
45  m_EditAllowed(true),
46  m_NodeObserverTag(0)
47 {
49 
50  if (orientation != 0)
51  m_Orientation = orientation;
52 
53  SetupUi();
55  ObserveNewNode(nullptr);
56 }
57 
59 {
60  m_DataInteractor = nullptr;
61 
63  {
64  m_PointSetNode->RemoveObserver(m_NodeObserverTag);
66  }
67 
68  delete m_PointListView;
69 }
70 
72 {
73  connect(this->m_LoadPointsBtn, SIGNAL(clicked()), this, SLOT(OnBtnLoadPoints()));
74  connect(this->m_SavePointsBtn, SIGNAL(clicked()), this, SLOT(OnBtnSavePoints()));
75  connect(this->m_MovePointUpBtn, SIGNAL(clicked()), this, SLOT(MoveSelectedPointUp()));
76  connect(this->m_MovePointDownBtn, SIGNAL(clicked()), this, SLOT(MoveSelectedPointDown()));
77  connect(this->m_RemovePointBtn, SIGNAL(clicked()), this, SLOT(RemoveSelectedPoint()));
78  connect(this->m_ToggleAddPoint, SIGNAL(toggled(bool)), this, SLOT(OnBtnAddPoint(bool)));
79  connect(this->m_AddPoint, SIGNAL(clicked()), this, SLOT(OnBtnAddPointManually()));
80  connect(this->m_PointListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnListDoubleClick()));
81  connect(this->m_PointListView, SIGNAL(SignalPointSelectionChanged()), this, SLOT(OnPointSelectionChanged()));
82  connect(this->m_PointListView, SIGNAL(SignalTimeStepChanged(int)), this, SLOT(OnTimeStepChanged(int)));
83 }
84 
86 {
87  m_TimeStepLabel->setText(QString("%1").arg(timeStep));
88 }
89 
91 {
92  // Setup the buttons
93 
94  m_ToggleAddPoint = new QPushButton();
95  m_ToggleAddPoint->setMaximumSize(25, 25);
96  m_ToggleAddPoint->setCheckable(true);
97  m_ToggleAddPoint->setToolTip("Toggle point editing (use SHIFT + Left Mouse Button to add Points)");
98  m_ToggleAddPoint->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/QtWidgetsExt/plus.svg")));
99 
100  m_AddPoint = new QPushButton();
101  m_AddPoint->setMaximumSize(25, 25);
102  m_AddPoint->setToolTip("Manually add point");
103  m_AddPoint->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/QtWidgetsExt/plus-xyz.svg")));
104 
105  m_RemovePointBtn = new QPushButton();
106  m_RemovePointBtn->setMaximumSize(25, 25);
107  m_RemovePointBtn->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/QtWidgetsExt/eraser.svg")));
108  m_RemovePointBtn->setToolTip("Erase one point from list (Hotkey: DEL)");
109 
110  m_MovePointUpBtn = new QPushButton();
111  m_MovePointUpBtn->setMaximumSize(25, 25);
112  m_MovePointUpBtn->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/QtWidgetsExt/arrow-up.svg")));
113  m_MovePointUpBtn->setToolTip("Swap selected point upwards (Hotkey: F2)");
114 
115  m_MovePointDownBtn = new QPushButton();
116  m_MovePointDownBtn->setMaximumSize(25, 25);
117  m_MovePointDownBtn->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/QtWidgetsExt/arrow-down.svg")));
118  m_MovePointDownBtn->setToolTip("Swap selected point downwards (Hotkey: F3)");
119 
120  m_SavePointsBtn = new QPushButton();
121  m_SavePointsBtn->setMaximumSize(25, 25);
122  m_SavePointsBtn->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/QtWidgetsExt/save.svg")));
123  m_SavePointsBtn->setToolTip("Save points to file");
124 
125  m_LoadPointsBtn = new QPushButton();
126  m_LoadPointsBtn->setMaximumSize(25, 25);
127  m_LoadPointsBtn->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/QtWidgetsExt/folder-open.svg")));
128  m_LoadPointsBtn->setToolTip("Load list of points from file (REPLACES current content)");
129 
130  int i;
131 
132  QBoxLayout *lay1;
133  QBoxLayout *lay2;
134  QBoxLayout *lay3;
135 
136  switch (m_Orientation)
137  {
138  case 0:
139  lay1 = new QVBoxLayout(this);
140  lay2 = new QHBoxLayout();
141  i = 0;
142  break;
143 
144  case 1:
145  lay1 = new QHBoxLayout(this);
146  lay2 = new QVBoxLayout();
147  i = -1;
148  break;
149 
150  case 2:
151  lay1 = new QHBoxLayout(this);
152  lay2 = new QVBoxLayout();
153  i = 0;
154  break;
155 
156  default:
157  lay1 = new QVBoxLayout(this);
158  lay2 = new QHBoxLayout();
159  i = -1;
160  break;
161  }
162 
163  // setup Layouts
164 
165  this->setLayout(lay1);
166  lay2->stretch(true);
167  lay2->addWidget(m_ToggleAddPoint);
168  lay2->addWidget(m_AddPoint);
169  lay2->addWidget(m_RemovePointBtn);
170  lay2->addWidget(m_MovePointUpBtn);
171  lay2->addWidget(m_MovePointDownBtn);
172  lay2->addWidget(m_SavePointsBtn);
173  lay2->addWidget(m_LoadPointsBtn);
174 
175  // setup Labels
176  m_TimeStepDisplay = new QLabel;
177  m_TimeStepLabel = new QLabel;
178  lay3 = new QHBoxLayout;
179 
180  m_TimeStepDisplay->setMaximumSize(200, 15);
181 
182  lay3->stretch(true);
183  lay3->setAlignment(Qt::AlignLeft);
184  lay3->addWidget(m_TimeStepDisplay);
185  lay3->addWidget(m_TimeStepLabel);
186 
187  m_TimeStepDisplay->setText("Time Step: ");
188  m_TimeStepLabel->setMaximumSize(10, 15);
189 
190  this->OnTimeStepChanged(0);
191 
192  //Add Layouts
193 
194  lay1->insertWidget(i, m_PointListView);
195  this->setLayout(lay1);
196  lay1->addLayout(lay2);
197  lay1->addLayout(lay3);
198 }
199 
201 {
202  if (newPs == nullptr)
203  return;
204 
205  this->m_PointSetNode->SetData(newPs);
206  dynamic_cast<QmitkPointListModel *>(this->m_PointListView->model())->SetPointSetNode(m_PointSetNode);
208 }
209 
211 {
212  if (m_DataInteractor.IsNotNull())
213  m_DataInteractor->SetDataNode(newNode);
214 
215  ObserveNewNode(newNode);
216  dynamic_cast<QmitkPointListModel *>(this->m_PointListView->model())->SetPointSetNode(newNode);
217 }
218 
220 {
221  if ((dynamic_cast<mitk::PointSet *>(m_PointSetNode->GetData())) == nullptr)
222  return; // don't write empty point sets. If application logic requires something else then do something else.
223  if ((dynamic_cast<mitk::PointSet *>(m_PointSetNode->GetData()))->GetSize() == 0)
224  return;
225 
226  // take the previously defined name of node as proposal for filename
227  std::string nodeName = m_PointSetNode->GetName();
228  nodeName = "/" + nodeName + ".mps";
229  QString fileNameProposal = QString();
230  fileNameProposal.append(nodeName.c_str());
231 
232  QString aFilename = QFileDialog::getSaveFileName(
233  nullptr, "Save point set", QDir::currentPath() + fileNameProposal, "MITK Pointset (*.mps)");
234  if (aFilename.isEmpty())
235  return;
236 
237  try
238  {
239  mitk::IOUtil::Save(m_PointSetNode->GetData(), aFilename.toStdString());
240  }
241  catch (...)
242  {
243  QMessageBox::warning(this,
244  "Save point set",
245  QString("File writer reported problems writing %1\n\n"
246  "PLEASE CHECK output file!")
247  .arg(aFilename));
248  }
249 }
250 
252 {
253  // get the name of the file to load
254  QString filename = QFileDialog::getOpenFileName(nullptr, "Open MITK Pointset", "", "MITK Point Sets (*.mps)");
255  if (filename.isEmpty())
256  return;
257 
258  // attempt to load file
259  try
260  {
261  mitk::PointSet::Pointer pointSet = mitk::IOUtil::Load<mitk::PointSet>(filename.toStdString());
262  if (pointSet.IsNull())
263  {
264  QMessageBox::warning(this, "Load point set", QString("File reader could not read %1").arg(filename));
265  return;
266  }
267 
268  // loading successful
269 
270  this->SetPointSet(pointSet);
271  }
272  catch (...)
273  {
274  QMessageBox::warning(this, "Load point set", QString("File reader collapsed while reading %1").arg(filename));
275  }
276  emit PointListChanged();
278 }
279 
281 {
282  return dynamic_cast<mitk::PointSet *>(m_PointSetNode->GetData());
283 }
284 
286 {
287  return m_PointSetNode;
288 }
289 
291 {
292  m_PointListView->SetMultiWidget(multiWidget);
293 }
294 
296 {
297  if (!m_PointSetNode)
298  return;
299  mitk::PointSet *pointSet = dynamic_cast<mitk::PointSet *>(m_PointSetNode->GetData());
300  if (!pointSet)
301  return;
302  if (pointSet->GetSize() == 0)
303  return;
304 
305  QmitkPointListModel *pointListModel = dynamic_cast<QmitkPointListModel *>(m_PointListView->model());
306  pointListModel->RemoveSelectedPoint();
307  emit PointListChanged();
308 }
309 
311 {
312  if (!m_PointSetNode)
313  return;
314  mitk::PointSet *pointSet = dynamic_cast<mitk::PointSet *>(m_PointSetNode->GetData());
315  if (!pointSet)
316  return;
317  if (pointSet->GetSize() == 0)
318  return;
319 
320  QmitkPointListModel *pointListModel = dynamic_cast<QmitkPointListModel *>(m_PointListView->model());
321  pointListModel->MoveSelectedPointDown();
322  emit PointListChanged();
323 }
324 
326 {
327  if (!m_PointSetNode)
328  return;
329  mitk::PointSet *pointSet = dynamic_cast<mitk::PointSet *>(m_PointSetNode->GetData());
330  if (!pointSet)
331  return;
332  if (pointSet->GetSize() == 0)
333  return;
334 
335  QmitkPointListModel *pointListModel = dynamic_cast<QmitkPointListModel *>(m_PointListView->model());
336  pointListModel->MoveSelectedPointUp();
337  emit PointListChanged();
338 }
339 
341 {
342  if (m_PointSetNode.IsNotNull())
343  {
344  if (checked)
345  {
346  m_DataInteractor = m_PointSetNode->GetDataInteractor();
347  // If no data Interactor is present create a new one
348  if (m_DataInteractor.IsNull())
349  {
350  // Create PointSetData Interactor
352  // Load the according state machine for regular point set interaction
353  m_DataInteractor->LoadStateMachine("PointSet.xml");
354  // Set the configuration file that defines the triggers for the transitions
355  m_DataInteractor->SetEventConfig("PointSetConfig.xml");
356  // set the DataNode (which already is added to the DataStorage
357  m_DataInteractor->SetDataNode(m_PointSetNode);
358  }
359  }
360  else
361  {
362  m_PointSetNode->SetDataInteractor(nullptr);
363  m_DataInteractor = nullptr;
364  }
365  emit EditPointSets(checked);
366  }
367 }
368 
370 {
371  mitk::PointSet *pointSet = this->GetPointSet();
372  QmitkEditPointDialog editPointDialog(this);
373 
374  if (this->GetPointSet()->IsEmpty())
375  {
376  editPointDialog.SetPoint(pointSet, 0, m_TimeStep);
377  }
378 
379  else
380  {
381  mitk::PointSet::PointsIterator maxIt = pointSet->GetMaxId();
382  mitk::PointSet::PointIdentifier maxId = maxIt->Index();
383  editPointDialog.SetPoint(pointSet, maxId + 1, m_TimeStep);
384  }
385 
386  editPointDialog.exec();
388 }
389 
391 {
392 }
393 
395 {
396  emit this->PointSelectionChanged();
397 }
398 
400 {
401 }
402 
404 {
405  m_EditAllowed = enabled;
406  if (enabled == false)
407  m_ToggleAddPoint->setEnabled(false);
408  else
409  m_ToggleAddPoint->setEnabled(true);
410  OnBtnAddPoint(enabled);
411 }
412 
414 {
415  if (m_DataInteractor.IsNotNull())
416  m_DataInteractor->SetDataNode(node);
417 
418  // remove old observer
419  if (m_PointSetNode)
420  {
421  if (m_DataInteractor)
422  {
423  m_DataInteractor = nullptr;
424  m_ToggleAddPoint->setChecked(false);
425  }
426 
427  m_PointSetNode->RemoveObserver(m_NodeObserverTag);
428  m_NodeObserverTag = 0;
429  }
430 
431  m_PointSetNode = node;
432  // add new observer if necessary
433  if (m_PointSetNode)
434  {
435  itk::ReceptorMemberCommand<QmitkPointListWidget>::Pointer command =
436  itk::ReceptorMemberCommand<QmitkPointListWidget>::New();
437  command->SetCallbackFunction(this, &QmitkPointListWidget::OnNodeDeleted);
438  m_NodeObserverTag = m_PointSetNode->AddObserver(itk::DeleteEvent(), command);
439  }
440  else
441  {
442  m_NodeObserverTag = 0;
443  }
444 
445  if (m_EditAllowed == true)
446  m_ToggleAddPoint->setEnabled(m_PointSetNode);
447  else
448  m_ToggleAddPoint->setEnabled(false);
449 
450  m_RemovePointBtn->setEnabled(m_PointSetNode);
451  m_LoadPointsBtn->setEnabled(m_PointSetNode);
452  m_SavePointsBtn->setEnabled(m_PointSetNode);
453  m_AddPoint->setEnabled(m_PointSetNode);
454 }
455 
456 void QmitkPointListWidget::OnNodeDeleted(const itk::EventObject &)
457 {
458  if (m_PointSetNode.IsNotNull() && !m_NodeObserverTag)
459  m_PointSetNode->RemoveObserver(m_NodeObserverTag);
460  m_NodeObserverTag = 0;
461  m_PointSetNode = nullptr;
463  m_ToggleAddPoint->setEnabled(false);
464 
465  m_RemovePointBtn->setEnabled(false);
466  m_LoadPointsBtn->setEnabled(false);
467  m_SavePointsBtn->setEnabled(false);
468  m_AddPoint->setEnabled(false);
469 }
470 
472 {
474 }
475 
477 {
479 }
480 
482 {
483  m_ToggleAddPoint->setChecked(false);
484 }
DataType::PointsContainerIterator PointsIterator
Definition: mitkPointSet.h:135
PointsIterator GetMaxId(int t=0)
Get an iterator to the max ID element if existent. Return End() otherwise.
A dialog for editing points directly (coordinates) via TextEdits.
void SetMultiWidget(QmitkStdMultiWidget *multiWidget)
If Multiwidget is set, the crosshair is automatically centering to the selected point As an alternati...
void RemoveSliceNavigationController(mitk::SliceNavigationController *snc)
Remove a mitk::SliceNavigationController instance.
void AddSliceNavigationController(mitk::SliceNavigationController *snc)
Add a mitk::SliceNavigationController instance.
void OnBtnAddPoint(bool checked)
void PointListChanged()
signal to inform about cleared or loaded point sets
void SetPointSet(mitk::PointSet *newPs)
assign a point set (contained in a node of DataStorage) for observation
void EditPointSets(bool active)
signal to inform about the state of the EditPointSetButton, whether an interactor for setting points ...
void OnTimeStepChanged(int timeStep)
GUI widget for handling mitk::PointSet.
QPushButton * m_MovePointDownBtn
Controls the selection of the slice the associated BaseRenderer will display.
QmitkPointListView * m_PointListView
DataType::PointIdentifier PointIdentifier
Definition: mitkPointSet.h:133
void PointSelectionChanged()
signal to inform that the selection of a point in the pointset has changed
void SetPointSetNode(mitk::DataNode *newNode)
assign a point set (contained in a node of DataStorage) for observation
virtual int GetSize(unsigned int t=0) const
returns the current size of the point-list
mitk::DataNode::Pointer m_PointSetNode
void OnPointSelectionChanged()
pass through signal from PointListView that point selection has changed
Data structure which stores a set of points. Superclass of mitk::Mesh.
Definition: mitkPointSet.h:75
The &#39;QmitkStdMultiWidget&#39; is a &#39;QmitkAbstractMultiWidget&#39; that is used to display multiple render win...
void ObserveNewNode(mitk::DataNode *node)
static RenderingManager * GetInstance()
void DeactivateInteractor(bool deactivate)
mitk::DataNode * GetPointSetNode()
mitk::DataInteractor::Pointer m_DataInteractor
void UnselectEditButton()
Unselects the edit button if it is selected.
static void Save(const mitk::BaseData *data, const std::string &path, bool setPathProperty=false)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:774
QmitkPointListWidget(QWidget *parent=nullptr, int orientation=0)
void SetMultiWidget(QmitkStdMultiWidget *multiWidget)
assign a QmitkStdMultiWidget for updating render window crosshair
void AddSliceNavigationController(mitk::SliceNavigationController *snc)
Add a mitk::SliceNavigationController instance.
void EnableEditButton(bool enabled)
static QIcon ThemeIcon(const QByteArray &originalSVG)
mitk::PointSet * GetPointSet()
void OnNodeDeleted(const itk::EventObject &e)
itk observer for node "delete" events
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
void SetPointSetNode(mitk::DataNode *pointSetNode)
assign a point set for observation
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
void RemoveSliceNavigationController(mitk::SliceNavigationController *snc)
Remove a mitk::SliceNavigationController instance.
void SetPoint(mitk::PointSet *_PointSet, mitk::PointSet::PointIdentifier _PointId, int timestep=0)