diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp index 2c99bda38c..d075ccca6b 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp @@ -1,213 +1,235 @@ /*============================================================================ 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 "mitkIRenderWindowPart.h" // 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::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; if (!InitObservers()) { - QMessageBox::information(nullptr, "Error", "Unable to set up the event observers. The " \ - "plot will not be triggered on changing the crosshair, " \ - "position or time step."); + QMessageBox::information(nullptr, "Error", "Unable to set up the event observers."); } m_CurrentSelectedPosition = m_renderWindowPart->GetSelectedPosition(); m_CurrentSelectedTimePoint = m_renderWindowPart->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(); + } +} + 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(); if (sliceNavController) { - 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))); + bool observersInitialized = this->ObserversInitialized(sliceNavController); + 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); } } } +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 885aa590b1..07a7b37cde 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h @@ -1,133 +1,136 @@ /*============================================================================ 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 __Q_MITK_SLICE_NAVIGATION_LISTENER_H #define __Q_MITK_SLICE_NAVIGATION_LISTENER_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 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; mitk::Point3D m_CurrentSelectedPosition; mitk::TimePointType m_CurrentSelectedTimePoint; }; #endif diff --git a/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.cpp b/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.cpp index be39b1f658..6c76d46de3 100644 --- a/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.cpp +++ b/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.cpp @@ -1,187 +1,192 @@ /*============================================================================ 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. ============================================================================*/ #include "QmitkPixelValueView.h" #include #include #include #include #include #include const std::string QmitkPixelValueView::VIEW_ID = "org.mitk.views.pixelvalue"; QmitkPixelValueView::QmitkPixelValueView(QObject*) : m_Ui(new Ui::QmitkPixelValueView) { } QmitkPixelValueView::~QmitkPixelValueView() { } void QmitkPixelValueView::CreateQtPartControl(QWidget* parent) { m_Ui->setupUi(parent); this->m_SliceNavigationListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceNavigationListener, &QmitkSliceNavigationListener::SelectedPositionChanged, this, &QmitkPixelValueView::OnSelectedPositionChanged); connect(&m_SliceNavigationListener, &QmitkSliceNavigationListener::SelectedTimePointChanged, this, &QmitkPixelValueView::OnSelectedTimePointChanged); this->Update(); } void QmitkPixelValueView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceNavigationListener.RenderWindowPartActivated(renderWindowPart); } void QmitkPixelValueView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceNavigationListener.RenderWindowPartDeactivated(renderWindowPart); } +void QmitkPixelValueView::RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) +{ + this->m_SliceNavigationListener.RenderWindowPartInputChanged(renderWindowPart); +} + void QmitkPixelValueView::OnSelectedPositionChanged(const mitk::Point3D&) { this->Update(); } void QmitkPixelValueView::OnSelectedTimePointChanged(const mitk::TimePointType&) { this->Update(); } void QmitkPixelValueView::NodeChanged(const mitk::DataNode*) { this->Update(); } void QmitkPixelValueView::Update() { const auto position = m_SliceNavigationListener.GetCurrentSelectedPosition(); const auto timePoint = m_SliceNavigationListener.GetCurrentSelectedTimePoint(); auto isImageData = mitk::TNodePredicateDataType::New(); auto nodes = GetDataStorage()->GetSubset(isImageData); if (nodes.IsNull()) { this->Clear(); return; } mitk::Image::Pointer image; mitk::DataNode::Pointer topParentNode; int component = 0; auto node = mitk::FindTopmostVisibleNode(nodes, position, timePoint, nullptr); if (node.IsNull()) { this->Clear(); return; } bool isBinary = false; node->GetBoolProperty("binary", isBinary); if (isBinary) { auto parentNodes = GetDataStorage()->GetSources(node, nullptr, true); if (!parentNodes->empty()) topParentNode = FindTopmostVisibleNode(nodes, position, timePoint, nullptr); if (topParentNode.IsNotNull()) { image = dynamic_cast(topParentNode->GetData()); topParentNode->GetIntProperty("Image.Displayed Component", component); } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } if (image.IsNotNull()) { m_Ui->imageNameLineEdit->setText(QString::fromStdString(node->GetName())); itk::Index<3> index; image->GetGeometry()->WorldToIndex(position, index); auto pixelType = image->GetChannelDescriptor().GetPixelType().GetPixelType(); if (pixelType == itk::IOPixelEnum::RGB || pixelType == itk::IOPixelEnum::RGBA) { m_Ui->pixelValueLineEdit->setText(QString::fromStdString(mitk::ConvertCompositePixelValueToString(image, index))); return; } if (pixelType == itk::IOPixelEnum::DIFFUSIONTENSOR3D || pixelType == itk::IOPixelEnum::SYMMETRICSECONDRANKTENSOR) { m_Ui->pixelValueLineEdit->setText(QStringLiteral("See ODF Details view.")); return; } mitk::ScalarType pixelValue = 0.0; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(image->GetTimeGeometry()->TimePointToTimeStep(timePoint)), index, pixelValue, component); std::ostringstream stream; stream.imbue(std::locale::classic()); stream.precision(2); if (fabs(pixelValue) > 1000000 || fabs(pixelValue) < 0.01) { stream << std::scientific; } else { stream << std::fixed; } stream << pixelValue; m_Ui->pixelValueLineEdit->setText(QString::fromStdString(stream.str())); } else { this->Clear(); } } void QmitkPixelValueView::Clear() { m_Ui->imageNameLineEdit->clear(); m_Ui->pixelValueLineEdit->clear(); } void QmitkPixelValueView::SetFocus() { } diff --git a/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.h b/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.h index 0066df315e..989dbb5994 100644 --- a/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.h +++ b/Plugins/org.mitk.gui.qt.pixelvalue/src/internal/QmitkPixelValueView.h @@ -1,56 +1,57 @@ /*============================================================================ 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 QmitkPixelValueView_h #define QmitkPixelValueView_h #include #include #include namespace Ui { class QmitkPixelValueView; } class QmitkPixelValueView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; QmitkPixelValueView(QObject* parent = nullptr); ~QmitkPixelValueView() override; void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; private: void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; + void RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) override; void OnSelectedPositionChanged(const mitk::Point3D& position); void OnSelectedTimePointChanged(const mitk::TimePointType& timePoint); void NodeChanged(const mitk::DataNode* node) override; void Clear(); void Update(); QmitkSliceNavigationListener m_SliceNavigationListener; Ui::QmitkPixelValueView* m_Ui; }; #endif