diff --git a/Modules/Core/include/mitkLevelWindowManager.h b/Modules/Core/include/mitkLevelWindowManager.h index 8101380fdf..3e8826d6b3 100644 --- a/Modules/Core/include/mitkLevelWindowManager.h +++ b/Modules/Core/include/mitkLevelWindowManager.h @@ -1,161 +1,219 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef mitkLevelWindowManager_h -#define mitkLevelWindowManager_h +#ifndef MITKLEVELWINDOWMANAGER_H +#define MITKLEVELWINDOWMANAGER_H +// mitk core #include "mitkBaseProperty.h" #include "mitkDataStorage.h" #include "mitkLevelWindowProperty.h" + +// c++ #include #include namespace mitk { /** - \brief Provides access to the LevelWindowProperty object and LevelWindow of the "current" image. + @brief Provides access to the LevelWindowProperty object and LevelWindow of the "current" image. - provides a LevelWindowProperty for purposes like GUI editors - this property comes from one of two possible sources - either something (e.g. the application) sets the property because of some user selection - OR the "Auto top-most" logic is used to search a DataStorage for the image with the highest "layer" property - value + value Changes on Level/Window can be set with SetLevelWindow() and will affect either the topmost layer image, if isAutoTopMost() returns true, or an image which is set by SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty). Changes to Level/Window, when another image gets active or by SetLevelWindow(const LevelWindow& levelWindow), will be sent to all listeners by Modified(). DataStorageChanged() listens to the DataStorage for new or removed images. Depending on how m_AutoTopMost is set, the new image becomes active or not. If an image is removed from the DataStorage and m_AutoTopMost is false, there is a check to proof, if the active image is still available. If not, then m_AutoTopMost becomes true. Note that this class is not thread safe at the moment! */ - class MITKCORE_EXPORT LevelWindowManager : public itk::Object { public: - mitkClassMacroItkParent(LevelWindowManager, itk::Object) itkFactorylessNewMacro(Self) itkCloneMacro(Self) - - void SetDataStorage(DataStorage *ds); - DataStorage *GetDataStorage(); ///< returns the datastorage - /** @brief (Re-)Initializes the LevelWindowManager by setting the topmost image. - * Use the removedNode parameter if a node was removed... - * @param autoTopMost true: sets the topmost layer image to be affected by changes - * @param removedNode != nullptr a node was removed from DataStorage */ - void SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode = nullptr); + mitkClassMacroItkParent(LevelWindowManager, itk::Object) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) - void RecaluclateLevelWindowForSelectedComponent(const itk::EventObject &); + void SetDataStorage(DataStorage *ds); + DataStorage *GetDataStorage(); - void Update(const itk::EventObject &e); ///< gets called if a visible property changes + /** + * @brief (Re-)Initialize the LevelWindowManager by setting the topmost image. + * Use the removedNode parameter if a node was removed. + * + * @param autoTopMost Set the topmost layer image to be affected by changes, if true. + * @param removedNode A node was removed from the data storage if != nullptr. + */ + void SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode = nullptr); + /** + * @brief (Re-)Initialize the LevelWindowManager by setting the selected images. + * Use the removedNode parameter if a node was removed. + * + * @param selectedImagesMode Set the selected images to be affected by changes, if true. + * @param removedNode A node was removed from the data storage if != nullptr. + */ + void SetSelectedImages(bool selectedImagesMode, const DataNode *removedNode = nullptr); - /** @brief Sets an specific LevelWindowProperty, all changes will affect the image belonging to this property. - * @throw mitk::Exception Throws an exception if the there is no image in the data storage which belongs to this - * property.*/ + void RecalculateLevelWindowForSelectedComponent(const itk::EventObject&); + /** + * @brief Update the level window. + * This function is called if a property of a data node is changed. + * Relevant properties are defined in the protected 'ObserverToPropertyValueMap'-members. + */ + void Update(const itk::EventObject&); + /** + * @brief Update the level window. + * This function is only called if the 'selected' property of a data node is changed. + * This is done in order to avoid finding the correct image each time a node is selected but + * the 'm_SelectedImages' bool value is set to false (as the normal 'Update'-function would do). + * Changes of the 'selected' property happen quite a lot so this should not slow down the application. + */ + void UpdateSelected(const itk::EventObject&); + /** + * @brief Set a specific LevelWindowProperty; all changes will affect the image belonging to this property. + * @throw mitk::Exception Throw an exception if the there is no image in the data storage which belongs to this + * property. + */ void SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty); - - /** @brief Sets new Level/Window values and informs all listeners about changes. */ + /** + * @brief Set new Level/Window values and inform all listeners about changes. + */ void SetLevelWindow(const LevelWindow &levelWindow); - - /** @return Returns Level/Window values for the current image.*/ - const LevelWindow &GetLevelWindow(); - - /** @return Returns the current mitkLevelWindowProperty object from the image that is affected by changes.*/ + /** + * @brief Return the current LevelWindowProperty object from the image that is affected by changes. + * + * @return The current LevelWindowProperty + */ LevelWindowProperty::Pointer GetLevelWindowProperty(); - - /** @return true if changes on slider or line-edits will affect always the topmost layer image. */ - bool isAutoTopMost(); - + /** + * @brief Return Level/Window values for the current image + * + * @return The LevelWindow value for the current image. + */ + const LevelWindow &GetLevelWindow(); + /** + * @brief Return true, if the changes on slider or line-edits will affect the topmost layer image. + * + * @return Return the member value that denotes the auto-topmost mode. + */ + bool IsAutoTopMost(); + /** + * @brief Return true, if changes on slider or line-edits will affect the currently selected images. + * + * @return Return the member value that denotes the selected-images mode. + */ + bool IsSelectedImages(); /** @brief This method is called when a node is added to the data storage. - * A listener on the data storage is used to call this method automatically after a node was added. - * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from - * the - * number of nodes. - */ + * A listener on the data storage is used to call this method automatically after a node was added. + * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from + * the number of nodes. + */ void DataStorageAddedNode(const DataNode *n = nullptr); - /** @brief This method is called when a node is removed to the data storage. - * A listener on the data storage is used to call this method automatically directly before a node will be - * removed. - * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from - * the - * number of nodes. - */ + * A listener on the data storage is used to call this method automatically directly before a node will be + * removed. + * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from + * the number of nodes. + */ void DataStorageRemovedNode(const DataNode *removedNode = nullptr); - - /** @brief change notifications from mitkLevelWindowProperty */ + /** + * @brief Change notifications from mitkLevelWindowProperty. + */ void OnPropertyModified(const itk::EventObject &e); - - Image *GetCurrentImage(); ///< return the currently active image - + /** + * @brief Return the currently active image. + * + * @return The member variable holding the currently active image. + */ + Image *GetCurrentImage(); /** * @return Returns the current number of observers which are registered in this object. * @throw mitk::Exception Throws an exception if the number of observers differs from * the number of relevant objects * which means that something is wrong. * */ int GetNumberOfObservers(); /** - * returns all nodes in the DataStorage that have the following properties: - * "visible" == true, "binary" == false, "levelwindow", and DataType == Image + * @brief Returns all nodes in the DataStorage that have the following properties: + * - "binary" == false + * - "levelwindow" + * - DataType == Image / DiffusionImage / TensorImage / OdfImage / ShImage */ DataStorage::SetOfObjects::ConstPointer GetRelevantNodes(); protected: LevelWindowManager(); ~LevelWindowManager() override; DataStorage::Pointer m_DataStorage; - LevelWindowProperty::Pointer m_LevelWindowProperty; ///< pointer to the LevelWindowProperty of the current image + /// Pointer to the LevelWindowProperty of the current image. + LevelWindowProperty::Pointer m_LevelWindowProperty; + typedef std::pair PropDataPair; - typedef std::map ObserverToPropertyMap; - - ObserverToPropertyMap - m_PropObserverToNode; ///< map to hold observer IDs to every visible property of DataNode�s BaseProperty - ObserverToPropertyMap - m_PropObserverToNode2; ///< map to hold observer IDs to every layer property of DataNode�s BaseProperty - ObserverToPropertyMap m_PropObserverToNode3; ///< map to hold observer IDs to every Image Rendering.Mode property of - /// DataNode�s BaseProperty - ObserverToPropertyMap - m_PropObserverToNode4; ///< map to hold observer IDs to every Image.Displayed Component property - /// of DataNode�s BaseProperty - ObserverToPropertyMap - m_PropObserverToNode5; ///< map to hold observer IDs to every image for level window property of - /// DataNode�s BaseProperty - - void UpdateObservers(); ///< updates the internal observer list. Ignores nodes which are marked to be deleted in the - /// variable m_NodeMarkedToDelete - void ClearPropObserverLists(); ///< internal help method to clear both lists/maps. - void CreatePropObserverLists(); ///< internal help method to create both lists/maps. - const mitk::DataNode *m_NodeMarkedToDelete; ///< this variable holds a data node which will be deleted from the - /// datastorage immedeately (if there is one, nullptr otherways) + typedef std::map ObserverToPropertyValueMap; + /// Map to hold observer IDs to every "visible" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToVisibleProperty; + /// Map to hold observer IDs to every "layer" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToLayerProperty; + /// Map to hold observer IDs to every "Image Rendering.Mode" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToRenderingModeProperty; + /// Map to hold observer IDs to every "Image.Displayed Component" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToDisplayedComponentProperty; + /// Map to hold observer IDs to every "imageForLevelWindow" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToLevelWindowImageProperty; + /// Map to hold observer IDs to every "selected" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToSelectedProperty; + + /// Updates the internal observer list. + /// Ignores nodes which are marked to be deleted in the variable m_NodeMarkedToDelete. + void UpdateObservers(); + /// Internal help method to clear both lists/maps. + void ClearPropObserverLists(); + /// Internal help method to create both lists/maps. + void CreatePropObserverLists(); + + bool IgnoreNode(const DataNode* dataNode); + + /// This variable holds a data node which will be deleted from the datastorage immediately + /// Nullptr, if there is no data node to be deleted. + const DataNode *m_NodeMarkedToDelete; bool m_AutoTopMost; + bool m_SelectedImagesMode; unsigned long m_ObserverTag; bool m_IsObserverTagSet; unsigned long m_PropertyModifiedTag; Image *m_CurrentImage; + std::vector m_RelevantDataNodes; bool m_IsPropertyModifiedTagSet; - bool m_SettingImgForLvlWinProp; + bool m_LevelWindowMutex; }; } -#endif + +#endif // MITKLEVELWINDOWMANAGER_H diff --git a/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp b/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp index 08c201f25f..740638f157 100644 --- a/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp +++ b/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp @@ -1,624 +1,741 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkLevelWindowManager.h" #include "mitkDataStorage.h" #include "mitkImage.h" #include "mitkMessage.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateProperty.h" #include "mitkProperties.h" #include "mitkRenderingModeProperty.h" #include mitk::LevelWindowManager::LevelWindowManager() - : m_DataStorage(nullptr), - m_LevelWindowProperty(nullptr), - m_AutoTopMost(true), - m_IsObserverTagSet(false), - m_CurrentImage(nullptr), - m_IsPropertyModifiedTagSet(false), - m_SettingImgForLvlWinProp(false) + : m_DataStorage(nullptr) + , m_LevelWindowProperty(nullptr) + , m_AutoTopMost(true) + , m_SelectedImagesMode(false) + , m_IsObserverTagSet(false) + , m_CurrentImage(nullptr) + , m_IsPropertyModifiedTagSet(false) + , m_LevelWindowMutex(false) { } mitk::LevelWindowManager::~LevelWindowManager() { if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); m_DataStorage = nullptr; } if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } // clear both observer maps this->ClearPropObserverLists(); } -void mitk::LevelWindowManager::SetDataStorage(mitk::DataStorage *ds) +void mitk::LevelWindowManager::SetDataStorage(DataStorage *ds) { if (ds == nullptr) return; /* remove listeners of old DataStorage */ if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); } /* register listener for new DataStorage */ m_DataStorage = ds; // register m_DataStorage->AddNodeEvent.AddListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.AddListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); this->DataStorageAddedNode(); // update us with new DataStorage } -void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject &) +mitk::DataStorage *mitk::LevelWindowManager::GetDataStorage() { - Modified(); + return m_DataStorage.GetPointer(); } -void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode *removedNode) +void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode/* = nullptr*/) { m_AutoTopMost = autoTopMost; - if (m_AutoTopMost == false) + if (false == m_AutoTopMost) + { return; + } + + // deactivate other mode + m_SelectedImagesMode = false; if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } - /* search topmost image */ + // find topmost image in the data storage if (m_DataStorage.IsNull()) { - itkExceptionMacro("DataStorage not set"); + mitkThrow() << "DataStorage not set"; } - int maxLayer = itk::NumericTraits::min(); + DataNode::Pointer topLevelNode; + int maxVisibleLayer = itk::NumericTraits::min(); m_LevelWindowProperty = nullptr; + m_CurrentImage = nullptr; - mitk::DataNode::Pointer topLevelNode; - - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { - mitk::DataNode::Pointer node = it->Value(); - if (node.IsNull() || (removedNode != nullptr && node == removedNode)) + DataNode::Pointer node = it->Value(); + if (node.IsNull() || node == removedNode) + { continue; + } - m_SettingImgForLvlWinProp = true; + m_LevelWindowMutex = true; node->SetBoolProperty("imageForLevelWindow", false); - m_SettingImgForLvlWinProp = false; + m_LevelWindowMutex = false; - if (node->IsVisible(nullptr) == false) + if (false == node->IsVisible(nullptr)) + { continue; + } - int layer = 0; + int layer = -1; node->GetIntProperty("layer", layer); - if (layer < maxLayer) + if (layer < maxVisibleLayer) + { + continue; + } + + bool ignore = this->IgnoreNode(node); + if (ignore) + { + continue; + } + + m_LevelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); + topLevelNode = node; + maxVisibleLayer = layer; + } + + // this will set the "imageForLevelWindow" property and the 'm_CurrentImage' and call 'Modified()' + this->SetLevelWindowProperty(m_LevelWindowProperty); + + if (m_LevelWindowProperty.IsNull()) + { + this->Modified(); + } +} + +void mitk::LevelWindowManager::SetSelectedImages(bool selectedImagesMode, const DataNode *removedNode/* = nullptr*/) +{ + m_SelectedImagesMode = selectedImagesMode; + if (false == m_SelectedImagesMode) + { + return; + } + + // deactivate other mode + m_AutoTopMost = false; + + if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) + { + m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); + m_IsPropertyModifiedTagSet = false; + } + + // find selected images in the data storage + if (m_DataStorage.IsNull()) + { + mitkThrow() << "DataStorage not set"; + } + + DataNode::Pointer lastSelectedNode; + m_LevelWindowProperty = nullptr; + m_CurrentImage = nullptr; + + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + { + DataNode::Pointer node = it->Value(); + if (node.IsNull() || node == removedNode) + { continue; + } + + m_LevelWindowMutex = true; + node->SetBoolProperty("imageForLevelWindow", false); + m_LevelWindowMutex = false; - mitk::LevelWindowProperty::Pointer levelWindowProperty = - dynamic_cast(node->GetProperty("levelwindow")); - if (levelWindowProperty.IsNull()) + if (false == node->IsSelected()) + { continue; + } - int nonLvlWinMode1 = mitk::RenderingModeProperty::LOOKUPTABLE_COLOR; - int nonLvlWinMode2 = mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR; + bool ignore = this->IgnoreNode(node); + if (ignore) + { + continue; + } - mitk::RenderingModeProperty::Pointer mode = - dynamic_cast(node->GetProperty("Image Rendering.Mode")); + m_LevelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); + m_RelevantDataNodes.push_back(node); + lastSelectedNode = node; + } + + // this will set the "imageForLevelWindow" property and the 'm_CurrentImage' and call 'Modified()' + this->SetLevelWindowProperty(m_LevelWindowProperty); + + if (m_LevelWindowProperty.IsNull()) + { + this->Modified(); + } +} - if (mode.IsNotNull()) +void mitk::LevelWindowManager::RecalculateLevelWindowForSelectedComponent(const itk::EventObject &event) +{ + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + { + DataNode::Pointer node = it->Value(); + if (node.IsNull()) + continue; + + bool isSelected = false; + node->GetBoolProperty("selected", isSelected); + if (isSelected) { - int currMode = mode->GetRenderingMode(); - if (currMode == nonLvlWinMode1 || currMode == nonLvlWinMode2) - { - continue; + LevelWindow selectedLevelWindow; + node->GetLevelWindow(selectedLevelWindow); // node is an image node because of predicates + + auto *image = dynamic_cast(node->GetData()); + int displayedComponent = 0; + if (image && (node->GetIntProperty("Image.Displayed Component", displayedComponent))) + { // we found a selected image with a displayed component + // let's recalculate the levelwindow for this. + selectedLevelWindow.SetAuto(image, true, true, static_cast(displayedComponent)); + node->SetLevelWindow(selectedLevelWindow); } } - else + + LevelWindow levelWindow; + node->GetLevelWindow(levelWindow); + } + + this->Update(event); +} + +void mitk::LevelWindowManager::Update(const itk::EventObject &) +{ + if (m_LevelWindowMutex) // no mutex, should still help + { + return; + } + + m_RelevantDataNodes.clear(); + if (m_AutoTopMost) + { + this->SetAutoTopMostImage(true); + return; + } + + if (m_SelectedImagesMode) + { + this->SetSelectedImages(true); + return; + } + + int maxVisibleLayer = itk::NumericTraits::min(); + DataNode::Pointer topLevelNode = nullptr; + std::vector nodesForLevelWindow; + + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + { + DataNode::Pointer node = it->Value(); + + if (node.IsNull()) + { continue; + } - m_LevelWindowProperty = levelWindowProperty; - m_CurrentImage = dynamic_cast(node->GetData()); - topLevelNode = node; + if (node->IsVisible(nullptr) == false) + { + continue; + } + + bool prop = false; + node->GetBoolProperty("imageForLevelWindow", prop); + if (prop) + { + nodesForLevelWindow.push_back(node); + continue; + } - maxLayer = layer; + int layer = -1; + node->GetIntProperty("layer", layer); + if (layer > maxVisibleLayer) + { + // top level node is backup node, if no node with + // "imageForLevelWindow" property with value "true" is found + topLevelNode = node; + maxVisibleLayer = layer; + } } - if (topLevelNode.IsNotNull()) + int nodesForLevelWindowSize = nodesForLevelWindow.size(); + if (nodesForLevelWindowSize > 2) { - m_SettingImgForLvlWinProp = true; - topLevelNode->SetBoolProperty("imageForLevelWindow", true); - m_SettingImgForLvlWinProp = false; + MITK_ERROR << "Error: not more than two visible nodes are expected to have the imageForLevelWindow property set at " + "any point."; } - this->SetLevelWindowProperty(m_LevelWindowProperty); + if (nodesForLevelWindowSize > 0) + { + // 1 or 2 nodes for level window found + for (const auto& node : nodesForLevelWindow) + { + LevelWindowProperty::Pointer newProp = dynamic_cast(node->GetProperty("levelwindow")); + if (newProp != m_LevelWindowProperty) + { + this->SetLevelWindowProperty(newProp); + return; + } + } + } + else if (topLevelNode) + { + // no nodes for level window found + LevelWindowProperty::Pointer lvlProp = dynamic_cast(topLevelNode->GetProperty("levelwindow")); + this->SetLevelWindowProperty(lvlProp); + } + else + { + // no nodes for level window found and no visible top level node found + this->Modified(); + } +} - if (m_LevelWindowProperty.IsNull()) +void mitk::LevelWindowManager::UpdateSelected(const itk::EventObject &) +{ + if (m_LevelWindowMutex) // no mutex, should still help { - Modified(); + return; + } + + m_RelevantDataNodes.clear(); + if (m_SelectedImagesMode) + { + this->SetSelectedImages(true); } - // else SetLevelWindowProperty will call Modified(); } -// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property. void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty) { if (levelWindowProperty.IsNull()) + { return; + } - /* search image than belongs to the property */ - typedef mitk::DataStorage::SetOfObjects NodeSetType; - NodeSetType::ConstPointer nodes = m_DataStorage->GetAll(); - NodeSetType::ConstIterator it = nodes->Begin(); + // find data node that belongs to the property + DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetAll(); mitk::DataNode::Pointer propNode = nullptr; - while (it != nodes->End()) + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { - mitk::DataNode::Pointer node = it.Value(); - mitk::LevelWindowProperty::Pointer prop = - dynamic_cast(node->GetProperty("levelwindow")); - if (prop == levelWindowProperty) + DataNode::Pointer node = it.Value(); + LevelWindowProperty::Pointer property = dynamic_cast(node->GetProperty("levelwindow")); + if (property == levelWindowProperty) { propNode = node; } else { - m_SettingImgForLvlWinProp = true; + m_LevelWindowMutex = true; node->SetBoolProperty("imageForLevelWindow", false); - m_SettingImgForLvlWinProp = false; + m_LevelWindowMutex = false; } - - ++it; } if (propNode.IsNull()) { - mitkThrow() << "No Image in DataStorage that belongs to LevelWindow property" << m_LevelWindowProperty; + mitkThrow() << "No Image in the data storage that belongs to level-window property " << m_LevelWindowProperty; } if (m_IsPropertyModifiedTagSet) // remove listener for old property { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } m_LevelWindowProperty = levelWindowProperty; itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); // register listener for new property command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified); m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver(itk::ModifiedEvent(), command); m_IsPropertyModifiedTagSet = true; - m_CurrentImage = dynamic_cast(propNode->GetData()); + m_CurrentImage = dynamic_cast(propNode->GetData()); - m_SettingImgForLvlWinProp = true; + m_LevelWindowMutex = true; propNode->SetBoolProperty("imageForLevelWindow", true); - m_SettingImgForLvlWinProp = false; + m_LevelWindowMutex = false; + + this->Modified(); +} + +void mitk::LevelWindowManager::SetLevelWindow(const LevelWindow &levelWindow) +{ + if (m_LevelWindowProperty.IsNotNull()) + { + m_LevelWindowProperty->SetLevelWindow(levelWindow); + for (const auto &dataNode : m_RelevantDataNodes) + { + auto levelWindowProperty = dynamic_cast(dataNode->GetProperty("levelwindow")); + if (nullptr == levelWindowProperty) + { + continue; + } + levelWindowProperty->SetLevelWindow(levelWindow); + } + } this->Modified(); } -// returns the current mitkLevelWindowProperty object from the image that is affected by changes mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty() { return m_LevelWindowProperty; } -// returns Level/Window values for the current image const mitk::LevelWindow &mitk::LevelWindowManager::GetLevelWindow() { if (m_LevelWindowProperty.IsNotNull()) { return m_LevelWindowProperty->GetLevelWindow(); } else { - itkExceptionMacro("No LevelWindow available!"); + mitkThrow() << "No LevelWindow available!"; } } -// sets new Level/Window values and informs all listeners about changes -void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow &levelWindow) +bool mitk::LevelWindowManager::IsAutoTopMost() { - if (m_LevelWindowProperty.IsNotNull()) - { - m_LevelWindowProperty->SetLevelWindow(levelWindow); - } - this->Modified(); + return m_AutoTopMost; } -void mitk::LevelWindowManager::DataStorageAddedNode(const mitk::DataNode *) +bool mitk::LevelWindowManager::IsSelectedImages() +{ + return m_SelectedImagesMode; +} + +void mitk::LevelWindowManager::DataStorageAddedNode(const DataNode *) { // update observers with new data storage - UpdateObservers(); + this->UpdateObservers(); // Initialize LevelWindowsManager to new image - SetAutoTopMostImage(true); + this->SetAutoTopMostImage(true); // check if everything is still ok - if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || - (m_PropObserverToNode2.size() != this->GetRelevantNodes()->size())) + if ((m_ObserverToVisibleProperty.size() != m_ObserverToLayerProperty.size()) || + (m_ObserverToLayerProperty.size() != this->GetRelevantNodes()->size())) { mitkThrow() << "Wrong number of observers in Level Window Manager!"; } } -void mitk::LevelWindowManager::DataStorageRemovedNode(const mitk::DataNode *removedNode) +void mitk::LevelWindowManager::DataStorageRemovedNode(const DataNode *removedNode) { - // first: check if deleted node is part of relevant nodes. If not, abort method because there is no need change - // anything. - if ((this->GetRelevantNodes()->size() == 0)) - return; + // First: check if deleted node is part of relevant nodes. + // If not, abort method because there is no need change anything. bool removedNodeIsRelevant = false; - /* Iterator code: is crashing, don't know why... so using for loop - for (mitk::DataStorage::SetOfObjects::ConstIterator it = this->GetRelevantNodes()->Begin(); - it != this->GetRelevantNodes()->End(); - ++it) - {if (it->Value() == removedNode) {removedNodeIsRelevant=true;}}*/ - for (unsigned int i = 0; i < this->GetRelevantNodes()->size(); i++) - { - if (this->GetRelevantNodes()->at(i) == removedNode) + DataStorage::SetOfObjects::ConstPointer relevantNodes = GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = relevantNodes->Begin(); it != relevantNodes->End(); ++it) + { + if (it->Value() == removedNode) { removedNodeIsRelevant = true; } } - if (!removedNodeIsRelevant) + + if (false == removedNodeIsRelevant) + { return; + } // remember node which will be removed m_NodeMarkedToDelete = removedNode; // update observers - UpdateObservers(); + this->UpdateObservers(); - /* search image than belongs to the property */ + // search image that belongs to the property if (m_LevelWindowProperty.IsNull()) { - SetAutoTopMostImage(true, removedNode); + this->SetAutoTopMostImage(true, removedNode); } else { - mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); - mitk::DataNode *n = m_DataStorage->GetNode(p2); - if (n == nullptr || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true - // change level window to topmost node + NodePredicateProperty::Pointer property = NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); + DataNode *n = m_DataStorage->GetNode(property); + if (n == nullptr || m_AutoTopMost) // if node was deleted, change our behavior to AutoTopMost, if AutoTopMost is + // true change level window to topmost node { - SetAutoTopMostImage(true, removedNode); + this->SetAutoTopMostImage(true, removedNode); } } // reset variable m_NodeMarkedToDelete = nullptr; // check if everything is still ok - if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || - (m_PropObserverToNode2.size() != (this->GetRelevantNodes()->size() - 1))) + if ((m_ObserverToVisibleProperty.size() != m_ObserverToLayerProperty.size()) || + (m_ObserverToLayerProperty.size() != (relevantNodes->size() - 1))) { mitkThrow() << "Wrong number of observers in Level Window Manager!"; } } -void mitk::LevelWindowManager::UpdateObservers() -{ - this->ClearPropObserverLists(); // remove old observers - CreatePropObserverLists(); // create new observer lists -} - -int mitk::LevelWindowManager::GetNumberOfObservers() -{ - return m_PropObserverToNode.size(); -} - -mitk::DataStorage *mitk::LevelWindowManager::GetDataStorage() +void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject &) { - return m_DataStorage.GetPointer(); + this->Modified(); } -// true if changes on slider or line-edits will affect always the topmost layer image -bool mitk::LevelWindowManager::isAutoTopMost() +mitk::Image *mitk::LevelWindowManager::GetCurrentImage() { - return m_AutoTopMost; + return m_CurrentImage; } -void mitk::LevelWindowManager::RecaluclateLevelWindowForSelectedComponent(const itk::EventObject &event) +int mitk::LevelWindowManager::GetNumberOfObservers() { - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) - { - mitk::DataNode::Pointer node = it->Value(); - if (node.IsNull()) - continue; - - bool isSelected = false; - node->GetBoolProperty("selected", isSelected); - if (isSelected) - { - mitk::LevelWindow selectedLevelWindow; - node->GetLevelWindow(selectedLevelWindow); // node is an image node because of predicates - - auto *image = dynamic_cast(node->GetData()); - int displayedComponent = 0; - if (image && (node->GetIntProperty("Image.Displayed Component", displayedComponent))) - { // we found a selected image with a displayed component - // let's recalculate the levelwindow for this. - selectedLevelWindow.SetAuto(image, true, true, static_cast(displayedComponent)); - node->SetLevelWindow(selectedLevelWindow); - } - } - - mitk::LevelWindow levelWindow; - node->GetLevelWindow(levelWindow); - } - - this->Update(event); + return m_ObserverToVisibleProperty.size(); } -void mitk::LevelWindowManager::Update(const itk::EventObject &) // visible property of a image has changed +mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes() { - if (m_SettingImgForLvlWinProp) // no mutex, should still help - { - return; - } - - if (m_AutoTopMost) - { - SetAutoTopMostImage(true); - return; - } - - int maxVisibleLayer = itk::NumericTraits::min(); - mitk::DataNode::Pointer highestVisible = nullptr; - std::vector visProbNodes; - - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + if (m_DataStorage.IsNull()) { - mitk::DataNode::Pointer node = it->Value(); - - if (node.IsNull()) - { - continue; - } - - bool visible = node->IsVisible(nullptr); - - if (node->IsVisible(nullptr)) - { - int layer = -1; - node->GetIntProperty("layer", layer); - if (layer > maxVisibleLayer) - { - maxVisibleLayer = layer; - highestVisible = node; - } - } - - bool prop = false; - node->GetBoolProperty("imageForLevelWindow", prop); - - if (prop && visible) - { - visProbNodes.push_back(node); - } + return DataStorage::SetOfObjects::ConstPointer(DataStorage::SetOfObjects::New()); } - int numVisProbNodes = visProbNodes.size(); - if (numVisProbNodes > 2) - { - MITK_ERROR << "Error: not more than two visible nodes are expected to have the imageForLevelWindow property set at " - "any point."; - } - else if (numVisProbNodes == 2) - { - for (std::vector::const_iterator it = visProbNodes.begin(); it != visProbNodes.end(); ++it) - { - mitk::LevelWindowProperty::Pointer newProp = - dynamic_cast((*it)->GetProperty("levelwindow")); - if (newProp != m_LevelWindowProperty) - { - this->SetLevelWindowProperty(newProp); - return; - } - } - } - else if (numVisProbNodes == 1) - { - mitk::LevelWindowProperty::Pointer newProp = - dynamic_cast(visProbNodes[0]->GetProperty("levelwindow")); - if (newProp != m_LevelWindowProperty) - { - this->SetLevelWindowProperty(newProp); - return; - } - } - else if (highestVisible) - { - mitk::LevelWindowProperty::Pointer lvlProp = - dynamic_cast(highestVisible->GetProperty("levelwindow")); + NodePredicateProperty::Pointer notBinary = NodePredicateProperty::New("binary", BoolProperty::New(false)); + NodePredicateProperty::Pointer hasLevelWindow = NodePredicateProperty::New("levelwindow", nullptr); - this->SetLevelWindowProperty(lvlProp); - } - else - { - Modified(); - } -} - -mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes() -{ - if (m_DataStorage.IsNull()) - return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New()); // return empty set - - mitk::NodePredicateProperty::Pointer notBinary = - mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false)); - mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", nullptr); - - mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); - mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage"); - mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage"); - mitk::NodePredicateDataType::Pointer isOdfImage = mitk::NodePredicateDataType::New("OdfImage"); - mitk::NodePredicateDataType::Pointer isShImage = mitk::NodePredicateDataType::New("ShImage"); - mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New(); + NodePredicateDataType::Pointer isImage = NodePredicateDataType::New("Image"); + NodePredicateDataType::Pointer isDImage = NodePredicateDataType::New("DiffusionImage"); + NodePredicateDataType::Pointer isTImage = NodePredicateDataType::New("TensorImage"); + NodePredicateDataType::Pointer isOdfImage = NodePredicateDataType::New("OdfImage"); + NodePredicateDataType::Pointer isShImage = NodePredicateDataType::New("ShImage"); + NodePredicateOr::Pointer predicateTypes = NodePredicateOr::New(); predicateTypes->AddPredicate(isImage); predicateTypes->AddPredicate(isDImage); predicateTypes->AddPredicate(isTImage); predicateTypes->AddPredicate(isOdfImage); predicateTypes->AddPredicate(isShImage); - mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New(); + NodePredicateAnd::Pointer predicate = NodePredicateAnd::New(); predicate->AddPredicate(notBinary); predicate->AddPredicate(hasLevelWindow); predicate->AddPredicate(predicateTypes); - mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset(predicate); + DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset(predicate); return relevantNodes; } -mitk::Image *mitk::LevelWindowManager::GetCurrentImage() +void mitk::LevelWindowManager::UpdateObservers() { - return m_CurrentImage; + this->ClearPropObserverLists(); // remove old observers + this->CreatePropObserverLists(); // create new observer lists } void mitk::LevelWindowManager::ClearPropObserverLists() { - for (auto iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); ++iter) + for (auto iter = m_ObserverToVisibleProperty.begin(); iter != m_ObserverToVisibleProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode.clear(); + m_ObserverToVisibleProperty.clear(); - for (auto iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); - ++iter) + for (auto iter = m_ObserverToLayerProperty.begin(); iter != m_ObserverToLayerProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode2.clear(); + m_ObserverToLayerProperty.clear(); - for (auto iter = m_PropObserverToNode3.begin(); iter != m_PropObserverToNode3.end(); - ++iter) + for (auto iter = m_ObserverToRenderingModeProperty.begin(); iter != m_ObserverToRenderingModeProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode3.clear(); + m_ObserverToRenderingModeProperty.clear(); - for (auto iter = m_PropObserverToNode4.begin(); iter != m_PropObserverToNode4.end(); - ++iter) + for (auto iter = m_ObserverToDisplayedComponentProperty.begin(); iter != m_ObserverToDisplayedComponentProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode4.clear(); + m_ObserverToDisplayedComponentProperty.clear(); - for (auto iter = m_PropObserverToNode5.begin(); iter != m_PropObserverToNode5.end(); - ++iter) + for (auto iter = m_ObserverToLevelWindowImageProperty.begin(); iter != m_ObserverToLevelWindowImageProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode5.clear(); + m_ObserverToLevelWindowImageProperty.clear(); + + for (auto iter = m_ObserverToSelectedProperty.begin(); iter != m_ObserverToSelectedProperty.end(); ++iter) + { + (*iter).second->RemoveObserver((*iter).first.first); + (*iter).second = nullptr; + } + m_ObserverToSelectedProperty.clear(); } void mitk::LevelWindowManager::CreatePropObserverLists() { if (m_DataStorage.IsNull()) // check if data storage is set { - itkExceptionMacro("DataStorage not set"); + mitkThrow() << "DataStorage not set"; } /* add observers for all relevant nodes */ - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete)) { continue; } /* register listener for changes in visible property */ itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &LevelWindowManager::Update); unsigned long visIdx = it->Value()->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); - m_PropObserverToNode[PropDataPair(visIdx, it->Value())] = it->Value()->GetProperty("visible"); + m_ObserverToVisibleProperty[PropDataPair(visIdx, it->Value())] = it->Value()->GetProperty("visible"); /* register listener for changes in layer property */ itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction(this, &LevelWindowManager::Update); unsigned long layerIdx = it->Value()->GetProperty("layer")->AddObserver(itk::ModifiedEvent(), command2); - m_PropObserverToNode2[PropDataPair(layerIdx, it->Value())] = it->Value()->GetProperty("layer"); + m_ObserverToLayerProperty[PropDataPair(layerIdx, it->Value())] = it->Value()->GetProperty("layer"); /* register listener for changes in layer property */ itk::ReceptorMemberCommand::Pointer command3 = itk::ReceptorMemberCommand::New(); command3->SetCallbackFunction(this, &LevelWindowManager::Update); - mitk::BaseProperty::Pointer imageRenderingMode = it->Value()->GetProperty("Image Rendering.Mode"); + BaseProperty::Pointer imageRenderingMode = it->Value()->GetProperty("Image Rendering.Mode"); if (imageRenderingMode.IsNotNull()) { unsigned long rendIdx = imageRenderingMode->AddObserver(itk::ModifiedEvent(), command3); - m_PropObserverToNode3[PropDataPair(rendIdx, it->Value())] = imageRenderingMode.GetPointer(); + m_ObserverToRenderingModeProperty[PropDataPair(rendIdx, it->Value())] = imageRenderingMode.GetPointer(); } itk::ReceptorMemberCommand::Pointer command4 = itk::ReceptorMemberCommand::New(); - command4->SetCallbackFunction(this, &LevelWindowManager::RecaluclateLevelWindowForSelectedComponent); - mitk::BaseProperty::Pointer displayedImageComponent = it->Value()->GetProperty("Image.Displayed Component"); + command4->SetCallbackFunction(this, &LevelWindowManager::RecalculateLevelWindowForSelectedComponent); + BaseProperty::Pointer displayedImageComponent = it->Value()->GetProperty("Image.Displayed Component"); if (displayedImageComponent.IsNotNull()) { unsigned long dispIdx = displayedImageComponent->AddObserver(itk::ModifiedEvent(), command4); - m_PropObserverToNode4[PropDataPair(dispIdx, it->Value())] = displayedImageComponent.GetPointer(); + m_ObserverToDisplayedComponentProperty[PropDataPair(dispIdx, it->Value())] = displayedImageComponent.GetPointer(); } itk::ReceptorMemberCommand::Pointer command5 = itk::ReceptorMemberCommand::New(); command5->SetCallbackFunction(this, &LevelWindowManager::Update); - mitk::BaseProperty::Pointer imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); + BaseProperty::Pointer imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); if (imgForLvlWin.IsNull()) { it->Value()->SetBoolProperty("imageForLevelWindow", false); imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); } unsigned long lvlWinIdx = imgForLvlWin->AddObserver(itk::ModifiedEvent(), command5); - m_PropObserverToNode5[PropDataPair(lvlWinIdx, it->Value())] = it->Value()->GetProperty("imageForLevelWindow"); + m_ObserverToLevelWindowImageProperty[PropDataPair(lvlWinIdx, it->Value())] = it->Value()->GetProperty("imageForLevelWindow"); + + itk::ReceptorMemberCommand::Pointer command6 = + itk::ReceptorMemberCommand::New(); + command6->SetCallbackFunction(this, &LevelWindowManager::UpdateSelected); + BaseProperty::Pointer selectedDataNode = it->Value()->GetProperty("selected"); + if (selectedDataNode.IsNull()) + { + it->Value()->SetBoolProperty("selected", false); + selectedDataNode = it->Value()->GetProperty("selected"); + } + unsigned long selectedIdx = selectedDataNode->AddObserver(itk::ModifiedEvent(), command5); + m_ObserverToSelectedProperty[PropDataPair(selectedIdx, it->Value())] = it->Value()->GetProperty("selected"); + } +} + +bool mitk::LevelWindowManager::IgnoreNode(const DataNode* dataNode) +{ + LevelWindowProperty::Pointer levelWindowProperty = + dynamic_cast(dataNode->GetProperty("levelwindow")); + if (levelWindowProperty.IsNull()) + { + return true; } + + int nonLvlWinMode1 = RenderingModeProperty::LOOKUPTABLE_COLOR; + int nonLvlWinMode2 = RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR; + + RenderingModeProperty::Pointer mode = + dynamic_cast(dataNode->GetProperty("Image Rendering.Mode")); + + if (mode.IsNotNull()) + { + int currMode = mode->GetRenderingMode(); + if (currMode == nonLvlWinMode1 || currMode == nonLvlWinMode2) + { + return true; + } + } + else + { + return true; + } + + return false; } diff --git a/Modules/Core/test/mitkLevelWindowManagerTest.cpp b/Modules/Core/test/mitkLevelWindowManagerTest.cpp index 9aaf1f8f22..11902e1ac3 100644 --- a/Modules/Core/test/mitkLevelWindowManagerTest.cpp +++ b/Modules/Core/test/mitkLevelWindowManagerTest.cpp @@ -1,625 +1,625 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkMersenneTwisterRandomVariateGenerator.h" #include "mitkLevelWindowManager.h" #include "mitkRenderingModeProperty.h" #include "mitkStandaloneDataStorage.h" #include #include #include #include #include #include #include #include class mitkLevelWindowManagerTestClass { public: static void TestInstantiation() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); MITK_TEST_CONDITION_REQUIRED(manager.IsNotNull(), "Testing mitk::LevelWindowManager::New()"); } static void TestSetGetDataStorage() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); MITK_TEST_OUTPUT(<< "Creating DataStorage: "); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); bool success = true; try { manager->SetDataStorage(ds); } catch (std::exception &e) { success = false; MITK_ERROR << "Exception: " << e.what(); } MITK_TEST_CONDITION_REQUIRED(success, "Testing mitk::LevelWindowManager SetDataStorage() "); MITK_TEST_CONDITION_REQUIRED(ds == manager->GetDataStorage(), "Testing mitk::LevelWindowManager GetDataStorage "); } static void TestMethodsWithInvalidParameters() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); bool success = false; mitk::LevelWindowProperty::Pointer levelWindowProperty = mitk::LevelWindowProperty::New(); try { manager->SetLevelWindowProperty(levelWindowProperty); } catch (const mitk::Exception &) { success = true; } MITK_TEST_CONDITION(success, "Testing mitk::LevelWindowManager SetLevelWindowProperty with invalid parameter"); } static void TestOtherMethods() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); - MITK_TEST_CONDITION(manager->isAutoTopMost(), "Testing mitk::LevelWindowManager isAutoTopMost"); + MITK_TEST_CONDITION(manager->IsAutoTopMost(), "Testing mitk::LevelWindowManager isAutoTopMost"); // It is not clear what the following code is supposed to test. The expression in // the catch(...) block does have no effect, so success is always true. // Related bugs are 13894 and 13889 /* bool success = true; try { mitk::LevelWindow levelWindow = manager->GetLevelWindow(); manager->SetLevelWindow(levelWindow); } catch (...) { success == false; } MITK_TEST_CONDITION(success,"Testing mitk::LevelWindowManager GetLevelWindow() and SetLevelWindow()"); */ manager->SetAutoTopMostImage(true); - MITK_TEST_CONDITION(manager->isAutoTopMost(), "Testing mitk::LevelWindowManager isAutoTopMost()"); + MITK_TEST_CONDITION(manager->IsAutoTopMost(), "Testing mitk::LevelWindowManager isAutoTopMost()"); } static void TestRemoveObserver(std::string testImageFile) { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); // add multiple objects to the data storage => multiple observers should be created mitk::Image::Pointer image1 = mitk::IOUtil::Load(testImageFile); mitk::DataNode::Pointer node1 = mitk::DataNode::New(); node1->SetData(image1); mitk::Image::Pointer image2 = mitk::IOUtil::Load(testImageFile); mitk::DataNode::Pointer node2 = mitk::DataNode::New(); node2->SetData(image2); ds->Add(node1); ds->Add(node2); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 2, "Test if nodes have been added"); MITK_TEST_CONDITION_REQUIRED( static_cast(manager->GetRelevantNodes()->size()) == manager->GetNumberOfObservers(), "Test if number of nodes is similar to number of observers"); mitk::Image::Pointer image3 = mitk::IOUtil::Load(testImageFile); mitk::DataNode::Pointer node3 = mitk::DataNode::New(); node3->SetData(image3); ds->Add(node3); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 3, "Test if another node have been added"); MITK_TEST_CONDITION_REQUIRED( static_cast(manager->GetRelevantNodes()->size()) == manager->GetNumberOfObservers(), "Test if number of nodes is similar to number of observers"); ds->Remove(node1); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 2, "Deleted node 1 (test GetRelevantNodes())"); MITK_TEST_CONDITION_REQUIRED(manager->GetNumberOfObservers() == 2, "Deleted node 1 (test GetNumberOfObservers())"); ds->Remove(node2); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 1, "Deleted node 2 (test GetRelevantNodes())"); MITK_TEST_CONDITION_REQUIRED(manager->GetNumberOfObservers() == 1, "Deleted node 2 (test GetNumberOfObservers())"); ds->Remove(node3); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 0, "Deleted node 3 (test GetRelevantNodes())"); MITK_TEST_CONDITION_REQUIRED(manager->GetNumberOfObservers() == 0, "Deleted node 3 (test GetNumberOfObservers())"); } static bool VerifyRenderingModes() { bool ok = (mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR == 1) && (mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR == 2) && (mitk::RenderingModeProperty::LOOKUPTABLE_COLOR == 3) && (mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR == 4); return ok; } static void TestLevelWindowSliderVisibility(std::string testImageFile) { bool renderingModesValid = mitkLevelWindowManagerTestClass::VerifyRenderingModes(); if (!renderingModesValid) { MITK_ERROR << "Exception: Image Rendering.Mode property value types inconsistent."; } mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); // add multiple objects to the data storage => multiple observers should be created mitk::Image::Pointer image1 = mitk::IOUtil::Load(testImageFile); mitk::DataNode::Pointer node1 = mitk::DataNode::New(); node1->SetData(image1); ds->Add(node1); mitk::DataNode::Pointer node2 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node3 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); std::vector nodeVec; // nodeVec.resize( 3 ); nodeVec.push_back(node1); nodeVec.push_back(node2); nodeVec.push_back(node3); typedef itk::Statistics::MersenneTwisterRandomVariateGenerator RandomGeneratorType; RandomGeneratorType::Pointer rnd = RandomGeneratorType::New(); rnd->Initialize(); for (unsigned int i = 0; i < 8; ++i) { unsigned int parity = i; for (unsigned int img = 0; img < 3; ++img) { if (parity & 1) { int mode = rnd->GetIntegerVariate() % 3; nodeVec[img]->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mode)); } else { int mode = rnd->GetIntegerVariate() % 2; nodeVec[img]->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(3 + mode)); } parity >>= 1; } MITK_TEST_CONDITION( renderingModesValid && ((!manager->GetLevelWindowProperty() && !i) || (manager->GetLevelWindowProperty() && i)), "Testing level window property member according to rendering mode"); } } static void TestSetLevelWindowProperty(std::string testImageFile) { mitk::LevelWindowManager::Pointer manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); // add multiple objects to the data storage => multiple observers should be created mitk::DataNode::Pointer node3 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node2 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node1 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); node3->SetIntProperty("layer", 1); node2->SetIntProperty("layer", 2); node1->SetIntProperty("layer", 3); manager->SetAutoTopMostImage(true); bool isImageForLevelWindow1, isImageForLevelWindow2, isImageForLevelWindow3; node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(isImageForLevelWindow1 && !isImageForLevelWindow2 && !isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 1."); manager->SetAutoTopMostImage(false); mitk::LevelWindowProperty::Pointer prop = dynamic_cast(node2->GetProperty("levelwindow")); manager->SetLevelWindowProperty(prop); node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(!isImageForLevelWindow1 && isImageForLevelWindow2 && !isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 2."); prop = dynamic_cast(node3->GetProperty("levelwindow")); manager->SetLevelWindowProperty(prop); node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(!isImageForLevelWindow1 && !isImageForLevelWindow2 && isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 3."); prop = dynamic_cast(node1->GetProperty("levelwindow")); manager->SetLevelWindowProperty(prop); node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(isImageForLevelWindow1 && !isImageForLevelWindow2 && !isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 3."); } static void TestImageForLevelWindowOnVisibilityChange(std::string testImageFile) { mitk::LevelWindowManager::Pointer manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); // add multiple objects to the data storage => multiple observers should be created mitk::DataNode::Pointer node3 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node2 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node1 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); node3->SetIntProperty("layer", 1); node2->SetIntProperty("layer", 2); node1->SetIntProperty("layer", 3); manager->SetAutoTopMostImage(false); bool isImageForLevelWindow1, isImageForLevelWindow2, isImageForLevelWindow3; node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(isImageForLevelWindow1 && !isImageForLevelWindow2 && !isImageForLevelWindow3, "Testing initial imageForLevelWindow setting."); node1->SetVisibility(false); node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(!isImageForLevelWindow1 && isImageForLevelWindow2 && !isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 2."); node2->SetVisibility(false); node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(!isImageForLevelWindow1 && !isImageForLevelWindow2 && isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 3."); node3->SetVisibility(false); node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(!isImageForLevelWindow1 && !isImageForLevelWindow2 && isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 3."); node1->SetVisibility(true); node1->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow1); node2->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow2); node3->GetBoolProperty("imageForLevelWindow", isImageForLevelWindow3); MITK_TEST_CONDITION(isImageForLevelWindow1 && !isImageForLevelWindow2 && !isImageForLevelWindow3, "Testing exclusive imageForLevelWindow property for node 3."); } static void TestImageForLevelWindowOnRandomPropertyChange(std::string testImageFile) { typedef std::vector BoolVecType; typedef itk::Statistics::MersenneTwisterRandomVariateGenerator RandomGeneratorType; // initialize the data storage mitk::LevelWindowManager::Pointer manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); mitk::DataNode::Pointer node3 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node2 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node1 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); node3->SetIntProperty("layer", 1); node2->SetIntProperty("layer", 2); node1->SetIntProperty("layer", 3); // node visibilities std::vector nodesVisible; nodesVisible.resize(3); std::fill(nodesVisible.begin(), nodesVisible.end(), true); // which node has the level window std::vector nodesForLevelWindow; nodesForLevelWindow.resize(3); std::fill(nodesForLevelWindow.begin(), nodesForLevelWindow.end(), false); // the nodes themselves std::vector nodes; nodes.push_back(node1); nodes.push_back(node2); nodes.push_back(node3); // status quo manager->SetAutoTopMostImage(false); bool lvlWin1, lvlWin2, lvlWin3; node1->GetBoolProperty("imageForLevelWindow", lvlWin1); node2->GetBoolProperty("imageForLevelWindow", lvlWin2); node3->GetBoolProperty("imageForLevelWindow", lvlWin3); MITK_TEST_CONDITION(lvlWin1 && !lvlWin2 && !lvlWin3, "Testing initial imageForLevelWindow setting."); nodesForLevelWindow[0] = lvlWin1; nodesForLevelWindow[1] = lvlWin2; nodesForLevelWindow[2] = lvlWin3; // prepare randomized visibility changes RandomGeneratorType::Pointer ranGen = RandomGeneratorType::New(); ranGen->Initialize(); int ranCount = 100; int validCount = 0; int invalidCount = 0; int mustHaveLvlWindow = 4; for (int run = 0; run < ranCount; ++run) { // toggle node visibility int ran = ranGen->GetIntegerVariate(2); nodes[ran]->SetBoolProperty("imageForLevelWindow", !nodesForLevelWindow[ran]); // one node must have the level window std::vector::const_iterator found = std::find(nodesForLevelWindow.begin(), nodesForLevelWindow.end(), true); if (found == nodesForLevelWindow.end()) { break; } // all invisible? found = std::find(nodesVisible.begin(), nodesVisible.end(), true); if (!nodesForLevelWindow[ran]) { mustHaveLvlWindow = pow(2, 2 - ran); } else { mustHaveLvlWindow = 4; } // get the current status node1->GetBoolProperty("imageForLevelWindow", lvlWin1); node2->GetBoolProperty("imageForLevelWindow", lvlWin2); node3->GetBoolProperty("imageForLevelWindow", lvlWin3); nodesForLevelWindow[0] = lvlWin1; nodesForLevelWindow[1] = lvlWin2; nodesForLevelWindow[2] = lvlWin3; int hasLevelWindow = 0; for (int i = 0; i < 3; ++i) { if (nodesForLevelWindow[i]) { hasLevelWindow += pow(2, 2 - i); } } validCount += hasLevelWindow == mustHaveLvlWindow ? 1 : 0; // test sensitivity int falseran = 0; while (falseran == 0) { falseran = ranGen->GetIntegerVariate(7); } BoolVecType falseNodes; falseNodes.push_back((falseran & 1) == 1 ? !lvlWin1 : lvlWin1); falseran >>= 1; falseNodes.push_back((falseran & 1) == 1 ? !lvlWin2 : lvlWin2); falseran >>= 1; falseNodes.push_back((falseran & 1) == 1 ? !lvlWin3 : lvlWin3); int falseLevelWindow = 0; for (int i = 0; i < 3; ++i) { if (falseNodes[i]) { falseLevelWindow += pow(2, 2 - i); } } invalidCount += falseLevelWindow == mustHaveLvlWindow ? 0 : 1; // in case of errors proceed anyway mustHaveLvlWindow = hasLevelWindow; } MITK_TEST_CONDITION(validCount == ranCount, "Testing proper node for level window property."); MITK_TEST_CONDITION(invalidCount == ranCount, "Sensitivity test."); } static void TestImageForLevelWindowOnRandomVisibilityChange(std::string testImageFile) { typedef std::vector BoolVecType; typedef itk::Statistics::MersenneTwisterRandomVariateGenerator RandomGeneratorType; // initialize the data storage mitk::LevelWindowManager::Pointer manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); mitk::DataNode::Pointer node3 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node2 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); mitk::DataNode::Pointer node1 = mitk::IOUtil::Load(testImageFile, *ds)->GetElement(0); node3->SetIntProperty("layer", 1); node2->SetIntProperty("layer", 2); node1->SetIntProperty("layer", 3); // node visibilities std::vector nodesVisible; nodesVisible.resize(3); std::fill(nodesVisible.begin(), nodesVisible.end(), true); // which node has the level window std::vector nodesForLevelWindow; nodesForLevelWindow.resize(3); std::fill(nodesForLevelWindow.begin(), nodesForLevelWindow.end(), false); // the nodes themselves std::vector nodes; nodes.push_back(node1); nodes.push_back(node2); nodes.push_back(node3); // status quo manager->SetAutoTopMostImage(false); bool lvlWin1, lvlWin2, lvlWin3; node1->GetBoolProperty("imageForLevelWindow", lvlWin1); node2->GetBoolProperty("imageForLevelWindow", lvlWin2); node3->GetBoolProperty("imageForLevelWindow", lvlWin3); MITK_TEST_CONDITION(lvlWin1 && !lvlWin2 && !lvlWin3, "Testing initial imageForLevelWindow setting."); nodesForLevelWindow[0] = lvlWin1; nodesForLevelWindow[1] = lvlWin2; nodesForLevelWindow[2] = lvlWin3; // prepare randomized visibility changes RandomGeneratorType::Pointer ranGen = RandomGeneratorType::New(); ranGen->Initialize(); int ranCount = 100; int validCount = 0; int invalidCount = 0; int mustHaveLvlWindow = 4; for (int run = 0; run < ranCount; ++run) { // toggle node visibility int ran = ranGen->GetIntegerVariate(2); nodesVisible[ran] = !nodesVisible[ran]; nodes[ran]->SetVisibility(nodesVisible[ran]); // one node must have the level window std::vector::const_iterator found = std::find(nodesForLevelWindow.begin(), nodesForLevelWindow.end(), true); if (found == nodesForLevelWindow.end()) { break; } int ind = found - nodesForLevelWindow.begin(); // all invisible? found = std::find(nodesVisible.begin(), nodesVisible.end(), true); bool allInvisible = (found == nodesVisible.end()); // which node shall get the level window now if (!allInvisible && !nodesVisible[ind]) { int count = 0; for (std::vector::const_iterator it = nodesVisible.begin(); it != nodesVisible.end(); ++it, ++count) { if (*it) { mustHaveLvlWindow = pow(2, 2 - count); break; } } } // get the current status node1->GetBoolProperty("imageForLevelWindow", lvlWin1); node2->GetBoolProperty("imageForLevelWindow", lvlWin2); node3->GetBoolProperty("imageForLevelWindow", lvlWin3); nodesForLevelWindow[0] = lvlWin1; nodesForLevelWindow[1] = lvlWin2; nodesForLevelWindow[2] = lvlWin3; int hasLevelWindow = 0; for (int i = 0; i < 3; ++i) { if (nodesForLevelWindow[i]) { hasLevelWindow += pow(2, 2 - i); } } validCount += hasLevelWindow == mustHaveLvlWindow ? 1 : 0; // test sensitivity int falseran = 0; while (falseran == 0) { falseran = ranGen->GetIntegerVariate(7); } BoolVecType falseNodes; falseNodes.push_back((falseran & 1) == 1 ? !lvlWin1 : lvlWin1); falseran >>= 1; falseNodes.push_back((falseran & 1) == 1 ? !lvlWin2 : lvlWin2); falseran >>= 1; falseNodes.push_back((falseran & 1) == 1 ? !lvlWin3 : lvlWin3); int falseLevelWindow = 0; for (int i = 0; i < 3; ++i) { if (falseNodes[i]) { falseLevelWindow += pow(2, 2 - i); } } invalidCount += falseLevelWindow == mustHaveLvlWindow ? 0 : 1; // in case of errors proceed anyway mustHaveLvlWindow = hasLevelWindow; } MITK_TEST_CONDITION(validCount == ranCount, "Testing proper node for level window property."); MITK_TEST_CONDITION(invalidCount == ranCount, "Sensitivity test."); } }; int mitkLevelWindowManagerTest(int argc, char *args[]) { MITK_TEST_BEGIN("mitkLevelWindowManager"); MITK_TEST_CONDITION_REQUIRED(argc >= 2, "Testing if test file is given."); std::string testImage = args[1]; mitkLevelWindowManagerTestClass::TestInstantiation(); mitkLevelWindowManagerTestClass::TestSetGetDataStorage(); mitkLevelWindowManagerTestClass::TestMethodsWithInvalidParameters(); mitkLevelWindowManagerTestClass::TestOtherMethods(); mitkLevelWindowManagerTestClass::TestRemoveObserver(testImage); mitkLevelWindowManagerTestClass::TestLevelWindowSliderVisibility(testImage); mitkLevelWindowManagerTestClass::TestSetLevelWindowProperty(testImage); mitkLevelWindowManagerTestClass::TestImageForLevelWindowOnVisibilityChange(testImage); mitkLevelWindowManagerTestClass::TestImageForLevelWindowOnRandomVisibilityChange(testImage); mitkLevelWindowManagerTestClass::TestImageForLevelWindowOnRandomPropertyChange(testImage); MITK_TEST_END(); } diff --git a/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h b/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h index 6c1a5af5f0..0b42568a4b 100644 --- a/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h +++ b/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h @@ -1,121 +1,121 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKLEVELWINDOWWIDGETCONTEXTMENU_H #define QMITKLEVELWINDOWWIDGETCONTEXTMENU_H #include #include #include #include /** * \ingroup QmitkModule * \brief Provides a contextmenu for Level/Window functionality. * * Either creates * a new contextmenu with standard functions or adds Level/Window standard * functions to an predefined contextmenu. */ class MITKQTWIDGETS_EXPORT QmitkLevelWindowWidgetContextMenu : public QWidget { Q_OBJECT public: /// constructor QmitkLevelWindowWidgetContextMenu(QWidget *parent, Qt::WindowFlags f = nullptr); ~QmitkLevelWindowWidgetContextMenu() override; /*! * data structure which reads and writes presets defined in a XML-file */ mitk::LevelWindowPreset *m_LevelWindowPreset; /*! * data structure which stores the values manipulated * by a QmitkLevelWindowWidgetContextMenu */ mitk::LevelWindow m_LevelWindow; /// submenu with all presets for contextmenu QMenu *m_PresetSubmenu; /// submenu with all images for contextmenu QMenu *m_ImageSubmenu; /// pointer to the object which manages all Level/Window changes on images and holds the LevelWindowProperty /// of the current image mitk::LevelWindowManager *m_Manager; /// map to hold all image-properties, one can get the image which is selected in the contextmenu /// with the QAction representing the image for the contextmenu std::map m_Images; /*! * returns the contextmenu with standard functions for Level/Window * * input is a prefilled contextmenu to which standard functions will be added */ - void getContextMenu(QMenu *contextmenu); + void GetContextMenu(QMenu *contextMenu); /// returns the contextmenu with standard functions for Level/Window - void getContextMenu(); + void GetContextMenu(); /// lets this object know about the LevelWindowManager to get all images and tell about changes - void setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); + void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); protected: - /// ID of preset selected in contextmenu - QAction *m_PresetAction; - /// ID of image selected in contextmenu - QAction *m_ImageAction; + QAction *m_PresetAction; + QAction *m_AutoTopmostAction; + QAction *m_SelectedImagesAction; -protected slots: +protected Q_SLOTS: /// sets level and window value of the current image to the values defined for the selected preset - void setPreset(QAction *presetAction); + void OnSetPreset(const QAction *presetAction); /// calls the mitkLevelWindow SetAuto method with guessByCentralSlice false, so that the greyvalues from whole image /// will be considered - void useOptimizedLevelWindow(); + void OnUseOptimizedLevelWindow(); /// calls the mitkLevelWindow SetToImageRange method, so that the greyvalues from whole image will be used - void useAllGreyvaluesFromImage(); + void OnUseAllGreyvaluesFromImage(); /// sets the level window slider to be fixed - void setFixed(); + void OnSetFixed(); /// adds a new Preset for presets-contextmenu - void addPreset(); + void OnAddPreset(); /// resets the current images Level/Window to its default values - void setDefaultLevelWindow(); + void OnSetDefaultLevelWindow(); /// resets the current images scalerange to its default values - void setDefaultScaleRange(); + void OnSetDefaultScaleRange(); /// changes the current images scalerange - void changeScaleRange(); + void OnChangeScaleRange(); /// sets the selected image or the topmost layer image to the new current image - void setImage(QAction *imageAction); + void OnSetImage(QAction *imageAction); /// sets the window to its maximum Size to fit the scalerange - void setMaximumWindow(); + void OnSetMaximumWindow(); }; -#endif + +#endif // QMITKLEVELWINDOWWIDGETCONTEXTMENU_H diff --git a/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h b/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h index 429238a86c..a01af09448 100644 --- a/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h @@ -1,97 +1,97 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKLINEEDITLEVELWINDOWWIDGET -#define QMITKLINEEDITLEVELWINDOWWIDGET +#ifndef QMITKLINEEDITLEVELWINDOWWIDGET_H +#define QMITKLINEEDITLEVELWINDOWWIDGET_H #include -#include - +// mitk core #include +// qt +#include + class QmitkLevelWindowWidgetContextMenu; class QLineEdit; /** * \ingroup QmitkModule * \brief Provides a widget with two lineedit fields, one to change the * window value of the current image and one to change the level value of * the current image. */ class MITKQTWIDGETS_EXPORT QmitkLineEditLevelWindowWidget : public QWidget { Q_OBJECT public: /// constructor QmitkLineEditLevelWindowWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr); /// destructor ~QmitkLineEditLevelWindowWidget() override; /// inputfield for level value QLineEdit *m_LevelInput; /// inputfield for window value QLineEdit *m_WindowInput; /*! * data structure which stores the values manipulated * by a QmitkLineEditLevelWindowWidget */ mitk::LevelWindow m_LevelWindow; /// manager who is responsible to collect and deliver changes on Level/Window mitk::LevelWindowManager::Pointer m_Manager; /// sets the manager who is responsible to collect and deliver changes on Level/Window - void setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); + void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); /// sets the DataStorage which holds all image-nodes void SetDataStorage(mitk::DataStorage *ds); /// returns the manager who is responsible to collect and deliver changes on Level/Window mitk::LevelWindowManager *GetManager(); private: /// creates the contextmenu for this widget from class QmitkLevelWindowWidgetContextMenu void contextMenuEvent(QContextMenuEvent *) override; /// change notifications from the mitkLevelWindowManager void OnPropertyModified(const itk::EventObject &e); -public slots: +public Q_SLOTS: - /// called when return is pressed in levelinput field + /** @brief Read the levelInput and change level and slider when the button "ENTER" was pressed + * in the windowInput-LineEdit. + */ void SetLevelValue(); - - /// called when return is pressed in windowinput field + /** @brief Read the windowInput and change window and slider when the button "ENTER" was pressed + * in the windowInput-LineEdit. + */ void SetWindowValue(); - // validator to accept only possible values for Level/Window in lineedits - // void setValidator(); - protected: unsigned long m_ObserverTag; bool m_IsObserverTagSet; - /*! - * data structure which creates the contextmenu for QmitkLineEditLevelWindowWidget - */ QmitkLevelWindowWidgetContextMenu *m_Contextmenu; }; -#endif // QMITKLINEEDITLEVELWINDOWWIDGET + +#endif // QMITKLINEEDITLEVELWINDOWWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h b/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h index 32b14887ab..624f8319ba 100644 --- a/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h @@ -1,193 +1,192 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKSLIDERLEVELWINDOW_WIDGET -#define QMITKSLIDERLEVELWINDOW_WIDGET +#ifndef QMITKSLIDERLEVELWINDOWWIDGET_H +#define QMITKSLIDERLEVELWINDOWWIDGET_H #include #include #include class QmitkLevelWindowWidgetContextMenu; /** * \ingroup QmitkModule * * \brief Provides a widget with a slider to change the level and * window value of the current image. * * This documentation actually refers to the QmitkLevelWindowWidget * and is only put in this class due to technical issues (should be * moved later). * * The QmitkLevelWindowWidget is a kind of container for a * QmitkSliderLevelWindowWidget (this is the cyan bar above the text * input fields) and a QmitkLineEditLevelWindowWidget (with two text * input fields). It holds a reference to a mitk::LevelWindowManager * variable, which keeps the LevelWindowProperty of the currently * selected image. Level/Window is manipulated by the text inputs and * the Slider to adjust brightness/contrast of a single image. All * changes on the slider or in the text input fields affect the current * image by giving new values to LevelWindowManager. LevelWindowManager * then sends a signal to tell other listeners about changes. * * Which image is changed is determined by mitkLevelWindowManager. If * m_AutoTopMost is true, always the topmost image in data tree (layer * property) is affected by changes. The image which is affected by * changes can also be changed by QmitkLevelWindowWidgetContextMenu, * the context menu for QmitkSliderLevelWindowWidget and * QmitkLineEditLevelWindowWidget. There you have the possibility to * set a certain image or always the topmost image in the data tree * (layer property) to be affected by changes. * * The internal mitk::LevelWindow variable contains a range that is * valid for a given image. It should not be possible to move the * level/window parameters outside this range. The range can be changed * and reset to its default values by QmitkLevelWindowWidgetContextMenu, * the context menu for QmitkSliderLevelWindowWidget and * QmitkLineEditLevelWindowWidget. * * Now for the behaviour of the text inputs: The upper one contains the * value of the level (brightness), the lower one shows the window (contrast). * * The behaviour of the cyan bar is more obvious: the scale in the * background shows the valid range. The cyan bar in front displays the * currently selected level/window setting. You can change the level by * dragging the bar with the left mouse button or clicking somewhere inside * the scalerange with the left mouse button. The window is changed by * moving the mouse on the upper or lower bound of the bar until the cursor * becomes an vertical double-arrowed symbol. Then you can change the * windowsize by clicking the left mouse button and move the mouse upwards * or downwards. The bar becomes greater upwards as well as downwards. If * you want to change the size of the window in only one direction you * have to press the CTRL-key while doing the same as mentioned above. * This information is also presented by a tooltip text when moving the * mouse on the upper or lower bound of the bar. */ class MITKQTWIDGETS_EXPORT QmitkSliderLevelWindowWidget : public QWidget { Q_OBJECT public: /// constructor QmitkSliderLevelWindowWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr); /// destructor ~QmitkSliderLevelWindowWidget() override; - /*! - * data structure which stores the values manipulated - * by a QmitkSliderLevelWindowWidget - */ - mitk::LevelWindow m_LevelWindow; - - /// manager who is responsible to collect and deliver changes on Level/Window - mitk::LevelWindowManager::Pointer m_Manager; - /// sets the manager who is responsible to collect and deliver changes on Level/Window - void setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); + void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); /// sets the DataStorage which holds all image-nodes - void setDataStorage(mitk::DataStorage *ds); + void SetDataStorage(mitk::DataStorage *ds); /// returns the manager who is responsible to collect and deliver changes on Level/Window mitk::LevelWindowManager *GetManager(); + mitk::LevelWindow m_LevelWindow; + + /// manager who is responsible to collect and deliver changes on Level/Window + mitk::LevelWindowManager::Pointer m_Manager; + private: - /// creates the contextmenu for this widget from class QmitkLevelWindowWidgetContextMenu + /// creates the context menu for this widget from class QmitkLevelWindowWidgetContextMenu void contextMenuEvent(QContextMenuEvent *) override; /// change notifications from the mitkLevelWindowManager void OnPropertyModified(const itk::EventObject &e); protected: /// recalculate the size and position of the slider bar - virtual void update(); + virtual void Update(); /*! * helper for drawing the component */ QRect m_Rect; /*! * helper for drawing the component */ QPoint m_StartPos; bool m_Resize; bool m_Bottom; bool m_MouseDown; bool m_Leftbutton; bool m_CtrlPressed; int m_MoveHeight; bool m_ScaleVisible; QRect m_LowerBound; QRect m_UpperBound; unsigned long m_ObserverTag; bool m_IsObserverTagSet; QFont m_Font; /*! - * data structure which creates the contextmenu for QmitkLineEditLevelWindowWidget + * data structure which creates the context menu for QmitkLineEditLevelWindowWidget */ QmitkLevelWindowWidgetContextMenu *m_Contextmenu; /*! * repaint the slider and the scale */ void paintEvent(QPaintEvent *e) override; /*! - * method implements the component behaviour + * method implements the component behavior * * checks if cursor is on upper or lower bound of slider bar and changes cursor symbol * - * checks if left mouse button is pressed and if CTRL is pressed and changes sliderbar in movedirection accordingly + * checks if left mouse button is pressed and if CTRL is pressed and changes sliderbar in move-direction accordingly */ void mouseMoveEvent(QMouseEvent *mouseEvent) override; void enterEvent(QEvent *event) override; /*! * registers events when a mousebutton is pressed * * if leftbutton is pressed m_Leftbutton is set to true * * also checks if CTRL is pressed and sets the bool variable m_CtrlPressed */ void mousePressEvent(QMouseEvent *mouseEvent) override; /*! * sets the variable m_MouseDown to false */ void mouseReleaseEvent(QMouseEvent *mouseEvent) override; /*! * causes an update of the sliderbar when resizing the window */ void resizeEvent(QResizeEvent *event) override; -protected slots: +protected Q_SLOTS: - /// hides the scale if "Hide Scale" is selected in contextmenu - void hideScale(); + /** @brief Hide the scale if "Hide Scale" is selected in the context menu + */ + void HideScale(); - /// shows the scale if "Show Scale" is selected in contextmenu - void showScale(); + /** @brief Shows the scale if "Show Scale" is selected in the context menu + */ + void ShowScale(); }; -#endif // QMITKSLIDERLEVELWINDOW_WIDGET + +#endif // QMITKSLIDERLEVELWINDOWWIDGET_H diff --git a/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp b/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp index a70e5b0151..d6805560a9 100644 --- a/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp @@ -1,37 +1,37 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkLevelWindowWidget.h" #include "QmitkSliderLevelWindowWidget.h" QmitkLevelWindowWidget::QmitkLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { this->setupUi(this); m_Manager = mitk::LevelWindowManager::New(); - SliderLevelWindowWidget->setLevelWindowManager(m_Manager.GetPointer()); - LineEditLevelWindowWidget->setLevelWindowManager(m_Manager.GetPointer()); + SliderLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); + LineEditLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); } void QmitkLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds) { m_Manager->SetDataStorage(ds); } mitk::LevelWindowManager *QmitkLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); } diff --git a/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp b/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp index 059c0c8189..3676429edf 100644 --- a/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp +++ b/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp @@ -1,252 +1,305 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ +#include + +// mitk core +#include + +// mitk qt widgets #include "QmitkLevelWindowPresetDefinitionDialog.h" #include "QmitkLevelWindowRangeChangeDialog.h" + +// qt #include -#include -#include QmitkLevelWindowWidgetContextMenu::QmitkLevelWindowWidgetContextMenu(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { m_LevelWindowPreset = mitk::LevelWindowPreset::New(); m_LevelWindowPreset->LoadPreset(); } QmitkLevelWindowWidgetContextMenu::~QmitkLevelWindowWidgetContextMenu() { m_LevelWindowPreset->Delete(); } -void QmitkLevelWindowWidgetContextMenu::setPreset(QAction *presetAction) +void QmitkLevelWindowWidgetContextMenu::OnSetPreset(const QAction *presetAction) { QString item = presetAction->text(); if (!(presetAction == m_PresetAction)) { double dlevel = m_LevelWindowPreset->getLevel(item.toStdString()); double dwindow = m_LevelWindowPreset->getWindow(item.toStdString()); if ((dlevel + dwindow / 2) > m_LevelWindow.GetRangeMax()) { double lowerBound = (dlevel - dwindow / 2); if (!(lowerBound > m_LevelWindow.GetRangeMax())) { dwindow = m_LevelWindow.GetRangeMax() - lowerBound; dlevel = lowerBound + dwindow / 2; } else { dlevel = m_LevelWindow.GetRangeMax() - 1; dwindow = 2; } } else if ((dlevel - dwindow / 2) < m_LevelWindow.GetRangeMin()) { double upperBound = (dlevel + dwindow / 2); if (!(upperBound < m_LevelWindow.GetRangeMin())) { dwindow = m_LevelWindow.GetRangeMin() + upperBound; dlevel = upperBound - dwindow / 2; } else { dlevel = m_LevelWindow.GetRangeMin() + 1; dwindow = 2; } } m_LevelWindow.SetLevelWindow(dlevel, dwindow); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } -void QmitkLevelWindowWidgetContextMenu::setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) +void QmitkLevelWindowWidgetContextMenu::SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) { m_Manager = levelWindowManager; } -void QmitkLevelWindowWidgetContextMenu::addPreset() +void QmitkLevelWindowWidgetContextMenu::OnAddPreset() { QmitkLevelWindowPresetDefinitionDialog addPreset(this); addPreset.setPresets(m_LevelWindowPreset->getLevelPresets(), m_LevelWindowPreset->getWindowPresets(), QString::number((int)m_LevelWindow.GetLevel()), QString::number((int)m_LevelWindow.GetWindow())); if (addPreset.exec()) { m_LevelWindowPreset->newPresets(addPreset.getLevelPresets(), addPreset.getWindowPresets()); } } -void QmitkLevelWindowWidgetContextMenu::setFixed() +void QmitkLevelWindowWidgetContextMenu::OnSetFixed() { m_LevelWindow.SetFixed(!m_LevelWindow.GetFixed()); m_Manager->SetLevelWindow(m_LevelWindow); } -void QmitkLevelWindowWidgetContextMenu::useAllGreyvaluesFromImage() +void QmitkLevelWindowWidgetContextMenu::OnUseAllGreyvaluesFromImage() { m_LevelWindow.SetToImageRange(m_Manager->GetCurrentImage()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::useOptimizedLevelWindow() +void QmitkLevelWindowWidgetContextMenu::OnUseOptimizedLevelWindow() { m_LevelWindow.SetAuto(m_Manager->GetCurrentImage(), false, false); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::setDefaultLevelWindow() +void QmitkLevelWindowWidgetContextMenu::OnSetDefaultLevelWindow() { m_LevelWindow.ResetDefaultLevelWindow(); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::setMaximumWindow() +void QmitkLevelWindowWidgetContextMenu::OnSetMaximumWindow() { m_LevelWindow.SetToMaxWindowSize(); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::setDefaultScaleRange() +void QmitkLevelWindowWidgetContextMenu::OnSetDefaultScaleRange() { m_LevelWindow.ResetDefaultRangeMinMax(); m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), m_LevelWindow.GetWindow()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::changeScaleRange() +void QmitkLevelWindowWidgetContextMenu::OnChangeScaleRange() { QmitkLevelWindowRangeChangeDialog changeRange(this); changeRange.setLowerLimit((mitk::ScalarType)m_LevelWindow.GetRangeMin()); changeRange.setUpperLimit((mitk::ScalarType)m_LevelWindow.GetRangeMax()); if (changeRange.exec()) { m_LevelWindow.SetRangeMinMax(changeRange.getLowerLimit(), changeRange.getUpperLimit()); m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), m_LevelWindow.GetWindow()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } -void QmitkLevelWindowWidgetContextMenu::setImage(QAction *imageAction) +void QmitkLevelWindowWidgetContextMenu::OnSetImage(QAction *imageAction) { - if (imageAction == m_ImageAction) - if (m_Manager->isAutoTopMost() == false) + if (imageAction == m_AutoTopmostAction) + { + if (m_Manager->IsAutoTopMost() == false) + { m_Manager->SetAutoTopMostImage(true); + } else + { m_Manager->SetAutoTopMostImage(false); + } + } + else if(imageAction == m_SelectedImagesAction) + { + if (m_Manager->IsSelectedImages() == false) + { + m_Manager->SetSelectedImages(true); + } + else + { + m_Manager->SetSelectedImages(false); + } + } else - m_Manager->SetLevelWindowProperty(m_Images[imageAction]); + { + m_Manager->SetLevelWindowProperty(m_Images.at(imageAction)); + } } -void QmitkLevelWindowWidgetContextMenu::getContextMenu(QMenu *contextmenu) +void QmitkLevelWindowWidgetContextMenu::GetContextMenu(QMenu *contextMenu) { + if (nullptr == contextMenu) + { + return; + } + try { m_LevelWindow = m_Manager->GetLevelWindow(); - QMenu *contextMenu = contextmenu; - Q_CHECK_PTR(contextMenu); - // contextMenu->setCheckable(true); - QAction *sliderFixed = contextMenu->addAction(tr("Set Slider Fixed"), this, SLOT(setFixed())); + QAction *sliderFixed = contextMenu->addAction(tr("Set slider fixed"), this, &QmitkLevelWindowWidgetContextMenu::OnSetFixed); sliderFixed->setCheckable(true); sliderFixed->setChecked(m_LevelWindow.IsFixed()); contextMenu->addSeparator(); - contextMenu->addAction(tr("Use whole image grey values"), this, SLOT(useAllGreyvaluesFromImage())); - contextMenu->addAction(tr("Use optimized levelwindow"), this, SLOT(useOptimizedLevelWindow())); + contextMenu->addAction(tr("Use whole image grey values"), this, &QmitkLevelWindowWidgetContextMenu::OnUseAllGreyvaluesFromImage); + contextMenu->addAction(tr("Use optimized level-window"), this, &QmitkLevelWindowWidgetContextMenu::OnUseOptimizedLevelWindow); contextMenu->addSeparator(); - contextMenu->addAction(tr("Set Maximum Window"), this, SLOT(setMaximumWindow())); - contextMenu->addAction(tr("Default Level/Window"), this, SLOT(setDefaultLevelWindow())); + contextMenu->addAction(tr("Set maximum window"), this, &QmitkLevelWindowWidgetContextMenu::OnSetMaximumWindow); + contextMenu->addAction(tr("Default level-window"), this, &QmitkLevelWindowWidgetContextMenu::OnSetDefaultLevelWindow); contextMenu->addSeparator(); - contextMenu->addAction(tr("Change Scale Range"), this, SLOT(changeScaleRange())); - contextMenu->addAction(tr("Default Scale Range"), this, SLOT(setDefaultScaleRange())); + contextMenu->addAction(tr("Change scale range"), this, &QmitkLevelWindowWidgetContextMenu::OnChangeScaleRange); + contextMenu->addAction(tr("Default scale range"), this, &QmitkLevelWindowWidgetContextMenu::OnSetDefaultScaleRange); contextMenu->addSeparator(); m_PresetSubmenu = new QMenu(this); - Q_CHECK_PTR(m_PresetSubmenu); m_PresetSubmenu->setTitle("Presets"); - m_PresetAction = m_PresetSubmenu->addAction(tr("Preset Definition"), this, SLOT(addPreset())); + m_PresetAction = m_PresetSubmenu->addAction(tr("Preset definition"), this, &QmitkLevelWindowWidgetContextMenu::OnAddPreset); m_PresetSubmenu->addSeparator(); std::map preset = m_LevelWindowPreset->getLevelPresets(); for (auto iter = preset.begin(); iter != preset.end(); iter++) { QString item = ((*iter).first.c_str()); m_PresetSubmenu->addAction(item); } - connect(m_PresetSubmenu, SIGNAL(triggered(QAction *)), this, SLOT(setPreset(QAction *))); + + connect(m_PresetSubmenu, &QMenu::triggered, this, &QmitkLevelWindowWidgetContextMenu::OnSetPreset); contextMenu->addMenu(m_PresetSubmenu); contextMenu->addSeparator(); - m_ImageSubmenu = new QMenu(this); m_ImageSubmenu->setTitle("Images"); - // m_ImageSubmenu->setCheckable(true); - m_ImageAction = m_ImageSubmenu->addAction(tr("Set Topmost Image")); - m_ImageAction->setCheckable(true); - if (m_Manager->isAutoTopMost()) - m_ImageAction->setChecked(true); + + // add action for "auto topmost image" action + m_AutoTopmostAction = m_ImageSubmenu->addAction(tr("Set topmost image")); + m_AutoTopmostAction->setCheckable(true); + if (m_Manager->IsAutoTopMost()) + { + m_AutoTopmostAction->setChecked(true); + } + + // add action for "selected images" action m_ImageSubmenu->addSeparator(); - Q_CHECK_PTR(m_ImageSubmenu); + m_SelectedImagesAction = m_ImageSubmenu->addAction(tr("Use selected images")); + m_SelectedImagesAction->setCheckable(true); + if (m_Manager->IsSelectedImages()) + { + m_SelectedImagesAction->setChecked(true); + } + + // add action for individual images + m_ImageSubmenu->addSeparator(); + mitk::DataStorage::SetOfObjects::ConstPointer allObjects = m_Manager->GetRelevantNodes(); for (mitk::DataStorage::SetOfObjects::ConstIterator objectIter = allObjects->Begin(); - objectIter != allObjects->End(); - ++objectIter) + objectIter != allObjects->End(); + ++objectIter) { mitk::DataNode *node = objectIter->Value(); - if (node) + if (nullptr == node) { - if (node->IsVisible(nullptr) == false) - continue; - mitk::LevelWindowProperty::Pointer levelWindowProperty = - dynamic_cast(node->GetProperty("levelwindow")); - bool isHelperObject = false; - node->GetBoolProperty("helper object", isHelperObject); - if (levelWindowProperty.IsNotNull() && !isHelperObject) + continue; + } + + bool isHelperObject = false; + node->GetBoolProperty("helper object", isHelperObject); + + if (isHelperObject) + { + continue; + } + + if (!node->IsVisible(nullptr)) + { + continue; + } + + mitk::LevelWindowProperty::Pointer levelWindowProperty = + dynamic_cast(node->GetProperty("levelwindow")); + + if (levelWindowProperty.IsNotNull()) + { + std::string name; + node->GetName(name); + QString item = name.c_str(); + QAction *id = m_ImageSubmenu->addAction(item); + id->setCheckable(true); + m_Images[id] = levelWindowProperty; + if (levelWindowProperty == m_Manager->GetLevelWindowProperty()) { - std::string name; - node->GetName(name); - QString item = name.c_str(); - QAction *id = m_ImageSubmenu->addAction(item); - id->setCheckable(true); - m_Images[id] = levelWindowProperty; - if (levelWindowProperty == m_Manager->GetLevelWindowProperty()) - { - id->setChecked(true); - } + id->setChecked(true); } } } - connect(m_ImageSubmenu, SIGNAL(triggered(QAction *)), this, SLOT(setImage(QAction *))); - contextMenu->addMenu(m_ImageSubmenu); + connect(m_ImageSubmenu, &QMenu::triggered, this, &QmitkLevelWindowWidgetContextMenu::OnSetImage); + + contextMenu->addMenu(m_ImageSubmenu); contextMenu->exec(QCursor::pos()); } catch (...) { } } -void QmitkLevelWindowWidgetContextMenu::getContextMenu() +void QmitkLevelWindowWidgetContextMenu::GetContextMenu() { auto contextMenu = new QMenu(this); - getContextMenu(contextMenu); + GetContextMenu(contextMenu); delete contextMenu; } diff --git a/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp b/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp index be5ad4ac87..6bb58cb3d3 100644 --- a/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp @@ -1,182 +1,172 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkLineEditLevelWindowWidget.h" -#include "QmitkLevelWindowWidgetContextMenu.h" +// mitk core #include +// mitk qt widgets +#include + +// qt #include #include #include + +// itk #include + +// c++ #include #include -using namespace std; - -/** -* Constructor -*/ QmitkLineEditLevelWindowWidget::QmitkLineEditLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Manager = mitk::LevelWindowManager::New(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkLineEditLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; - m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); // true); + m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); auto layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); m_LevelInput = new QLineEdit(this); m_LevelInput->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); m_LevelInput->setToolTip("Edit this field to change the center of the levelwindow."); - // m_LevelInput->setFrameShape( QLineEdit::LineEditPanel ); - // m_LevelInput->setFrameShadow( QLineEdit::Sunken ); m_WindowInput = new QLineEdit(this); m_WindowInput->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); m_WindowInput->setToolTip( "Edit this field to change the span of the levelwindow. This number describes the whole span around the center."); - // m_WindowInput->setFrameShape( QLineEdit::LineEditPanel ); - // m_WindowInput->setFrameShadow( QLineEdit::Sunken ); layout->addWidget(m_LevelInput); layout->addWidget(m_WindowInput); // signals and slots connections connect(m_LevelInput, SIGNAL(editingFinished()), this, SLOT(SetLevelValue())); connect(m_WindowInput, SIGNAL(editingFinished()), this, SLOT(SetWindowValue())); // Validator for both LineEdit-widgets, to limit the valid input-range to int. - // QValidator* validatorWindowInput = new QIntValidator(1, 20000000, this); - QValidator *validatorWindowInput = new QDoubleValidator(0, numeric_limits::max(), 2, this); + QValidator *validatorWindowInput = new QDoubleValidator(0, std::numeric_limits::max(), 2, this); m_WindowInput->setValidator(validatorWindowInput); - // QValidator* validatorLevelInput = new QIntValidator(-10000000, 10000000, this); - // QValidator* validatorLevelInput = new QDoubleValidator(numeric_limits::min(), - // numeric_limits::max(), 2, this); - // m_LevelInput->setValidator(validatorLevelInput); - this->hide(); } QmitkLineEditLevelWindowWidget::~QmitkLineEditLevelWindowWidget() { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } } void QmitkLineEditLevelWindowWidget::OnPropertyModified(const itk::EventObject &) { try { m_LevelWindow = m_Manager->GetLevelWindow(); - // setValidator(); QString level; QString window; if (m_LevelWindow.IsFloatingValues()) { std::stringstream ssLevel; std::stringstream ssWindow; ssLevel << std::setprecision(3) << m_LevelWindow.GetLevel(); ssWindow << std::setprecision(3) << m_LevelWindow.GetWindow(); level = ssLevel.str().c_str(); window = ssWindow.str().c_str(); } else { level.setNum((int)(m_LevelWindow.GetLevel())); window.setNum((int)(m_LevelWindow.GetWindow())); } m_LevelInput->setText(level); m_WindowInput->setText(window); m_LevelInput->setEnabled(!m_LevelWindow.IsFixed()); m_WindowInput->setEnabled(!m_LevelWindow.IsFixed()); this->show(); } catch (...) { try { this->hide(); } catch (...) { } } } -void QmitkLineEditLevelWindowWidget::setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) +void QmitkLineEditLevelWindowWidget::SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } m_Manager = levelWindowManager; if (m_Manager.IsNotNull()) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkLineEditLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; } } void QmitkLineEditLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds) { m_Manager->SetDataStorage(ds); } -// read the levelInput and change level and slider when the button "ENTER" was pressed in the windowInput-LineEdit void QmitkLineEditLevelWindowWidget::SetLevelValue() { double level = m_LevelInput->text().toDouble(); m_LevelWindow.SetLevelWindow(level, m_LevelWindow.GetWindow()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -// read the windowInput and change window and slider when the button "ENTER" was pressed in the windowInput-LineEdit void QmitkLineEditLevelWindowWidget::SetWindowValue() { double window = m_WindowInput->text().toDouble(); m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), window); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLineEditLevelWindowWidget::contextMenuEvent(QContextMenuEvent *) { - m_Contextmenu->setLevelWindowManager(m_Manager.GetPointer()); - m_Contextmenu->getContextMenu(); + m_Contextmenu->SetLevelWindowManager(m_Manager.GetPointer()); + m_Contextmenu->GetContextMenu(); } mitk::LevelWindowManager *QmitkLineEditLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); -} \ No newline at end of file +} diff --git a/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp b/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp index d491d9185c..1642b8c67b 100644 --- a/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp @@ -1,570 +1,554 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include +// mitk core +#include + +// mitk qt widgets +#include + +// qt #include #include #include #include -#include +// itk #include -#include +// c++ #include -/** -* Constructor -*/ -QmitkSliderLevelWindowWidget::QmitkSliderLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) +QmitkSliderLevelWindowWidget::QmitkSliderLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget(parent, f) { m_Manager = mitk::LevelWindowManager::New(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; setMouseTracking(true); m_Resize = false; m_Bottom = false; m_CtrlPressed = false; m_MouseDown = false; m_Font.setPointSize(6); m_MoveHeight = height() - 25; m_ScaleVisible = true; - m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); //, true); - - // setBackgroundMode( Qt::NoBackground ); + m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); this->hide(); - update(); + Update(); } QmitkSliderLevelWindowWidget::~QmitkSliderLevelWindowWidget() { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } } -void QmitkSliderLevelWindowWidget::setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) +void QmitkSliderLevelWindowWidget::SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } m_Manager = levelWindowManager; if (m_Manager.IsNotNull()) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; } } void QmitkSliderLevelWindowWidget::OnPropertyModified(const itk::EventObject &) { try { m_LevelWindow = m_Manager->GetLevelWindow(); this->show(); - update(); + Update(); } catch (...) { try { this->hide(); } catch (...) { } } } void QmitkSliderLevelWindowWidget::paintEvent(QPaintEvent *itkNotUsed(e)) { QPixmap pm(width(), height()); pm.fill(this->palette().color(this->backgroundRole())); QPainter painter(&pm); painter.setFont(m_Font); painter.setPen(this->palette().color(this->foregroundRole())); QColor c(51, 153, 204); QColor cl = c.light(); QColor cd = c.dark(); painter.setBrush(c); painter.drawRect(m_Rect); float mr = m_LevelWindow.GetRange(); float smallestLevelableValue = 1e-9; //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges //from images, but old scene serialization may contain infinite ranges that overwrite the new //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962. //Until LevelWindow and this widget is refactored the check was the minimal invasive fix. if (!std::isfinite(mr)) { mr = m_LevelWindow.GetWindow(); } // avoiding a division by 0 while still enabling small level windows if (mr < smallestLevelableValue) mr = smallestLevelableValue; float fact = (float)m_MoveHeight / mr; // begin draw scale if (m_ScaleVisible) { double minRange = (double)m_LevelWindow.GetRangeMin(); double maxRange = (double)m_LevelWindow.GetRangeMax(); //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges //from images, but old scene serialization may contain infinite ranges that overwrite the new //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962. //Until LevelWindow and this widget is refactored the check was the minimal invasive fix. if (!std::isfinite(minRange)) { minRange = m_LevelWindow.GetLowerWindowBound(); } //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges //from images, but old scene serialization may contain infinite ranges that overwrite the new //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962. //Until LevelWindow and this widget is refactored the check was the minimal invasive fix. if (!std::isfinite(maxRange)) { maxRange = m_LevelWindow.GetUpperWindowBound(); } int yValue = m_MoveHeight + (int)(minRange * fact); QString s = " 0"; if (minRange < 0 && maxRange > 0) { painter.drawLine(5, yValue, 15, yValue); painter.drawText(21, yValue + 3, s); } int count = 1; int k = 5; bool enoughSpace = false; bool enoughSpace2 = false; double dStepSize = pow(10, floor(log10(mr / 100)) + 1); for (int i = m_MoveHeight + (int)(minRange * fact); i < m_MoveHeight;) // negative { if (-count * dStepSize < minRange) { break; } yValue = m_MoveHeight + (int)((minRange + count * dStepSize) * fact); s = QString::number(-count * dStepSize); if (count % k && ((dStepSize * fact) > 2.5)) { painter.drawLine(8, yValue, 12, yValue); enoughSpace = true; } else if (!(count % k)) { if ((k * dStepSize * fact) > 7) { painter.drawLine(5, yValue, 15, yValue); painter.drawText(21, yValue + 3, s); enoughSpace2 = true; } else { k += 5; } } if (enoughSpace) { i = yValue; count++; } else if (enoughSpace2) { i = yValue; count += k; } else { i = yValue; count = k; } } count = 1; k = 5; enoughSpace = false; enoughSpace2 = false; for (int i = m_MoveHeight + (int)(minRange * fact); i >= 0;) { if (count * dStepSize > maxRange) { break; } yValue = m_MoveHeight + (int)((minRange - count * dStepSize) * fact); s = QString::number(count * dStepSize); if (count % k && ((dStepSize * fact) > 2.5)) { if (!(minRange > 0 && (count * dStepSize) < minRange)) painter.drawLine(8, yValue, 12, yValue); enoughSpace = true; } else if (!(count % k)) { if ((k * dStepSize * fact) > 7) { if (!(minRange > 0 && (count * dStepSize) < minRange)) { painter.drawLine(5, yValue, 15, yValue); painter.drawText(21, yValue + 3, s); } enoughSpace2 = true; } else { k += 5; } } if (enoughSpace) { i = yValue; count++; } else if (enoughSpace2) { i = yValue; count += k; } else { i = yValue; count = k; } } } // end draw scale painter.setPen(cl); painter.drawLine(m_Rect.topLeft(), m_Rect.topRight()); painter.drawLine(m_Rect.topLeft(), m_Rect.bottomLeft()); painter.setPen(cd); painter.drawLine(m_Rect.topRight(), m_Rect.bottomRight()); painter.drawLine(m_Rect.bottomRight(), m_Rect.bottomLeft()); painter.end(); QPainter p(this); p.drawPixmap(0, 0, pm); } -/** -* -*/ void QmitkSliderLevelWindowWidget::mouseMoveEvent(QMouseEvent *mouseEvent) { if (!mouseEvent) return; if (m_LevelWindow.IsFixed()) return; if (!m_MouseDown) { if (mouseEvent->pos().y() >= 0 && mouseEvent->pos().y() <= (m_Rect.topLeft().y() + 3)) { setCursor(Qt::SizeVerCursor); m_UpperBound.setRect(m_Rect.topLeft().x(), m_Rect.topLeft().y() - 3, 17, 7); this->setToolTip("Ctrl + left click to change only upper bound"); m_Resize = true; } else if (mouseEvent->pos().y() >= (m_Rect.bottomLeft().y() - 3)) { setCursor(Qt::SizeVerCursor); m_LowerBound.setRect(m_Rect.bottomLeft().x(), m_Rect.bottomLeft().y() - 3, 17, 7); this->setToolTip("Ctrl + left click to change only lower bound"); m_Resize = true; m_Bottom = true; } else { setCursor(Qt::ArrowCursor); this->setToolTip("Left click and mouse move to adjust the slider"); m_Resize = false; m_Bottom = false; } } else { float fact = (float)m_MoveHeight / m_LevelWindow.GetRange(); if (m_Leftbutton) { if (m_Resize && !m_CtrlPressed) { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; if (m_Bottom) value = m_LevelWindow.GetWindow() + ((2 * diff)); else value = m_LevelWindow.GetWindow() - ((2 * diff)); if (value < 0) value = 0; m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), value); } else if (m_Resize && m_CtrlPressed) { if (!m_Bottom) { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; value = m_LevelWindow.GetWindow() - ((diff)); if (value < 0) value = 0; float oldWindow; float oldLevel; float newLevel; oldWindow = m_LevelWindow.GetWindow(); oldLevel = m_LevelWindow.GetLevel(); newLevel = oldLevel + (value - oldWindow) / 2; if (!((newLevel + value / 2) > m_LevelWindow.GetRangeMax())) m_LevelWindow.SetLevelWindow(newLevel, value); } else { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; value = m_LevelWindow.GetWindow() + ((diff)); if (value < 0) value = 0; float oldWindow; float oldLevel; float newLevel; oldWindow = m_LevelWindow.GetWindow(); oldLevel = m_LevelWindow.GetLevel(); newLevel = oldLevel - (value - oldWindow) / 2; if (!((newLevel - value / 2) < m_LevelWindow.GetRangeMin())) m_LevelWindow.SetLevelWindow(newLevel, value); } } else { const float minv = m_LevelWindow.GetRangeMin(); const float level = (m_MoveHeight - mouseEvent->pos().y()) / fact + minv; double diff = (mouseEvent->pos().x()) / fact; diff -= (m_StartPos.x()) / fact; m_StartPos = mouseEvent->pos(); float window; if (m_Bottom) window = m_LevelWindow.GetWindow() + ((2 * diff)); else window = m_LevelWindow.GetWindow() - ((2 * diff)); if (window < 0) window = 0; m_LevelWindow.SetLevelWindow(level, window); } m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } + void QmitkSliderLevelWindowWidget::enterEvent(QEvent * /*event*/) { - /* - if(event->type() != QEvent::MouseMove) - return;*/ - - // mouseMoveEvent( static_cast< QMouseEvent* > ( event ) ); QPoint p = QCursor::pos(); p = this->mapFromGlobal(p); QMouseEvent ev(QEvent::MouseMove, p, Qt::NoButton, Qt::NoButton, Qt::NoModifier); this->mouseMoveEvent(&ev); } -/** -* -*/ void QmitkSliderLevelWindowWidget::mousePressEvent(QMouseEvent *mouseEvent) { if (m_LevelWindow.IsFixed()) return; m_MouseDown = true; m_StartPos = mouseEvent->pos(); if (mouseEvent->button() == Qt::LeftButton) { if (mouseEvent->modifiers() == Qt::ControlModifier || mouseEvent->modifiers() == Qt::ShiftModifier) { m_CtrlPressed = true; } else { m_CtrlPressed = false; } m_Leftbutton = true; } else m_Leftbutton = false; mouseMoveEvent(mouseEvent); } -/** -* -*/ void QmitkSliderLevelWindowWidget::resizeEvent(QResizeEvent *event) { m_MoveHeight = event->size().height() - 25; - update(); + Update(); } -/** -* -*/ void QmitkSliderLevelWindowWidget::mouseReleaseEvent(QMouseEvent *) { if (m_LevelWindow.IsFixed()) return; m_MouseDown = false; } -/** -* -*/ -void QmitkSliderLevelWindowWidget::update() +void QmitkSliderLevelWindowWidget::Update() { int rectWidth; if (m_ScaleVisible) { rectWidth = 17; setMinimumSize(QSize(50, 50)); setMaximumSize(QSize(50, 2000)); setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); } else { rectWidth = 26; setMinimumSize(QSize(40, 50)); setMaximumSize(QSize(50, 2000)); setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); } float mr = m_LevelWindow.GetRange(); if (mr < 1e-9) mr = 1e-9; float fact = (float)m_MoveHeight / mr; float rectHeight = m_LevelWindow.GetWindow() * fact; if (rectHeight < 15) rectHeight = 15; if (m_LevelWindow.GetLowerWindowBound() < 0) m_Rect.setRect(2, (int)(m_MoveHeight - (m_LevelWindow.GetUpperWindowBound() - m_LevelWindow.GetRangeMin()) * fact), rectWidth, (int)rectHeight); else m_Rect.setRect(2, (int)(m_MoveHeight - (m_LevelWindow.GetUpperWindowBound() - m_LevelWindow.GetRangeMin()) * fact), rectWidth, (int)rectHeight); QWidget::repaint(); } void QmitkSliderLevelWindowWidget::contextMenuEvent(QContextMenuEvent *) { - m_Contextmenu->setLevelWindowManager(m_Manager.GetPointer()); + m_Contextmenu->SetLevelWindowManager(m_Manager.GetPointer()); auto contextMenu = new QMenu(this); Q_CHECK_PTR(contextMenu); if (m_ScaleVisible) - contextMenu->addAction(tr("Hide Scale"), this, SLOT(hideScale())); + contextMenu->addAction(tr("Hide Scale"), this, SLOT(HideScale())); else - contextMenu->addAction(tr("Show Scale"), this, SLOT(showScale())); + contextMenu->addAction(tr("Show Scale"), this, SLOT(ShowScale())); contextMenu->addSeparator(); - m_Contextmenu->getContextMenu(contextMenu); + m_Contextmenu->GetContextMenu(contextMenu); // Fix: Bug #13327 we need to reset the m_MouseDown value // otherwise the cursor is not correctly restored afterwards m_MouseDown = false; } -void QmitkSliderLevelWindowWidget::hideScale() +void QmitkSliderLevelWindowWidget::HideScale() { m_ScaleVisible = false; - update(); + Update(); } -void QmitkSliderLevelWindowWidget::showScale() +void QmitkSliderLevelWindowWidget::ShowScale() { m_ScaleVisible = true; - update(); + Update(); } -void QmitkSliderLevelWindowWidget::setDataStorage(mitk::DataStorage *ds) +void QmitkSliderLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds) { m_Manager->SetDataStorage(ds); } mitk::LevelWindowManager *QmitkSliderLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); }