diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp index d075ccca6b..01b558111e 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp @@ -1,235 +1,250 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Qmitk -#include "QmitkRenderWindow.h" -#include "QmitkSliceNavigationListener.h" +#include +#include -#include "mitkIRenderWindowPart.h" +#include +#include // Qt #include #include ///********************************************** QmitkSliceNavigationListener::QmitkSliceNavigationListener() : m_renderWindowPart(nullptr), m_PendingSliceChangedEvent(false), m_CurrentSelectedPosition(std::numeric_limits::lowest()), m_CurrentSelectedTimePoint(std::numeric_limits::lowest()) { } QmitkSliceNavigationListener::~QmitkSliceNavigationListener() { this->RemoveAllObservers(); } mitk::TimePointType QmitkSliceNavigationListener::GetCurrentSelectedTimePoint() const { return m_CurrentSelectedTimePoint; } mitk::Point3D QmitkSliceNavigationListener::GetCurrentSelectedPosition() const { return m_CurrentSelectedPosition; } void QmitkSliceNavigationListener::OnSliceChangedDelayed() { m_PendingSliceChangedEvent = false; emit SliceChanged(); if (nullptr != m_renderWindowPart) { const auto newSelectedPosition = m_renderWindowPart->GetSelectedPosition(); - const auto newSelectedTimePoint = m_renderWindowPart->GetSelectedTimePoint(); if (newSelectedPosition != m_CurrentSelectedPosition) { m_CurrentSelectedPosition = newSelectedPosition; emit SelectedPositionChanged(newSelectedPosition); } - - if (newSelectedTimePoint != m_CurrentSelectedTimePoint) - { - m_CurrentSelectedTimePoint = newSelectedTimePoint; - emit SelectedTimePointChanged(newSelectedTimePoint); - } } } void QmitkSliceNavigationListener::OnSliceChangedInternal(const itk::EventObject&) { // Since there are always 3 events arriving (one for each render window) every time the slice // or time changes, the slot OnSliceChangedDelayed is triggered - and only if it hasn't been // triggered yet - so it is only executed once for every slice/time change. if (!m_PendingSliceChangedEvent) { m_PendingSliceChangedEvent = true; QTimer::singleShot(0, this, SLOT(OnSliceChangedDelayed())); } } +void QmitkSliceNavigationListener::OnTimeChangedInternal(itk::Object* sender, const itk::EventObject& e) +{ + if (!dynamic_cast(&e)) + { + return; + } + + const auto* timeNavigationController = dynamic_cast(sender); + if (nullptr == timeNavigationController) + { + return; + } + + const mitk::TimePointType newSelectedTimePoint = timeNavigationController->GetSelectedTimePoint(); + if (newSelectedTimePoint != m_CurrentSelectedTimePoint) + { + m_CurrentSelectedTimePoint = newSelectedTimePoint; + emit SelectedTimePointChanged(newSelectedTimePoint); + } +} + void QmitkSliceNavigationListener::OnSliceNavigationControllerDeleted(const itk::Object* sender, const itk::EventObject& /*e*/) { const mitk::SliceNavigationController* sendingSlicer = dynamic_cast(sender); this->RemoveObservers(sendingSlicer); } void QmitkSliceNavigationListener::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_renderWindowPart != renderWindowPart) { m_renderWindowPart = renderWindowPart; + auto* timeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); + itk::MemberCommand::Pointer cmdTimeEvent = + itk::MemberCommand::New(); + cmdTimeEvent->SetCallbackFunction(this, &QmitkSliceNavigationListener::OnTimeChangedInternal); + m_ControllerToTimeObserverTag = timeNavigationController->AddObserver(mitk::TimeNavigationController::TimeEvent(0), cmdTimeEvent); + if (!InitObservers()) { QMessageBox::information(nullptr, "Error", "Unable to set up the event observers."); } m_CurrentSelectedPosition = m_renderWindowPart->GetSelectedPosition(); - m_CurrentSelectedTimePoint = m_renderWindowPart->GetSelectedTimePoint(); + m_CurrentSelectedTimePoint = timeNavigationController->GetSelectedTimePoint(); } } void QmitkSliceNavigationListener::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { m_renderWindowPart = nullptr; this->RemoveAllObservers(renderWindowPart); } void QmitkSliceNavigationListener::RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) { if (m_renderWindowPart == renderWindowPart) { if (!InitObservers()) { QMessageBox::information(nullptr, "Error", "Unable to set up the event observers."); } m_CurrentSelectedPosition = m_renderWindowPart->GetSelectedPosition(); - m_CurrentSelectedTimePoint = m_renderWindowPart->GetSelectedTimePoint(); + + const auto* timeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); + m_CurrentSelectedTimePoint = timeNavigationController->GetSelectedTimePoint(); } } bool QmitkSliceNavigationListener::InitObservers() { bool result = true; typedef QHash WindowMapType; WindowMapType windowMap = m_renderWindowPart->GetQmitkRenderWindows(); auto i = windowMap.begin(); while (i != windowMap.end()) { - mitk::SliceNavigationController* sliceNavController = - i.value()->GetSliceNavigationController(); + mitk::SliceNavigationController* sliceNavController = i.value()->GetSliceNavigationController(); - if (sliceNavController) + if (nullptr != sliceNavController) { bool observersInitialized = this->ObserversInitialized(sliceNavController); - if(false == observersInitialized) + if (false == observersInitialized) { itk::ReceptorMemberCommand::Pointer cmdSliceEvent = itk::ReceptorMemberCommand::New(); cmdSliceEvent->SetCallbackFunction(this, &QmitkSliceNavigationListener::OnSliceChangedInternal); int tag = sliceNavController->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), cmdSliceEvent); m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, i.key().toStdString(), m_renderWindowPart))); - itk::ReceptorMemberCommand::Pointer cmdTimeEvent = - itk::ReceptorMemberCommand::New(); - cmdTimeEvent->SetCallbackFunction(this, &QmitkSliceNavigationListener::OnSliceChangedInternal); - tag = sliceNavController->AddObserver( - mitk::SliceNavigationController::GeometryTimeEvent(nullptr, 0), - cmdTimeEvent); - - m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, - i.key().toStdString(), m_renderWindowPart))); - itk::ReceptorMemberCommand::Pointer cmdUpdateEvent = itk::ReceptorMemberCommand::New(); cmdUpdateEvent->SetCallbackFunction(this, &QmitkSliceNavigationListener::OnSliceChangedInternal); tag = sliceNavController->AddObserver( mitk::SliceNavigationController::GeometryUpdateEvent(nullptr, 0), cmdUpdateEvent); m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, i.key().toStdString(), m_renderWindowPart))); itk::MemberCommand::Pointer cmdDelEvent = itk::MemberCommand::New(); cmdDelEvent->SetCallbackFunction(this, &QmitkSliceNavigationListener::OnSliceNavigationControllerDeleted); tag = sliceNavController->AddObserver( itk::DeleteEvent(), cmdDelEvent); m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, i.key().toStdString(), m_renderWindowPart))); } } ++i; result = result && sliceNavController; } return result; } void QmitkSliceNavigationListener::RemoveObservers(const mitk::SliceNavigationController* deletedSlicer) { std::pair < ObserverMapType::const_iterator, ObserverMapType::const_iterator> obsRange = m_ObserverMap.equal_range(deletedSlicer); for (ObserverMapType::const_iterator pos = obsRange.first; pos != obsRange.second; ++pos) { pos->second.controller->RemoveObserver(pos->second.observerTag); } m_ObserverMap.erase(deletedSlicer); } void QmitkSliceNavigationListener::RemoveAllObservers(mitk::IRenderWindowPart* deletedPart) { for (ObserverMapType::const_iterator pos = m_ObserverMap.begin(); pos != m_ObserverMap.end();) { ObserverMapType::const_iterator delPos = pos++; if (deletedPart == nullptr || deletedPart == delPos->second.renderWindowPart) { delPos->second.controller->RemoveObserver(delPos->second.observerTag); m_ObserverMap.erase(delPos); } } + + auto* timeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); + timeNavigationController->RemoveObserver(m_ControllerToTimeObserverTag); } bool QmitkSliceNavigationListener::ObserversInitialized(mitk::SliceNavigationController* controller) { auto it = m_ObserverMap.find(controller); return it != m_ObserverMap.end(); } QmitkSliceNavigationListener::ObserverInfo::ObserverInfo(mitk::SliceNavigationController* controller, int observerTag, const std::string& renderWindowName, mitk::IRenderWindowPart* part) : controller(controller), observerTag(observerTag), renderWindowName(renderWindowName), renderWindowPart(part) { } diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h index a014d14a49..d075f60572 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h @@ -1,135 +1,137 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkSliceNavigationListener_h #define QmitkSliceNavigationListener_h #include #include #include #include #include namespace itk { class Object; } namespace mitk { class SliceNavigationController; struct IRenderWindowPart; } /** @brief Helper class to allow QmitkAbstractView and derived classes to react on changes of the slice/time navigation. Purpose of the class to be used in view and to give the respective view class (by composition) the posibility to react on changes of the currently selected timepoint or position in the world geometry.\n It also offers convinient signals that are only triggered when the selected timepoint or the selected possition of the active render window have realy changed.\n In order to setup this class properly the following things must be regarded: - View class must also derive public from mitk::IRenderWindowPartListener - View class must implement void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) and pass the renderWindowPart to the listener. void QmitkMyView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceNavigationListener.RenderWindowPartActivated(renderWindowPart); } - View class must implement void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) and pass the renderWindowPart to the listener. void QmitkMyView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceNavigationListener.RenderWindowPartDeactivated(renderWindowPart); } - View class must pass its on render window part in its CreateQtPartControl(QWidget* parent) this->m_SliceNavigationListener.RenderWindowPartActivated(this->GetRenderWindowPart()); - View class must connect the SliceChanged signal of the listener as see fit. */ class MITK_QT_COMMON QmitkSliceNavigationListener : public QObject { Q_OBJECT public: QmitkSliceNavigationListener(); ~QmitkSliceNavigationListener() override; mitk::TimePointType GetCurrentSelectedTimePoint() const; mitk::Point3D GetCurrentSelectedPosition() const; signals: /** Signal triggered as soon as there is any change. It may be a change in the position/slice or of the selected timepoint.*/ void SliceChanged(); /** Convinience signal that can be used if you are only interested in changes of the current selected time point. Changes in spatial position will be ignored.*/ void SelectedTimePointChanged(const mitk::TimePointType& newTimePoint); /** Convinience signal that can be used if you are only interested in changes of the current selected position. Changes in time will be ignored.*/ void SelectedPositionChanged(const mitk::Point3D& newPoint); public slots: void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart); void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart); void RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart); protected slots: /** Overwrite function to implement the behavior on slice/time changes. */ void OnSliceChangedDelayed(); protected: /** @brief Calls OnSliceChangedDelayed so the event isn't triggered multiple times. */ void OnSliceChangedInternal(const itk::EventObject& e); + void OnTimeChangedInternal(itk::Object* sender, const itk::EventObject& e); void OnSliceNavigationControllerDeleted(const itk::Object* sender, const itk::EventObject& /*e*/); /** Initializes and sets the observers that are used to monitor changes in the selected position or time point in order to actualize the view.h*/ bool InitObservers(); void RemoveObservers(const mitk::SliceNavigationController* deletedSlicer); /** Removes all observers of the deletedPart. If null pointer is passed all observers will be removed.*/ void RemoveAllObservers(mitk::IRenderWindowPart* deletedPart = nullptr); bool ObserversInitialized(mitk::SliceNavigationController* controller); mitk::IRenderWindowPart* m_renderWindowPart; // Needed for observing the events for when a slice or time step is changed. bool m_PendingSliceChangedEvent; /**Helper structure to manage the registered observer events.*/ struct ObserverInfo { mitk::SliceNavigationController* controller; int observerTag; std::string renderWindowName; mitk::IRenderWindowPart* renderWindowPart; ObserverInfo(mitk::SliceNavigationController* controller, int observerTag, const std::string& renderWindowName, mitk::IRenderWindowPart* part); }; typedef std::multimap ObserverMapType; ObserverMapType m_ObserverMap; + unsigned int m_ControllerToTimeObserverTag; mitk::Point3D m_CurrentSelectedPosition; mitk::TimePointType m_CurrentSelectedTimePoint; }; #endif