diff --git a/Core/Code/DataManagement/mitkLevelWindowManager.cpp b/Core/Code/DataManagement/mitkLevelWindowManager.cpp index 5140cb17e1..8f6ca0a1ee 100644 --- a/Core/Code/DataManagement/mitkLevelWindowManager.cpp +++ b/Core/Code/DataManagement/mitkLevelWindowManager.cpp @@ -1,388 +1,439 @@ /*=================================================================== 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 #include "mitkDataStorage.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateNot.h" #include "mitkProperties.h" #include "mitkMessage.h" mitk::LevelWindowManager::LevelWindowManager() : m_DataStorage(NULL) , m_LevelWindowProperty(NULL) , m_AutoTopMost(true) , m_IsObserverTagSet(false) , m_CurrentImage(NULL) , m_IsPropertyModifiedTagSet(false) { } mitk::LevelWindowManager::~LevelWindowManager() { if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( - MessageDelegate1( this, &LevelWindowManager::DataStorageChanged )); + MessageDelegate1( this, &LevelWindowManager::DataStorageAddedNode )); m_DataStorage->RemoveNodeEvent.RemoveListener( MessageDelegate1( this, &LevelWindowManager::DataStorageRemovedNode )); m_DataStorage = NULL; } if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } - for( std::map::iterator iter = m_PropObserverToNode.begin(); - iter != m_PropObserverToNode.end(); - ++iter ) - { - (*iter).second->RemoveObserver((*iter).first); - } - - for( std::map::iterator iter = m_PropObserverToNode2.begin(); - iter != m_PropObserverToNode2.end(); - ++iter ) - { - (*iter).second->RemoveObserver((*iter).first); - } + //clear both observer maps + this->ClearPropObserverLists(); } void mitk::LevelWindowManager::SetDataStorage( mitk::DataStorage* ds ) { if (ds == NULL) return; /* remove listeners of old DataStorage */ if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( - MessageDelegate1( this, &LevelWindowManager::DataStorageChanged )); + MessageDelegate1( this, &LevelWindowManager::DataStorageAddedNode )); m_DataStorage->RemoveNodeEvent.RemoveListener( MessageDelegate1( this, &LevelWindowManager::DataStorageRemovedNode )); } /* register listener for new DataStorage */ m_DataStorage = ds; // register m_DataStorage->AddNodeEvent.AddListener( - MessageDelegate1( this, &LevelWindowManager::DataStorageChanged )); + MessageDelegate1( this, &LevelWindowManager::DataStorageAddedNode )); m_DataStorage->RemoveNodeEvent.AddListener( MessageDelegate1( this, &LevelWindowManager::DataStorageRemovedNode )); - this->DataStorageChanged(); // update us with new DataStorage + this->DataStorageAddedNode(); // update us with new DataStorage } void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject& ) { Modified(); } void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode* removedNode) { m_AutoTopMost = autoTopMost; if (m_AutoTopMost == false) return; if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } /* search topmost image */ if (m_DataStorage.IsNull()) { itkExceptionMacro("DataStorage not set"); } int maxLayer = itk::NumericTraits::min(); m_LevelWindowProperty = NULL; mitk::DataNode::Pointer topLevelNode; 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() || (removedNode != NULL && node == removedNode)) continue; node->SetBoolProperty( "imageForLevelWindow", false ); if (node->IsVisible(NULL) == false) continue; int layer = 0; node->GetIntProperty("layer", layer); if ( layer < maxLayer ) continue; mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); if (levelWindowProperty.IsNull()) continue; m_LevelWindowProperty = levelWindowProperty; m_CurrentImage = dynamic_cast(node->GetData()); topLevelNode = node; maxLayer = layer; } if (topLevelNode.IsNotNull()) { topLevelNode->SetBoolProperty( "imageForLevelWindow", true ); } this->SetLevelWindowProperty( m_LevelWindowProperty ); if ( m_LevelWindowProperty.IsNull() ) { Modified(); } // 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; 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; /* search image than belongs to the property */ mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); mitk::DataNode* n = m_DataStorage->GetNode(p); if (n == NULL) { - itkExceptionMacro("No Image in DataStorage that belongs to LevelWindow property " << m_LevelWindowProperty); + mitkThrow() << "No Image in DataStorage that belongs to LevelWindow property" << m_LevelWindowProperty; } m_CurrentImage = dynamic_cast(n->GetData()); n->SetBoolProperty( "imageForLevelWindow", true ); 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!"); } } // sets new Level/Window values and informs all listeners about changes void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow& levelWindow) { if (m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->SetLevelWindow(levelWindow); } this->Modified(); } -void mitk::LevelWindowManager::DataStorageChanged( const mitk::DataNode* ) -{ - this->DataStorageRemovedNode(); -} -void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::DataNode* removedNode ) +void mitk::LevelWindowManager::DataStorageAddedNode( const mitk::DataNode* ) { - /* remove old observers */ - for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin(); - iter != m_PropObserverToNode.end(); - ++iter) - { - (*iter).second->RemoveObserver((*iter).first); - } - m_PropObserverToNode.clear(); - for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin(); - iter != m_PropObserverToNode2.end(); - ++iter) - { - (*iter).second->RemoveObserver((*iter).first); - } - m_PropObserverToNode2.clear(); + //update observers with new data storage + UpdateObservers(); - if (m_DataStorage.IsNull()) - { - itkExceptionMacro("DataStorage not set"); - } + //Initialize LevelWindowsManager to new image + SetAutoTopMostImage(true); - /* listen to changes in visible property of all images */ + //check if everything is still ok + if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || (m_PropObserverToNode2.size() != this->GetRelevantNodes()->size())) + {mitkThrow() << "Wrong number of observers in Level Window Manager!";} - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); - it != all->End(); - ++it) - { - if (it->Value().IsNull()) - continue; +} - /* register listener for changes in visible property */ - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction(this, &LevelWindowManager::Update); - m_PropObserverToNode[it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command )] = it->Value()->GetProperty("visible"); - } +void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::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; + 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; iGetRelevantNodes()->size(); i++) + { + if (this->GetRelevantNodes()->at(i) == removedNode) {removedNodeIsRelevant=true;} + } + if (!removedNodeIsRelevant) return; - /* listen to changes in layer property of all images */ + //remember node which will be removed + m_NodeMarkedToDelete = removedNode; - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); - it != all->End(); - ++it) - { - if (it->Value().IsNull()) - continue; - /* register listener for changes in layer property */ - itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); - command2->SetCallbackFunction(this, &LevelWindowManager::Update); - m_PropObserverToNode2[it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 )] = it->Value()->GetProperty("layer"); - } + //update observers + UpdateObservers(); /* search image than belongs to the property */ if (m_LevelWindowProperty.IsNull()) { SetAutoTopMostImage(true, removedNode); } else { mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); mitk::DataNode* n = m_DataStorage->GetNode(p2); if (n == NULL || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true change level window to topmost node + { SetAutoTopMostImage(true, removedNode); - } + } + } + + //reset variable + m_NodeMarkedToDelete = NULL; + + //check if everything is still ok + if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || (m_PropObserverToNode2.size() != (this->GetRelevantNodes()->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() { return m_DataStorage.GetPointer(); } // true if changes on slider or line-edits will affect always the topmost layer image bool mitk::LevelWindowManager::isAutoTopMost() { return m_AutoTopMost; } void mitk::LevelWindowManager::Update(const itk::EventObject&) // visible property of a image has changed { if (m_AutoTopMost) { SetAutoTopMostImage(true); return; } 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; node->SetBoolProperty( "imageForLevelWindow", false ); if (node->IsVisible(NULL) == false) continue; mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); if (levelWindowProperty.IsNull()) continue; m_LevelWindowProperty = levelWindowProperty; m_CurrentImage = dynamic_cast(node->GetData()); node->SetBoolProperty( "imageForLevelWindow", true ); if (m_LevelWindowProperty.IsNull() && m_LevelWindowProperty.GetPointer() == levelWindowProperty) // we found our m_LevelWindowProperty { return; } } 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::BoolProperty::Pointer trueProp = mitk::BoolProperty::New(true); mitk::NodePredicateProperty::Pointer notBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false)); mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", NULL); 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 isQImage = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New(); predicateTypes->AddPredicate(isImage); predicateTypes->AddPredicate(isDImage); predicateTypes->AddPredicate(isTImage); predicateTypes->AddPredicate(isQImage); mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New(); predicate->AddPredicate(notBinary); predicate->AddPredicate(hasLevelWindow); predicate->AddPredicate(predicateTypes); mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset( predicate ); + return relevantNodes; } mitk::Image* mitk::LevelWindowManager::GetCurrentImage() { return m_CurrentImage; } + +void mitk::LevelWindowManager::ClearPropObserverLists() +{ +for( ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin(); + iter != m_PropObserverToNode.end(); + ++iter ) + { + (*iter).second->RemoveObserver((*iter).first.first); + (*iter).second = 0; + } + m_PropObserverToNode.clear(); + + for( ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin(); + iter != m_PropObserverToNode2.end(); + ++iter ) + { + (*iter).second->RemoveObserver((*iter).first.first); + (*iter).second = 0; + } + m_PropObserverToNode2.clear(); +} + +void mitk::LevelWindowManager::CreatePropObserverLists() +{ + if (m_DataStorage.IsNull()) //check if data storage is set + {itkExceptionMacro("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) + { + 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 idx = it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ); + m_PropObserverToNode[PropDataPair(idx, it->Value())] = it->Value()->GetProperty("visible"); + } + + /* add observers for all layer properties*/ + for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); + it != all->End(); + ++it) + { + if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete)) + {continue;} + /* register listener for changes in layer property */ + itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); + command2->SetCallbackFunction(this, &LevelWindowManager::Update); + unsigned long idx = it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 ); + m_PropObserverToNode2[PropDataPair(idx, it->Value())] = it->Value()->GetProperty("layer"); + } + +} diff --git a/Core/Code/DataManagement/mitkLevelWindowManager.h b/Core/Code/DataManagement/mitkLevelWindowManager.h index 8d322a24ad..0327c51dfb 100644 --- a/Core/Code/DataManagement/mitkLevelWindowManager.h +++ b/Core/Code/DataManagement/mitkLevelWindowManager.h @@ -1,116 +1,142 @@ /*=================================================================== 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 #include "mitkDataStorage.h" #include "mitkLevelWindowProperty.h" #include "mitkBaseProperty.h" #include +#include namespace mitk { /** \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 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 MITK_CORE_EXPORT LevelWindowManager : public itk::Object { public: mitkClassMacro(LevelWindowManager, itk::Object) itkNewMacro(Self); void SetDataStorage(DataStorage* ds); DataStorage* GetDataStorage(); ///< returns the datastorage - /// if autoTopMost == true: sets the topmost layer image to be affected by changes - /// if removedNode != NULL a node was removed from 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 != NULL a node was removed from DataStorage */ void SetAutoTopMostImage(bool autoTopMost, const DataNode* removedNode = NULL); void Update(const itk::EventObject& e); ///< gets called if a visible property changes - /** - * Sets an specific LevelWindowProperty, all changes will affect the image belonging to this property. - */ + /** @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 SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty); - /// sets new Level/Window values and informs all listeners about changes + /** @brief Sets new Level/Window values and informs all listeners about changes. */ void SetLevelWindow(const LevelWindow& levelWindow); - /// returns Level/Window values for the current image + /** @return Returns Level/Window values for the current image.*/ const LevelWindow& GetLevelWindow(); - /// returns the current mitkLevelWindowProperty object from the image that is affected by changes + /** @return Returns the current mitkLevelWindowProperty object from the image that is affected by changes.*/ LevelWindowProperty::Pointer GetLevelWindowProperty(); - /// true if changes on slider or line-edits will affect always the topmost layer image + /** @return true if changes on slider or line-edits will affect always the topmost layer image. */ bool isAutoTopMost(); - /// Change notifications from DataStorage - void DataStorageChanged(const DataNode* n = NULL); + /** @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. + */ + void DataStorageAddedNode(const DataNode* n = NULL); - /// Node removal notifications from DataStorage + /** @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. + */ void DataStorageRemovedNode(const DataNode* removedNode = NULL); - /// change notifications from mitkLevelWindowProperty + /** @brief change notifications from mitkLevelWindowProperty */ void OnPropertyModified(const itk::EventObject& e); Image* GetCurrentImage(); ///< return the currently active image + /** + * @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 */ DataStorage::SetOfObjects::ConstPointer GetRelevantNodes(); protected: LevelWindowManager(); ~LevelWindowManager(); DataStorage::Pointer m_DataStorage; LevelWindowProperty::Pointer m_LevelWindowProperty; ///< pointer to the LevelWindowProperty of the current image - typedef std::map ObserverToPropertyMap; - ObserverToPropertyMap m_PropObserverToNode; ///< map to hold observer IDīs to every visible property of DataNodeīs BaseProperty + typedef std::pair PropDataPair; + typedef std::map ObserverToPropertyMap; + + ObserverToPropertyMap m_PropObserverToNode; ///< map to hold observer IDīs to every visible property of DataNodeīs BaseProperty ObserverToPropertyMap m_PropObserverToNode2; ///< map to hold observer IDīs to every layer 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, NULL otherways) + bool m_AutoTopMost; unsigned long m_ObserverTag; bool m_IsObserverTagSet; unsigned long m_PropertyModifiedTag; Image* m_CurrentImage; bool m_IsPropertyModifiedTagSet; }; } #endif - diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index ef2647c57c..b1ac9f1433 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,93 +1,98 @@ MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) # MITK_INSTALL_TARGETS(EXECUTABLES MitkTestDriver) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_CT mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_MR mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_SC mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkVolumeCalculatorTest_Png2D-bw mitkVolumeCalculatorTest ${MITK_DATA_DIR}/Png2D-bw.png ${MITK_DATA_DIR}/Pic2DplusT.nrrd) mitkAddCustomModuleTest(mitkEventMapperTest_Test1And2 mitkEventMapperTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) #mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/BallBinary30x30x30.nrrd) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.nrrd) mitkAddCustomModuleTest(mitkStateMachineFactoryTest_TestStateMachine1_2 mitkStateMachineFactoryTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkDicomSeriesReaderTest_CTImage mitkDicomSeriesReaderTest ${MITK_DATA_DIR}/TinyCTAbdomen) mitkAddCustomModuleTest(mitkPointSetReaderTest mitkPointSetReaderTest ${MITK_DATA_DIR}/PointSetReaderTestData.mps) mitkAddCustomModuleTest(mitkImageTest_4DImageData mitkImageTest ${MITK_DATA_DIR}/US4DCyl.nrrd) mitkAddCustomModuleTest(mitkImageTest_2D+tImageData mitkImageTest ${MITK_DATA_DIR}/Pic2DplusT.nrrd) mitkAddCustomModuleTest(mitkImageTest_3DImageData mitkImageTest ${MITK_DATA_DIR}/Pic3D.nrrd) mitkAddCustomModuleTest(mitkImageTest_brainImage mitkImageTest ${MITK_DATA_DIR}/brain.mhd) #mitkAddCustomModuleTest(mitkImageTest_color2DImage mitkImageTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) mitkAddCustomModuleTest(mitkIOUtilTest mitkIOUtilTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/pointSet.mps ${MITK_DATA_DIR}/binary.stl ) +mitkAddCustomModuleTest(mitkLevelWindowManagerTest mitkLevelWindowManagerTest + ${MITK_DATA_DIR}/Pic3D.nrrd +) + + if(WIN32 OR APPLE OR MITK_ENABLE_GUI_TESTING) ### since the rendering test's do not run in ubuntu, yet, we build them only for other systems or if the user explicitly sets the variable MITK_ENABLE_GUI_TESTING mitkAddCustomModuleTest(mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2DTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/rgbaImage640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3d640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2DColorTest #test for color property (=blue) Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dColorBlue640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2DLevelWindowTest #test for levelwindow property (=blood) #Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dLevelWindowBlood640x480REF.png #corresponding reference #screenshot ) #mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dOpacity640x480 mitkImageVtkMapper2DOpacityTest #test for opacity (=0.5) Pic3D coronal slice # ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage # -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dOpacity640x480REF.png #corresponding reference screenshot #) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DSwivelTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dSwivel640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkSurfaceVtkMapper3DTest_TextureProperty mitkSurfaceVtkMapper3DTest ${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom.vtp ${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom_RGBImage.nrrd -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedLiver640x480REF.png #corresponding reference screenshot ) #mitkAddCustomModuleTest(mitkSurfaceVtkMapper3DTexturedSphereTest_Football mitkSurfaceVtkMapper3DTexturedSphereTest # ${MITK_DATA_DIR}/RenderingTestData/texture.jpg #input texture # -V # ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedSphere640x480REF.png corresponding reference screenshot #) SET_PROPERTY(TEST mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2D_pic3dSwivel640x480 #mitkSurfaceVtkMapper3DTest_TextureProperty #mitkSurfaceVtkMapper3DTexturedSphereTest_Football #mitkImageVtkMapper2D_pic3dOpacity640x480 PROPERTY RUN_SERIAL TRUE) endif() add_test(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) set_property(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) add_test(mitkImageWriterTest_nrrdImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) add_test(mitkImageWriterTest_2DPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/Png2D-bw.png) add_test(mitkImageWriterTest_rgbPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/RenderingTestData/rgbImage.png) add_test(mitkImageWriterTest_rgbaPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png) set_property(TEST mitkImageWriterTest_nrrdImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_2DPNGImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_rgbPNGImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_rgbaPNGImage PROPERTY LABELS MITK-Core) add_subdirectory(DICOMTesting) diff --git a/Core/Code/Testing/files.cmake b/Core/Code/Testing/files.cmake index ce2d17ff52..a11495c505 100644 --- a/Core/Code/Testing/files.cmake +++ b/Core/Code/Testing/files.cmake @@ -1,128 +1,128 @@ # tests with no extra command line parameter set(MODULE_TESTS mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkDispatcherTest.cpp mitkEnumerationPropertyTest.cpp mitkEventTest.cpp mitkEventConfigTest.cpp mitkFocusManagerTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkGlobalInteractionTest.cpp mitkImageDataItemTest.cpp #mitkImageMapper2DTest.cpp mitkImageGeneratorTest.cpp mitkBaseDataTest.cpp #mitkImageToItkTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkInteractorTest.cpp mitkInteractionEventTest.cpp mitkITKThreadingTest.cpp - # mitkLevelWindowManagerTest.cpp mitkLevelWindowTest.cpp mitkMessageTest.cpp #mitkPipelineSmartPointerCorrectnessTest.cpp mitkPixelTypeTest.cpp mitkPlaneGeometryTest.cpp mitkPointSetFileIOTest.cpp mitkPointSetTest.cpp mitkPointSetWriterTest.cpp mitkPointSetReaderTest.cpp mitkPointSetInteractorTest.cpp mitkPropertyTest.cpp mitkPropertyListTest.cpp #mitkRegistrationBaseTest.cpp #mitkSegmentationInterpolationTest.cpp mitkSlicedGeometry3DTest.cpp mitkSliceNavigationControllerTest.cpp mitkStateMachineTest.cpp mitkStateMachineContainerTest.cpp mitkStateTest.cpp mitkSurfaceTest.cpp mitkSurfaceToSurfaceFilterTest.cpp mitkTimeSlicedGeometryTest.cpp mitkTransitionTest.cpp mitkUndoControllerTest.cpp mitkVtkWidgetRenderingTest.cpp mitkVerboseLimitedLinearUndoTest.cpp mitkWeakPointerTest.cpp mitkTransferFunctionTest.cpp #mitkAbstractTransformGeometryTest.cpp mitkStepperTest.cpp itkTotalVariationDenoisingImageFilterTest.cpp mitkRenderingManagerTest.cpp vtkMitkThickSlicesFilterTest.cpp mitkNodePredicateSourceTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp #QmitkRenderingTestHelper.cpp mitkExceptionTest.cpp mitkExtractSliceFilterTest.cpp mitkLogTest.cpp mitkImageDimensionConverterTest.cpp mitkLoggingAdapterTest.cpp mitkUIDGeneratorTest.cpp ) # test with image filename as an extra command line parameter set(MODULE_IMAGE_TESTS mitkPlanePositionManagerTest.cpp mitkSurfaceVtkWriterTest.cpp #mitkImageSliceSelectorTest.cpp mitkImageTimeSelectorTest.cpp # mitkVtkPropRendererTest.cpp mitkDataNodeFactoryTest.cpp #mitkSTLFileReaderTest.cpp mitkImageAccessorTest.cpp ) # list of images for which the tests are run set(MODULE_TESTIMAGES # Pic-Factory no more available in Core, test images now in .nrrd format US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd binary.stl ball.stl ) set(MODULE_CUSTOM_TESTS #mitkLabeledImageToSurfaceFilterTest.cpp #mitkExternalToolsTest.cpp mitkDataStorageTest.cpp mitkDataNodeTest.cpp mitkDicomSeriesReaderTest.cpp mitkDICOMLocaleTest.cpp mitkEventMapperTest.cpp mitkNodeDependentPointSetInteractorTest.cpp mitkStateMachineFactoryTest.cpp mitkPointSetLocaleTest.cpp mitkImageTest.cpp mitkImageWriterTest.cpp mitkImageVtkMapper2DTest.cpp mitkImageVtkMapper2DLevelWindowTest.cpp mitkImageVtkMapper2DOpacityTest.cpp mitkImageVtkMapper2DColorTest.cpp mitkImageVtkMapper2DSwivelTest.cpp mitkIOUtilTest.cpp mitkSurfaceVtkMapper3DTest mitkSurfaceVtkMapper3DTexturedSphereTest.cpp mitkVolumeCalculatorTest.cpp + mitkLevelWindowManagerTest.cpp ) # Create an artificial module initializing class for # the usServiceListenerTest.cpp usFunctionGenerateModuleInit(testdriver_init_file NAME ${MODULE_NAME}TestDriver DEPENDS "Mitk" VERSION "0.1.0" EXECUTABLE ) set(TEST_CPP_FILES ${testdriver_init_file} mitkRenderingTestHelper.cpp) diff --git a/Core/Code/Testing/mitkLevelWindowManagerTest.cpp b/Core/Code/Testing/mitkLevelWindowManagerTest.cpp index a845b2ca55..0ec80fd91b 100644 --- a/Core/Code/Testing/mitkLevelWindowManagerTest.cpp +++ b/Core/Code/Testing/mitkLevelWindowManagerTest.cpp @@ -1,97 +1,157 @@ /*=================================================================== 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 "mitkStandaloneDataStorage.h" +#include +#include -int mitkLevelWindowManagerTest(int, char* []) +class mitkLevelWindowManagerTestClass { +public: + + static void TestInstantiation() + { mitk::LevelWindowManager::Pointer manager; - std::cout << "Testing mitk::LevelWindowManager::New(): "; manager = mitk::LevelWindowManager::New(); - if (manager.IsNull()) - { - std::cout<<"[FAILED]"<SetDataStorage(ds); - std::cout<<"[PASSED]"<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 "); - std::cout << "Testing mitk::LevelWindowManager GetDataStorage "; - if (ds != manager->GetDataStorage()) - { - std::cout<<"[FAILED]"<SetLevelWindowProperty(levelWindowProperty); - std::cout<<"[PASSED]"<GetLevelWindowProperty()) + static void TestMethodsWithInvalidParameters() { - std::cout<<"[FAILED]"<SetDataStorage(ds); + + bool success = false; + mitk::LevelWindowProperty::Pointer levelWindowProperty = mitk::LevelWindowProperty::New(); + try + { + manager->SetLevelWindowProperty(levelWindowProperty); + } + catch(mitk::Exception e) + { + success = true; + } + MITK_TEST_CONDITION(success,"Testing mitk::LevelWindowManager SetLevelWindowProperty with invalid parameter"); } - std::cout<<"[PASSED]"<isAutoTopMost()) + + static void TestOtherMethods() { - std::cout<<"[FAILED]"<SetDataStorage(ds); + + MITK_TEST_CONDITION(manager->isAutoTopMost(),"Testing mitk::LevelWindowManager isAutoTopMost"); - std::cout << "Testing mitk::LevelWindowManager GetLevelWindow "; + bool success = true; try { - const mitk::LevelWindow levelWindow = manager->GetLevelWindow(); - std::cout<<"[PASSED]"<GetLevelWindow(); manager->SetLevelWindow(levelWindow); - std::cout<<"[PASSED]"<SetAutoTopMostImage(true); - std::cout<<"[PASSED]"<isAutoTopMost())) + MITK_TEST_CONDITION(manager->isAutoTopMost(),"Testing mitk::LevelWindowManager isAutoTopMost()"); + } + + static void TestRemoveObserver(std::string testImageFile) { - std::cout<<"[FAILED]"<SetDataStorage(ds); + + //add multiple objects to the data storage => multiple observers should be created + mitk::Image::Pointer image1 = mitk::IOUtil::LoadImage(testImageFile); + mitk::DataNode::Pointer node1 = mitk::DataNode::New(); + node1->SetData(image1); + mitk::Image::Pointer image2 = mitk::IOUtil::LoadImage(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(manager->GetRelevantNodes()->size() == manager->GetNumberOfObservers(), "Test if number of nodes is similar to number of observers"); + + mitk::Image::Pointer image3 = mitk::IOUtil::LoadImage(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(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())"); + } - std::cout<<"[PASSED]"<= 2, "Testing if test file is given."); + std::string testImage = args[1]; + + mitkLevelWindowManagerTestClass::TestInstantiation(); + mitkLevelWindowManagerTestClass::TestSetGetDataStorage(); + mitkLevelWindowManagerTestClass::TestMethodsWithInvalidParameters(); + mitkLevelWindowManagerTestClass::TestOtherMethods(); + mitkLevelWindowManagerTestClass::TestRemoveObserver(testImage); + + MITK_TEST_END(); }