Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
QmitkAbstractView.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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "QmitkAbstractView.h"
19 #include "internal/QmitkCommonActivator.h"
20 #include "internal/QmitkDataNodeItemModel.h"
21 
22 // mitk Includes
23 #include <mitkLogMacros.h>
26 #include <mitkWorkbenchUtil.h>
27 #include <mitkDataNodeObject.h>
28 #include <mitkIRenderingManager.h>
29 
30 // berry Includes
31 #include <berryIWorkbenchPage.h>
32 #include <berryIBerryPreferences.h>
33 #include <berryIEditorPart.h>
35 #include <berryUIException.h>
36 
37 // CTK Includes
38 #include <ctkServiceTracker.h>
39 
40 // Qt Includes
41 #include <QItemSelectionModel>
42 #include <QApplication>
43 #include <QMessageBox>
44 #include <QScrollArea>
45 #include <QVBoxLayout>
46 
47 class QmitkAbstractViewPrivate
48 {
49 public:
50 
51  QmitkAbstractViewPrivate(QmitkAbstractView* qq)
52  : q(qq)
53  , m_PrefServiceTracker(QmitkCommonActivator::GetContext())
54  , m_DataStorageServiceTracker(QmitkCommonActivator::GetContext())
55  , m_Parent(nullptr)
56  , m_DataNodeItemModel(new QmitkDataNodeItemModel)
57  , m_DataNodeSelectionModel(new QItemSelectionModel(m_DataNodeItemModel))
58  , m_InDataStorageChanged(false)
59  {
60  m_PrefServiceTracker.open();
61  m_DataStorageServiceTracker.open();
62  }
63 
64  ~QmitkAbstractViewPrivate()
65  {
66  delete m_DataNodeSelectionModel;
67  delete m_DataNodeItemModel;
68 
69  m_PrefServiceTracker.close();
70  m_DataStorageServiceTracker.close();
71  }
72 
78  void NodeAddedProxy(const mitk::DataNode* node)
79  {
80  // garantuee no recursions when a new node event is thrown in NodeAdded()
81  if(!m_InDataStorageChanged)
82  {
83  m_InDataStorageChanged = true;
84  q->NodeAdded(node);
85  q->DataStorageModified();
86  m_InDataStorageChanged = false;
87  }
88  }
89 
95  void NodeRemovedProxy(const mitk::DataNode* node)
96  {
97  // garantuee no recursions when a new node event is thrown in NodeAdded()
98  if(!m_InDataStorageChanged)
99  {
100  m_InDataStorageChanged = true;
101  q->NodeRemoved(node);
102  q->DataStorageModified();
103  m_InDataStorageChanged = false;
104  }
105  }
106 
112  void NodeChangedProxy(const mitk::DataNode* node)
113  {
114  // garantuee no recursions when a new node event is thrown in NodeAdded()
115  if(!m_InDataStorageChanged)
116  {
117  m_InDataStorageChanged = true;
118  q->NodeChanged(node);
119  q->DataStorageModified();
120  m_InDataStorageChanged = false;
121  }
122  }
123 
127  void BlueBerrySelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart,
128  const berry::ISelection::ConstPointer& selection)
129  {
130  if(sourcepart.IsNull() || sourcepart.GetPointer() == static_cast<berry::IWorkbenchPart*>(q))
131  return;
132 
133  if(selection.IsNull())
134  {
135  q->OnNullSelection(sourcepart);
136  return;
137  }
138 
139  mitk::DataNodeSelection::ConstPointer _DataNodeSelection
140  = selection.Cast<const mitk::DataNodeSelection>();
141  q->OnSelectionChanged(sourcepart, this->DataNodeSelectionToQList(_DataNodeSelection));
142  }
143 
147  QList<mitk::DataNode::Pointer> DataNodeSelectionToQList(mitk::DataNodeSelection::ConstPointer currentSelection) const;
148 
149  QmitkAbstractView* const q;
150 
151  ctkServiceTracker<berry::IPreferencesService*> m_PrefServiceTracker;
152 
153  ctkServiceTracker<mitk::IDataStorageService*> m_DataStorageServiceTracker;
154 
159  QWidget* m_Parent;
160 
164  QmitkDataNodeSelectionProvider::Pointer m_SelectionProvider;
165 
169  QmitkDataNodeItemModel* m_DataNodeItemModel;
170 
174  QItemSelectionModel* m_DataNodeSelectionModel;
175 
179  QScopedPointer<berry::ISelectionListener> m_BlueBerrySelectionListener;
180 
185  bool m_InDataStorageChanged;
186 
187 };
188 
190  : d(new QmitkAbstractViewPrivate(this))
191 {
192 }
193 
194 void QmitkAbstractView::CreatePartControl(QWidget* parent)
195 {
196 
197  // scrollArea
198  auto scrollArea = new QScrollArea;
199  //QVBoxLayout* scrollAreaLayout = new QVBoxLayout(scrollArea);
200  scrollArea->setFrameShadow(QFrame::Plain);
201  scrollArea->setFrameShape(QFrame::NoFrame);
202  scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
203  scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
204 
205  // m_Parent
206  d->m_Parent = new QWidget;
207  //m_Parent->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
208  this->CreateQtPartControl(d->m_Parent);
209 
210  //scrollAreaLayout->addWidget(m_Parent);
211  //scrollArea->setLayout(scrollAreaLayout);
212 
213  // set the widget now
214  scrollArea->setWidgetResizable(true);
215  scrollArea->setWidget(d->m_Parent);
216 
217  // add the scroll area to the real parent (the view tabbar)
218  QWidget* parentQWidget = static_cast<QWidget*>(parent);
219  auto parentLayout = new QVBoxLayout(parentQWidget);
220  parentLayout->setMargin(0);
221  parentLayout->setSpacing(0);
222  parentLayout->addWidget(scrollArea);
223 
224  // finally set the layout containing the scroll area to the parent widget (= show it)
225  parentQWidget->setLayout(parentLayout);
226 
227  this->AfterCreateQtPartControl();
228 }
229 
230 void QmitkAbstractView::AfterCreateQtPartControl()
231 {
232  this->SetSelectionProvider();
233 
234  // REGISTER DATASTORAGE LISTENER
236  ( d.data(), &QmitkAbstractViewPrivate::NodeAddedProxy ) );
238  ( d.data(), &QmitkAbstractViewPrivate::NodeChangedProxy ) );
240  ( d.data(), &QmitkAbstractViewPrivate::NodeRemovedProxy ) );
241 
242  // REGISTER PREFERENCES LISTENER
244  if(prefs.IsNotNull())
245  prefs->OnChanged.AddListener(
247  &QmitkAbstractView::OnPreferencesChanged));
248 
249  // REGISTER FOR WORKBENCH SELECTION EVENTS
250  d->m_BlueBerrySelectionListener.reset(new berry::NullSelectionChangedAdapter<QmitkAbstractViewPrivate>(
251  d.data(), &QmitkAbstractViewPrivate::BlueBerrySelectionChanged));
252  this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddPostSelectionListener(d->m_BlueBerrySelectionListener.data());
253 
254  // EMULATE INITIAL SELECTION EVENTS
255 
256  // send the current selection
257  berry::IWorkbenchPart::Pointer activePart = this->GetSite()->GetPage()->GetActivePart();
258  if (activePart.IsNotNull())
259  {
260  this->OnSelectionChanged(activePart, this->GetCurrentSelection());
261  }
262 
263  // send preferences changed event
264  this->OnPreferencesChanged(this->GetPreferences().Cast<berry::IBerryPreferences>().GetPointer());
265 }
266 
268 {
269  this->Register();
270 
272  ( d.data(), &QmitkAbstractViewPrivate::NodeAddedProxy ) );
274  ( d.data(), &QmitkAbstractViewPrivate::NodeRemovedProxy) );
276  ( d.data(), &QmitkAbstractViewPrivate::NodeChangedProxy ) );
277 
279  if(prefs.IsNotNull())
280  {
281  prefs->OnChanged.RemoveListener(
283  &QmitkAbstractView::OnPreferencesChanged));
284  // flush the preferences here (disabled, everyone should flush them by themselves at the right moment)
285  // prefs->Flush();
286  }
287 
288  // REMOVE SELECTION PROVIDER
289  this->GetSite()->SetSelectionProvider(berry::ISelectionProvider::Pointer(nullptr));
290 
291  berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService();
292  if(s)
293  {
294  s->RemovePostSelectionListener(d->m_BlueBerrySelectionListener.data());
295  }
296 
297  this->UnRegister(false);
298 }
299 
300 void QmitkAbstractView::SetSelectionProvider()
301 {
302  // REGISTER A SELECTION PROVIDER
304  d->m_SelectionProvider->SetItemSelectionModel(GetDataNodeSelectionModel());
305  this->GetSite()->SetSelectionProvider(berry::ISelectionProvider::Pointer(d->m_SelectionProvider));
306 }
307 
308 QItemSelectionModel *QmitkAbstractView::GetDataNodeSelectionModel() const
309 {
310  return nullptr;
311 }
312 
313 void QmitkAbstractView::OnPreferencesChanged( const berry::IBerryPreferences* )
314 {
315 }
316 
317 void QmitkAbstractView::DataStorageModified()
318 {
319 }
320 
321 void QmitkAbstractView::DataStorageChanged(mitk::IDataStorageReference::Pointer /*dsRef*/)
322 {
323 }
324 
325 mitk::IRenderWindowPart* QmitkAbstractView::GetRenderWindowPart( IRenderWindowPartStrategies strategies ) const
326 {
327  berry::IWorkbenchPage::Pointer page = this->GetSite()->GetPage();
328 
329  // Return the active editor if it implements mitk::IRenderWindowPart
330  mitk::IRenderWindowPart* renderPart =
331  dynamic_cast<mitk::IRenderWindowPart*>(page->GetActiveEditor().GetPointer());
332  if (renderPart) return renderPart;
333 
334  // No suitable active editor found, check visible editors
335  QList<berry::IEditorReference::Pointer> editors = page->GetEditorReferences();
336  for (QList<berry::IEditorReference::Pointer>::iterator i = editors.begin();
337  i != editors.end(); ++i)
338  {
339  berry::IWorkbenchPart::Pointer part = (*i)->GetPart(false);
340  if (page->IsPartVisible(part))
341  {
342  renderPart = dynamic_cast<mitk::IRenderWindowPart*>(part.GetPointer());
343  if (renderPart) return renderPart;
344  }
345  }
346 
347  // No suitable visible editor found, check visible views
348  QList<berry::IViewReference::Pointer> views = page->GetViewReferences();
349  for(QList<berry::IViewReference::Pointer>::iterator i = views.begin();
350  i != views.end(); ++i)
351  {
352  berry::IWorkbenchPart::Pointer part = (*i)->GetPart(false);
353  if (page->IsPartVisible(part))
354  {
355  renderPart = dynamic_cast<mitk::IRenderWindowPart*>(part.GetPointer());
356  if (renderPart) return renderPart;
357  }
358  }
359 
360  // No strategies given
361  if (strategies == NONE) return nullptr;
362 
364 
365  bool activate = false;
366  if(strategies & ACTIVATE)
367  {
368  activate = true;
369  }
370 
371  berry::IEditorPart::Pointer editorPart;
372 
373  if(strategies & OPEN)
374  {
375  // This will create a default editor for the given input. If an editor
376  // with that input is already open, the editor is brought to the front.
377  try
378  {
379  editorPart = mitk::WorkbenchUtil::OpenEditor(page, input, activate);
380  }
381  catch (const berry::PartInitException&)
382  {
383  // There is no editor registered which can handle the given input.
384  }
385  }
386  else if (activate || (strategies & BRING_TO_FRONT))
387  {
388  // check if a suitable editor is already opened
389  editorPart = page->FindEditor(input);
390  if (editorPart)
391  {
392  if (activate)
393  {
394  page->Activate(editorPart);
395  }
396  else
397  {
398  page->BringToTop(editorPart);
399  }
400  }
401  }
402 
403  return dynamic_cast<mitk::IRenderWindowPart*>(editorPart.GetPointer());
404 }
405 
407 {
408  mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart();
409  if (renderPart == nullptr) return;
410 
411  if (mitk::IRenderingManager* renderingManager = renderPart->GetRenderingManager())
412  {
413  renderingManager->RequestUpdateAll(requestType);
414  }
415  else
416  {
417  renderPart->RequestUpdate(requestType);
418  }
419 }
420 
421 void QmitkAbstractView::HandleException( const char* str, QWidget* parent, bool showDialog ) const
422 {
423  //itkGenericOutputMacro( << "Exception caught: " << str );
424  MITK_ERROR << str;
425  if ( showDialog )
426  {
427  QMessageBox::critical ( parent, "Exception caught!", str );
428  }
429 }
430 
431 void QmitkAbstractView::HandleException( std::exception& e, QWidget* parent, bool showDialog ) const
432 {
433  HandleException( e.what(), parent, showDialog );
434 }
435 
437 {
438  QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
439 }
440 
442 {
443  QApplication::setOverrideCursor( QCursor(Qt::BusyCursor) );
444 }
445 
447 {
448  this->RestoreOverrideCursor();
449 }
450 
452 {
453  this->RestoreOverrideCursor();
454 }
455 
457 {
458  QApplication::restoreOverrideCursor();
459 }
460 
462 {
463  berry::IPreferencesService* prefService = d->m_PrefServiceTracker.getService();
464  // const_cast workaround for bad programming: const uncorrectness this->GetViewSite() should be const
465  QString id = "/" + (const_cast<QmitkAbstractView*>(this))->GetViewSite()->GetId();
466  return prefService ? prefService->GetSystemPreferences()->Node(id): berry::IPreferences::Pointer(nullptr);
467 }
468 
471 {
472  mitk::IDataStorageService* dsService = d->m_DataStorageServiceTracker.getService();
473 
474  if (dsService != nullptr)
475  {
476  return dsService->GetDataStorage()->GetDataStorage();
477  }
478 
479  return nullptr;
480 }
481 
483 {
484  mitk::IDataStorageService* dsService = d->m_DataStorageServiceTracker.getService();
485 
486  if (dsService != nullptr)
487  {
488  return dsService->GetDataStorage();
489  }
490 
491  return mitk::IDataStorageReference::Pointer(nullptr);
492 }
493 
494 QList<mitk::DataNode::Pointer> QmitkAbstractView::GetCurrentSelection() const
495 {
496  berry::ISelection::ConstPointer selection( this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection());
497  mitk::DataNodeSelection::ConstPointer currentSelection = selection.Cast<const mitk::DataNodeSelection>();
498  return d->DataNodeSelectionToQList(currentSelection);
499 }
500 
502 {
503  return this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection();
504 }
505 
506 QList<mitk::DataNode::Pointer> QmitkAbstractView::GetDataManagerSelection() const
507 {
508  berry::ISelection::ConstPointer selection( this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.datamanager"));
509  mitk::DataNodeSelection::ConstPointer currentSelection = selection.Cast<const mitk::DataNodeSelection>();
510  return d->DataNodeSelectionToQList(currentSelection);
511 }
512 
514 {
515  return this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.datamanager");
516 }
517 
519  QItemSelectionModel::SelectionFlags flags) const
520 {
521  berry::IViewPart::Pointer datamanagerView = this->GetSite()->GetWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.datamanager");
522  if (datamanagerView.IsNull()) return;
523 
524  datamanagerView->GetSite()->GetSelectionProvider().Cast<berry::QtSelectionProvider>()->SetSelection(selection, flags);
525 }
526 
528 {
529  berry::ISelection::ConstPointer currentSelection = this->GetSite()->GetSelectionProvider()->GetSelection();
530  if (currentSelection.IsNull()) return;
531 
532  SetDataManagerSelection(currentSelection);
533 }
534 
535 void QmitkAbstractView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/,
536  const QList<mitk::DataNode::Pointer>& /*nodes*/)
537 {
538 }
539 
540 void QmitkAbstractView::OnNullSelection(berry::IWorkbenchPart::Pointer /*part*/)
541 {
542 }
543 
544 QList<mitk::DataNode::Pointer> QmitkAbstractViewPrivate::DataNodeSelectionToQList(mitk::DataNodeSelection::ConstPointer currentSelection) const
545 {
546  if (currentSelection.IsNull()) return QList<mitk::DataNode::Pointer>();
547  return QList<mitk::DataNode::Pointer>::fromStdList(currentSelection->GetSelectedDataNodes());
548 }
549 
550 void QmitkAbstractView::NodeAdded( const mitk::DataNode* /*node*/ )
551 {
552 }
553 
554 void QmitkAbstractView::NodeRemoved( const mitk::DataNode* /*node*/ )
555 {
556 }
557 
558 void QmitkAbstractView::NodeChanged( const mitk::DataNode* /*node*/ )
559 {
560 }
561 
563 {
564  QList<mitk::DataNode::Pointer> nodes;
565  nodes << node;
566  this->FireNodesSelected(nodes);
567 }
568 
569 void QmitkAbstractView::FireNodesSelected( const QList<mitk::DataNode::Pointer>& nodes )
570 {
571  // if this is the first call to FireNodesSelected and the selection provider has no QItemSelectiomMode
572  // yet, set our helper model
573  if (d->m_SelectionProvider->GetItemSelectionModel() == nullptr)
574  {
575  d->m_SelectionProvider->SetItemSelectionModel(d->m_DataNodeSelectionModel);
576  }
577  else if (d->m_SelectionProvider->GetItemSelectionModel() != d->m_DataNodeSelectionModel)
578  {
579  MITK_WARN << "A custom data node selection model has been set. Ignoring call to FireNodesSelected().";
580  return;
581  }
582 
583  if (nodes.empty())
584  {
585  d->m_DataNodeSelectionModel->clearSelection();
586  d->m_DataNodeItemModel->clear();
587  }
588  else
589  {
590 
591  // The helper data node model is just used for sending selection events.
592  // We add the to be selected nodes and set the selection range to everything.
593 
594  d->m_DataNodeItemModel->clear();
595  foreach(mitk::DataNode::Pointer node, nodes)
596  {
597  d->m_DataNodeItemModel->AddDataNode(node);
598  }
599  d->m_DataNodeSelectionModel->select(QItemSelection(d->m_DataNodeItemModel->index(0,0), d->m_DataNodeItemModel->index(nodes.size()-1, 0)),
600  QItemSelectionModel::ClearAndSelect);
601  }
602 }
A BlueBerry selection provider for mitk::DataNode selections.
mitk::IRenderWindowPart * GetRenderWindowPart(IRenderWindowPartStrategies strategies=NONE) const
virtual void RemovePostSelectionListener(ISelectionListener *listener)=0
void Register() const
virtual void RequestUpdate(mitk::RenderingManager::RequestType requestType=mitk::RenderingManager::REQUEST_UPDATE_ALL)=0
void HandleException(std::exception &e, QWidget *parent=nullptr, bool showDialog=true) const
void FireNodeSelected(mitk::DataNode::Pointer node)
#define MITK_ERROR
Definition: mitkLogMacros.h:24
void UnRegister(bool del=true) const
berry::IPreferences::Pointer GetPreferences() const
virtual mitk::IRenderingManager * GetRenderingManager() const =0
void RequestRenderWindowUpdate(mitk::RenderingManager::RequestType requestType=mitk::RenderingManager::REQUEST_UPDATE_ALL)
virtual IDataStorageReference::Pointer GetDataStorage() const =0
void SetDataManagerSelection(const berry::ISelection::ConstPointer &selection, QItemSelectionModel::SelectionFlags flags=QItemSelectionModel::ClearAndSelect) const
Interface for a MITK Workbench Part providing a render window.
virtual SmartPointer< IPreferences > GetSystemPreferences()=0
virtual void FireNodesSelected(const QList< mitk::DataNode::Pointer > &nodes)
An editor input based on a mitk::DataStorage.
berry::SmartPointer< Self > Pointer
Definition: berryObject.h:88
virtual void CreateQtPartControl(QWidget *parent)=0
mitk::IDataStorageReference::Pointer GetDataStorageReference() const
#define MITK_WARN
Definition: mitkLogMacros.h:23
bool IsDataManagerSelectionValid() const
A convenient base class for MITK related BlueBerry Views.
bool IsCurrentSelectionValid() const
ObjectType * GetPointer() const
QList< mitk::DataNode::Pointer > GetDataManagerSelection() const
void SynchronizeDataManagerSelection() const
SmartPointer< Other > Cast() const
static berry::IEditorPart::Pointer OpenEditor(berry::IWorkbenchPage::Pointer page, berry::IEditorInput::Pointer input, const QString &editorId, bool activate=false)
mitk::DataStorage::Pointer GetDataStorage() const
berry::SmartPointer< Self > Pointer
An interface for accessing a mitk::RenderingManager instance.
QList< mitk::DataNode::Pointer > GetCurrentSelection() const
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
IWorkbenchPartSite::Pointer GetSite() const override