Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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