diff --git a/Modules/Core/include/mitkIPropertyDescriptions.h b/Modules/Core/include/mitkIPropertyDescriptions.h index c4bd599ba5..ba7633ee7d 100644 --- a/Modules/Core/include/mitkIPropertyDescriptions.h +++ b/Modules/Core/include/mitkIPropertyDescriptions.h @@ -1,81 +1,93 @@ /*=================================================================== 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 mitkIPropertyDescriptions_h #define mitkIPropertyDescriptions_h #include #include #include namespace mitk { /** * \ingroup MicroServices_Interfaces * \brief Interface of property descriptions service. * * This service allows you to manage descriptions for properties. * The property view displays descriptions of selected properties (in rich text format) at its bottom. */ class MITKCORE_EXPORT IPropertyDescriptions { public: virtual ~IPropertyDescriptions(); /** \brief Add a description for a specific property. * * \param[in] propertyName Name of the property. * \param[in] description Description of the property. * \param[in] className Optional data node class name to which this description is restricted. * \param[in] overwrite Overwrite already existing description. * \return True if description was added successfully. */ virtual bool AddDescription(const std::string& propertyName, const std::string& description, const std::string& className = "", bool overwrite = false) = 0; + /** \brief Add a description for all properties matching the property regulary expression. + * + * \param[in] propertyRegEx String of the regular expression specifing all relevant property names. + * \param[in] description Description of the property. + * \param[in] className Optional data node class name to which this description is restricted. + * \param[in] overwrite Overwrite already existing description. + * \return True if description was added successfully. + */ + virtual bool AddDescriptionRegEx(const std::string& propertyRegEx, const std::string& description, const std::string& className = "", bool overwrite = false) = 0; + /** \brief Get the description for a specific property. * * \param[in] propertyName Name of the property. * \param[in] className Optional data node class name to which the returned description is restricted. + * \param[in] allowNameRegEx Indicates of also regular expressions should be regarded. * \return Property description or empty string if no description is available. */ - virtual std::string GetDescription(const std::string& propertyName, const std::string& className = "") = 0; + virtual std::string GetDescription(const std::string& propertyName, const std::string& className = "", bool allowNameRegEx = true) const = 0; /** \brief Check if a specific property has a description. * * \param[in] propertyName Name of the property. * \param[in] className Optional data node class name to which this description is restricted. + * \param[in] allowNameRegEx Indicates of also regular expressions should be regarded. * \return True if the property has a description, false otherwise. */ - virtual bool HasDescription(const std::string& propertyName, const std::string& className = "") = 0; + virtual bool HasDescription(const std::string& propertyName, const std::string& className = "", bool allowNameRegEx = true) const = 0; /** \brief Remove all descriptions. * * \param[in] className Optional data node class name to which this description is restricted. */ virtual void RemoveAllDescriptions(const std::string& className = "") = 0; /** \brief Remove description of specific property. * * \param[in] propertyName Name of the property. * \param[in] className Optional data node class name to which this description is restricted. */ virtual void RemoveDescription(const std::string& propertyName, const std::string& className = "") = 0; }; } MITK_DECLARE_SERVICE_INTERFACE(mitk::IPropertyDescriptions, "org.mitk.IPropertyDescriptions") #endif diff --git a/Modules/Core/include/mitkIPropertyPersistence.h b/Modules/Core/include/mitkIPropertyPersistence.h index 7af8014663..168d99fdf5 100644 --- a/Modules/Core/include/mitkIPropertyPersistence.h +++ b/Modules/Core/include/mitkIPropertyPersistence.h @@ -1,107 +1,115 @@ /*=================================================================== 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 mitkIPropertyPersistence_h #define mitkIPropertyPersistence_h #include #include namespace mitk { /** \ingroup MicroServices_Interfaces * \brief Interface of property persistence service * * This service allows you to manage persistence info for base data properties. - * Persistent properties will be saved if the file format supports custom key value pairs like the .nrrd file format. + * Persistent properties will be saved if the file format supports custom key value pairs like the .nrrd file format.\n + * \remark The service supports the use of regular expressions (regex; ECMAscript syntax) + * for property names and persistance keys to specifiy persistence rules in a generic way. The getter of the interface + * (GetInfo and GetInfoByKey) will always ensure that the return containes no regex, thus name and key in the results + * can directly be used. For details on how the result names and keys are determined, please @TODO + * */ class MITKCORE_EXPORT IPropertyPersistence { public: virtual ~IPropertyPersistence(); - using InfoMapType = std::multimap ; + using InfoResultType = std::list; using MimeTypeNameType = PropertyPersistenceInfo::MimeTypeNameType; /** \brief Add persistence info for a specific base data property. - * If there is already a property info instances for the passed - * property name and the same info, it won't be added. Infos are - * regarded equal, if the mime types are equal. - * You may enforce to overrite the old equal info for a property name - * by the overweite parameter. + * If there is already a property info instance for the passed + * property name and the same info, it won't be added. Info instances + * are regarded equal, if the mime types are equal. + * You may enforce to overwrite the old equal info for a property name + * by the overwrite parameter. * * \param[in] propertyName Name of the property. * \param[in] info Persistence info of the property. * \param[in] overwrite Overwrite already existing persistence info. * \return True if persistence info was added successfully. */ - virtual bool AddInfo(const std::string& propertyName, PropertyPersistenceInfo::Pointer info, bool overwrite = false) = 0; + virtual bool AddInfo(const PropertyPersistenceInfo* info, bool overwrite = false) = 0; /** \brief Get the persistence info for a specific base data property. - * * \param[in] propertyName Name of the property. + * \param[in] allowNameRegEx Indicates if also added info instances with regexs are being checked. * \return Property persistence info or null pointer if no persistence info is available. */ - virtual InfoMapType GetInfos(const std::string& propertyName) = 0; + virtual InfoResultType GetInfo(const std::string& propertyName, bool allowNameRegEx = true) const = 0; - /** \brief Get the persistence info that will use the specified key. + /** \brief Get the persistence info for a specific base data property and mime type. * * \param[in] propertyName Name of the property. + * \param[in] mime Name of the mime type the info is specified for. + * \param[in] allowMimeWildCard Indicates if wildcard is allowed. If it is allowed, the method will first try to find the specified info. + * If no info was found but an info exists with the mime type name PropertyPersistenceInfo::ANY_MIMETYPE_NAME(), the later info will be + * returned as fall back option. + * \param[in] allowNameRegEx Indicates if also added info instances with regexs are being checked. * \return Property persistence info or null pointer if no persistence info is available. */ - virtual InfoMapType GetInfosByKey(const std::string& persistenceKey) = 0; + virtual InfoResultType GetInfo(const std::string& propertyName, const MimeTypeNameType& mime, bool allowMimeWildCard = false, bool allowNameRegEx = true) const = 0; - /** \brief Get the persistence info for a specific base data property and mime type. + /** \brief Get the persistence info that will use the specified key. * * \param[in] propertyName Name of the property. - * \param[in] mime Name of the mime type the info is specified for. - * \param[in] allowWildCard Indicates if wildcard is allowed. If it is allowed, the method will first try to find the specified info. - * If no info was found but an info exists with the mime type name PropertyPersistenceInfo::ANY_MIMETYPE_NAME(), the later info will be - * returned as fall back option. + * \param[in] allowKeyRegEx Indicates if also added info instances with regexs for the key are being checked. * \return Property persistence info or null pointer if no persistence info is available. */ - virtual PropertyPersistenceInfo::Pointer GetInfo(const std::string& propertyName, const MimeTypeNameType& mime, bool allowWildCard = false) = 0; + virtual InfoResultType GetInfoByKey(const std::string& persistenceKey, bool allowKeyRegEx = true) const = 0; /** \brief Check if a specific base data property has persistence info. * * \param[in] propertyName Name of the property. + * \param[in] allowNameRegEx Indicates if also added info instances with regexs are being checked. * \return True if the property has persistence info, false otherwise. */ - virtual bool HasInfos(const std::string& propertyName) = 0; + virtual bool HasInfo(const std::string& propertyName, bool allowNameRegEx = true) const = 0; /** \brief Remove all persistence info. */ - virtual void RemoveAllInfos() = 0; + virtual void RemoveAllInfo() = 0; - /** \brief Remove persistence infos of a specific property name. + /** \brief Remove persistence info instances of a specific property name/regex. * - * \param[in] propertyName Name of the property. + * \param[in] propertyName Registered name or regex that should be removed. */ - virtual void RemoveInfos(const std::string& propertyName) = 0; + virtual void RemoveInfo(const std::string& propertyName) = 0; - /** \brief Remove persistence infos of a specific property name and mime type. + /** \brief Remove persistence info instances of a specific property name/regex and mime type. * - * \param[in] propertyName Name of the property. + * \param[in] propertyName Registered name or regex that should be removed. * \param[in] mime Name of the mime type. */ - virtual void RemoveInfos(const std::string& propertyName, const MimeTypeNameType& mime) = 0; + virtual void RemoveInfo(const std::string& propertyName, const MimeTypeNameType& mime) = 0; }; } MITK_DECLARE_SERVICE_INTERFACE(mitk::IPropertyPersistence, "org.mitk.IPropertyPersistence") #endif diff --git a/Modules/Core/include/mitkPropertyDescriptions.h b/Modules/Core/include/mitkPropertyDescriptions.h index 3747d5e2fe..0ba4e31f5a 100644 --- a/Modules/Core/include/mitkPropertyDescriptions.h +++ b/Modules/Core/include/mitkPropertyDescriptions.h @@ -1,49 +1,51 @@ /*=================================================================== 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 mitkPropertyDescriptions_h #define mitkPropertyDescriptions_h #include #include namespace mitk { class PropertyDescriptions : public IPropertyDescriptions { public: PropertyDescriptions(); ~PropertyDescriptions(); bool AddDescription(const std::string& propertyName, const std::string& description, const std::string& className, bool overwrite) override; - std::string GetDescription(const std::string& propertyName, const std::string& className) override; - bool HasDescription(const std::string& propertyName, const std::string& className) override; + bool AddDescriptionRegEx(const std::string& propertyRegEx, const std::string& description, const std::string& className, bool overwrite) override; + std::string GetDescription(const std::string& propertyName, const std::string& className, bool overwrite) const override; + bool HasDescription(const std::string& propertyName, const std::string& className, bool overwrite) const override; void RemoveAllDescriptions(const std::string& className) override; void RemoveDescription(const std::string& propertyName, const std::string& className) override; private: typedef std::map DescriptionMap; typedef DescriptionMap::const_iterator DescriptionMapConstIterator; typedef DescriptionMap::iterator DescriptionMapIterator; PropertyDescriptions(const PropertyDescriptions&); PropertyDescriptions& operator=(const PropertyDescriptions&); std::map m_Descriptions; + std::map m_DescriptionsRegEx; }; } #endif diff --git a/Modules/Core/include/mitkPropertyPersistence.h b/Modules/Core/include/mitkPropertyPersistence.h index f561b330c3..57beb42d17 100644 --- a/Modules/Core/include/mitkPropertyPersistence.h +++ b/Modules/Core/include/mitkPropertyPersistence.h @@ -1,57 +1,59 @@ /*=================================================================== 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 mitkPropertyPersistence_h #define mitkPropertyPersistence_h #include #include namespace mitk { class PropertyPersistence : public IPropertyPersistence { public: PropertyPersistence(); ~PropertyPersistence(); - typedef IPropertyPersistence::InfoMapType InfoMapType; + typedef IPropertyPersistence::InfoResultType InfoResultType; - bool AddInfo(const std::string& propertyName, PropertyPersistenceInfo::Pointer info, bool overwrite) override; - InfoMapType GetInfos(const std::string& propertyName) override; - InfoMapType GetInfosByKey(const std::string& persistenceKey) override; - PropertyPersistenceInfo::Pointer GetInfo(const std::string& propertyName, const MimeTypeNameType& mime, bool allowWildCard) override; - bool HasInfos(const std::string& propertyName) override; - void RemoveAllInfos() override; - void RemoveInfos(const std::string& propertyName) override; - void RemoveInfos(const std::string& propertyName, const MimeTypeNameType& mime) override; + bool AddInfo(const PropertyPersistenceInfo* info, bool overwrite) override; + InfoResultType GetInfo(const std::string& propertyName, bool allowNameRegEx) const override; + InfoResultType GetInfo(const std::string& propertyName, const MimeTypeNameType& mime, bool allowMimeWildCard, bool allowNameRegEx) const override; + InfoResultType GetInfoByKey(const std::string& persistenceKey, bool allowKeyRegEx) const override; + bool HasInfo(const std::string& propertyName, bool allowNameRegEx) const override; + void RemoveAllInfo() override; + void RemoveInfo(const std::string& propertyName) override; + void RemoveInfo(const std::string& propertyName, const MimeTypeNameType& mime) override; private: - typedef std::multimap InfoMap; - typedef InfoMap::const_iterator InfoMapConstIterator; - typedef InfoMap::iterator InfoMapIterator; + typedef std::multimap InfoMap; + + /**Helper function that selects */ + using SelectFunctionType = std::function < bool(const InfoMap::value_type&) >; + static InfoMap SelectInfo(const InfoMap& infoMap, const SelectFunctionType& selectFunction); PropertyPersistence(const PropertyPersistence&); PropertyPersistence& operator=(const PropertyPersistence&); - InfoMap m_Infos; + InfoMap m_InfoMap; }; /**Creates an unmanaged (!) instance of PropertyPersistence for testing purposes.*/ MITKCORE_EXPORT IPropertyPersistence* CreateTestInstancePropertyPersistence(); } #endif diff --git a/Modules/Core/include/mitkPropertyPersistenceInfo.h b/Modules/Core/include/mitkPropertyPersistenceInfo.h index bb19e8ed2f..41d42569f1 100644 --- a/Modules/Core/include/mitkPropertyPersistenceInfo.h +++ b/Modules/Core/include/mitkPropertyPersistenceInfo.h @@ -1,104 +1,126 @@ /*=================================================================== 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 mitkPropertyPersistenceInfo_h #define mitkPropertyPersistenceInfo_h #include #include #include #include #include namespace mitk { /** \brief Property persistence info. This class is used to specify the way the persistance of a property of BaseData derived instances is handled. The info specifies the key for property, as well as the mime type the info is defined for and should be used. Additionally the functions for deserialization and serialization of the property can be defined. As default */ class MITKCORE_EXPORT PropertyPersistenceInfo : public itk::LightObject { public: using DeserializationFunctionType = std::function < mitk::BaseProperty::Pointer(const std::string&) > ; using SerializationFunctionType = std::function < std::string(const mitk::BaseProperty*) > ; using MimeTypeNameType = std::string; mitkClassMacroItkParent(PropertyPersistenceInfo, itk::LightObject); itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(Self, const std::string&); mitkNewMacro2Param(Self, const std::string&, const std::string&); + std::string GetName() const; std::string GetKey() const; - void SetKey(const std::string& key); + void SetName(const std::string& name); + void SetNameAndKey(const std::string& name, const std::string& key); - const MimeTypeNameType GetMimeTypeName() const; + bool IsRegEx() const; + + /** Sets the name and the key identifier as a regular expression that describes valid names and keys. + * @pre nameRegEx must be a valid regular expression, otherweis a regex_error esception + * is thrown and the info object is not changed. + * @pre keyRegEx must be a valid regular expression, otherweis a regex_error esception + * is thrown and the info object is not changed.*/ + void UseRegEx(const std::string& nameRegEx, const std::string& nameTemplate); + void UseRegEx(const std::string& nameRegEx, const std::string& nameTemplate, const std::string& keyRegEx, const std::string keyTemplate); + + const std::string& GetKeyTemplate() const; + const std::string& GetNameTemplate() const; + + const MimeTypeNameType& GetMimeTypeName() const; void SetMimeTypeName(const MimeTypeNameType& mimeTypeName); const DeserializationFunctionType GetDeserializationFunction() const; void SetDeserializationFunction(const DeserializationFunctionType& fnc); const SerializationFunctionType GetSerializationFunction() const; void SetSerializationFunction(const SerializationFunctionType& fnc); + PropertyPersistenceInfo::Pointer UnRegExByName(const std::string& propertyName) const; + PropertyPersistenceInfo::Pointer UnRegExByKey(const std::string& key) const; + /** This mime type name indicates that a info can be used for any mime type as long as - not another info with a more specific mime type is available.*/ + another info with a more specific mime type is not available.*/ static MimeTypeNameType ANY_MIMETYPE_NAME(); protected: /** \brief Constructor. * - * \param[in] key Key used to save the property value as key value pair. If empty, the property name is used. + * \param[in] name Name is the name of the property that described by the info. Key will be the same. */ - PropertyPersistenceInfo(const std::string& key = ""); + PropertyPersistenceInfo(const std::string& name = ""); /** \brief Constructor. * - * \param[in] key Key used to save the property value as key value pair. + * \param[in] name Name is the name of the property that described by the info. Key will be the same. * \param[in] mimeTypeName mime type the info is defined for. */ - PropertyPersistenceInfo(const std::string& key, const std::string& mimeTypeName); + PropertyPersistenceInfo(const std::string& name, const std::string& mimeTypeName); + virtual ~PropertyPersistenceInfo(); + virtual void PrintSelf(std::ostream & os, itk::Indent indent) const override; + private: PropertyPersistenceInfo(const Self& other); Self& operator=(const Self& other); struct Impl; Impl* m_Impl; }; + MITKCORE_EXPORT std::ostream& operator << (std::ostream& os, const PropertyPersistenceInfo& info); namespace PropertyPersistenceSerialization { /** Simple default serialization that uses prop->GetValueAsString for the serialization.*/ MITKCORE_EXPORT ::std::string serializeByGetValueAsString(const mitk::BaseProperty* prop); } namespace PropertyPersistenceDeserialization { /** Simple default functions that puts the passed string into a string property.*/ MITKCORE_EXPORT mitk::BaseProperty::Pointer deserializeToStringProperty(const std::string& value); } } #endif diff --git a/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp b/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp index 73356ffa87..673fd89f20 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp @@ -1,78 +1,160 @@ /*=================================================================== 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 "mitkPropertyDescriptions.h" #include #include +#include mitk::PropertyDescriptions::PropertyDescriptions() { } mitk::PropertyDescriptions::~PropertyDescriptions() { } bool mitk::PropertyDescriptions::AddDescription(const std::string& propertyName, const std::string& description, const std::string& className, bool overwrite) { if (propertyName.empty()) return false; DescriptionMap& descriptions = m_Descriptions[className]; std::pair ret = descriptions.insert(std::make_pair(propertyName, description)); if (!ret.second && overwrite) { ret.first->second = description; ret.second = true; } return ret.second; } -std::string mitk::PropertyDescriptions::GetDescription(const std::string& propertyName, const std::string& className) +bool mitk::PropertyDescriptions::AddDescriptionRegEx(const std::string& propertyRegEx, const std::string& description, const std::string& className, bool overwrite) +{ + if (propertyRegEx.empty()) + return false; + + try + { + std::regex checker(propertyRegEx); //no exception => valid we can change the info + } + catch (std::regex_error) + { + return false; + } + + DescriptionMap& descriptions = m_DescriptionsRegEx[className]; + std::pair ret = descriptions.insert(std::make_pair(propertyRegEx, description)); + + if (!ret.second && overwrite) + { + ret.first->second = description; + ret.second = true; + } + + return ret.second; +} + +std::string mitk::PropertyDescriptions::GetDescription(const std::string& propertyName, const std::string& className, bool allowNameRegEx) const { if (!propertyName.empty()) { - DescriptionMap& descriptions = m_Descriptions[className]; - DescriptionMapConstIterator iter = descriptions.find(propertyName); + auto descriptionsIter = m_Descriptions.find(className); + + if (descriptionsIter != m_Descriptions.cend()) + { + DescriptionMapConstIterator iter = descriptionsIter->second.find(propertyName); - if (iter != descriptions.end()) - return iter->second; + if (iter != descriptionsIter->second.end()) + return iter->second; + } + } + + if (allowNameRegEx && !propertyName.empty()) + { + auto selector = [propertyName](const DescriptionMap::value_type& x) + { + std::regex ex(x.first); + return std::regex_match(propertyName, ex); + }; + + auto descriptionsIter = m_DescriptionsRegEx.find(className); + + if (descriptionsIter != m_DescriptionsRegEx.cend()) + { + auto finding = std::find_if(descriptionsIter->second.cbegin(), descriptionsIter->second.cend(), selector); + + if (finding != descriptionsIter->second.cend()) + return finding->second; + } } return ""; } -bool mitk::PropertyDescriptions::HasDescription(const std::string& propertyName, const std::string& className) +bool mitk::PropertyDescriptions::HasDescription(const std::string& propertyName, const std::string& className, bool allowNameRegEx) const { - const DescriptionMap& descriptions = m_Descriptions[className]; + if (!propertyName.empty()) + { + auto descriptionsIter = m_Descriptions.find(className); - return !propertyName.empty() - ? descriptions.find(propertyName) != descriptions.end() - : false; + if (descriptionsIter != m_Descriptions.cend()) + { + DescriptionMapConstIterator iter = descriptionsIter->second.find(propertyName); + + if (iter != descriptionsIter->second.end()) + return true; + } + } + + if (allowNameRegEx && !propertyName.empty()) + { + auto selector = [propertyName](const DescriptionMap::value_type& x) + { + std::regex ex(x.first); + return std::regex_match(propertyName, ex); + }; + + auto descriptionsIter = m_DescriptionsRegEx.find(className); + + if (descriptionsIter != m_DescriptionsRegEx.cend()) + { + auto finding = std::find_if(descriptionsIter->second.cbegin(), descriptionsIter->second.cend(), selector); + + if (finding != descriptionsIter->second.cend()) + return true; + } + } + + return false; } void mitk::PropertyDescriptions::RemoveAllDescriptions(const std::string& className) { m_Descriptions[className].clear(); + m_DescriptionsRegEx[className].clear(); } void mitk::PropertyDescriptions::RemoveDescription(const std::string& propertyName, const std::string& className) { if (!propertyName.empty()) + { m_Descriptions[className].erase(propertyName); + m_DescriptionsRegEx[className].erase(propertyName); + } } diff --git a/Modules/Core/src/DataManagement/mitkPropertyPersistence.cpp b/Modules/Core/src/DataManagement/mitkPropertyPersistence.cpp index e8f7ecb653..626e0532d8 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyPersistence.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyPersistence.cpp @@ -1,157 +1,253 @@ /*=================================================================== 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 #include #include +#include + +#include mitk::PropertyPersistence::PropertyPersistence() { } mitk::PropertyPersistence::~PropertyPersistence() { } -bool mitk::PropertyPersistence::AddInfo(const std::string& propertyName, PropertyPersistenceInfo::Pointer info, bool overwrite) +bool mitk::PropertyPersistence::AddInfo(const PropertyPersistenceInfo* info, bool overwrite) { - if (propertyName.empty()) + if (!info) { return false; } - if (info.IsNull()) + if (info->GetName().empty()) { return false; } - PropertyPersistenceInfo::MimeTypeNameType mime = info->GetMimeTypeName(); + mitk::PropertyPersistenceInfo::MimeTypeNameType mime = info->GetMimeTypeName(); - auto infoRange = m_Infos.equal_range(propertyName); + auto infoRange = m_InfoMap.equal_range(info->GetName()); - auto predicate = [mime](const std::pair& x){return x.second.IsNotNull() && x.second->GetMimeTypeName() == mime; }; + auto predicate = [mime](const std::pair& x) + { + return x.second.IsNotNull() && x.second->GetMimeTypeName() == mime; + }; auto finding = std::find_if(infoRange.first, infoRange.second, predicate); bool exists = finding != infoRange.second; bool result = false; if (!exists || overwrite) { if (exists && overwrite) { - m_Infos.erase(finding); + m_InfoMap.erase(finding); } result = true; - m_Infos.insert(std::make_pair(propertyName, info)); + m_InfoMap.insert(std::make_pair(info->GetName(), info)); } return result; } -mitk::PropertyPersistence::InfoMapType mitk::PropertyPersistence::GetInfos(const std::string& propertyName) +mitk::PropertyPersistence::InfoMap mitk::PropertyPersistence::SelectInfo(const InfoMap& infoMap, const SelectFunctionType& selectFunction) { - auto infoRange = m_Infos.equal_range(propertyName); - - InfoMapType result; + InfoMap result; - for (auto pos = infoRange.first; pos != infoRange.second; ++pos) + for (auto pos : infoMap) { - result.insert(std::make_pair(pos->first, pos->second)); + if (selectFunction(pos)) + { + result.insert(pos); + } } return result; -} +}; -mitk::PropertyPersistence::InfoMapType mitk::PropertyPersistence::GetInfosByKey(const std::string& persistenceKey) +mitk::PropertyPersistence::InfoResultType mitk::PropertyPersistence::GetInfo(const std::string& propertyName, bool allowNameRegEx) const { - InfoMapType result; + SelectFunctionType select = [propertyName](const InfoMap::value_type& x) + { + return x.second.IsNotNull() && !x.second->IsRegEx() && x.second->GetName() == propertyName; + }; - for (auto pos : m_Infos) + InfoMap selection = SelectInfo(m_InfoMap, select); + + InfoResultType result; + for (const auto & pos : selection) { - if (pos.second.IsNotNull() && pos.second->GetKey() == persistenceKey) + result.push_back(pos.second->UnRegExByName(propertyName).GetPointer()); + } + + if (allowNameRegEx) + { + select = [propertyName](const InfoMap::value_type& x) + { + if (x.second.IsNotNull() && x.second->IsRegEx()) + { + std::regex ex(x.second->GetName()); + return std::regex_match(propertyName, ex); + } + return false; + }; + + selection = SelectInfo(m_InfoMap, select); + + for (const auto & pos : selection) { - result.insert(std::make_pair(pos.first, pos.second)); + result.push_back(pos.second->UnRegExByName(propertyName).GetPointer()); } } return result; } -mitk::PropertyPersistenceInfo::Pointer mitk::PropertyPersistence::GetInfo(const std::string& propertyName, const MimeTypeNameType& mime, bool allowWildCard) +bool infoPredicate(const std::multimap::value_type& x, const std::string& propertyName, const std::string& mime) { - auto infoRange = m_Infos.equal_range(propertyName); + return x.second.IsNotNull() && !x.second->IsRegEx() && x.second->GetName() == propertyName && x.second->GetMimeTypeName() == mime; +} - auto predicate = [mime](const std::pair& x){return x.second.IsNotNull() && x.second->GetMimeTypeName() == mime; }; +bool infoPredicateRegEx(const std::multimap::value_type& x, const std::string& propertyName, const std::string& mime) +{ + if (x.second.IsNotNull() && x.second->IsRegEx()) + { + std::regex ex(x.second->GetName()); + return std::regex_match(propertyName, ex) && x.second->GetMimeTypeName() == mime; + } + return false; +} - auto finding = std::find_if(infoRange.first, infoRange.second, predicate); +mitk::PropertyPersistence::InfoResultType mitk::PropertyPersistence::GetInfo(const std::string& propertyName, const MimeTypeNameType& mime, bool allowMimeWildCard, bool allowNameRegEx) const +{ + SelectFunctionType select = [propertyName, mime](const InfoMap::value_type& x) + { + return infoPredicate(x, propertyName, mime); + }; - mitk::PropertyPersistenceInfo::Pointer result = nullptr; + InfoMap selection = SelectInfo(m_InfoMap, select); - if (finding == infoRange.second && allowWildCard) + if (allowNameRegEx) { - auto predicateWild = [](const std::pair& x){return x.second.IsNotNull() && x.second->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME(); }; + select = [propertyName, mime](const InfoMap::value_type& x) + { + return infoPredicateRegEx(x, propertyName, mime); + }; + + InfoMap regExSelection = SelectInfo(m_InfoMap, select); - finding = std::find_if(infoRange.first, infoRange.second, predicateWild); + selection.insert(regExSelection.begin(), regExSelection.end()); } + if (selection.empty() && allowMimeWildCard) + { //no perfect match => second run through with "any mime type" + select = [propertyName](const InfoMap::value_type& x) + { + return infoPredicate(x, propertyName, PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); + }; + + selection = SelectInfo(m_InfoMap, select); + + if (allowNameRegEx) + { + select = [propertyName](const InfoMap::value_type& x) + { + return infoPredicateRegEx(x, propertyName, PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); + }; + + InfoMap regExSelection = SelectInfo(m_InfoMap, select); + + selection.insert(regExSelection.begin(), regExSelection.end()); + } + } - if (finding != infoRange.second) + InfoResultType result; + for (const auto & pos : selection) { - result = finding->second; + result.push_back(pos.second->UnRegExByName(propertyName).GetPointer()); } return result; } -bool mitk::PropertyPersistence::HasInfos(const std::string& propertyName) +mitk::PropertyPersistence::InfoResultType mitk::PropertyPersistence::GetInfoByKey(const std::string& persistenceKey, bool allowKeyRegEx) const { - return !propertyName.empty() - ? m_Infos.find(propertyName) != m_Infos.cend() - : false; + InfoResultType result; + + for (const auto& pos : m_InfoMap) + { + if (pos.second.IsNotNull()) + { + bool valid = pos.second->GetKey() == persistenceKey; + if (!valid && pos.second->IsRegEx() && allowKeyRegEx) + { + std::regex ex(pos.second->GetKey()); + valid = std::regex_match(persistenceKey, ex); + } + + if (valid) + { + result.push_back(pos.second->UnRegExByKey(persistenceKey).GetPointer()); + } + } + } + + return result; } -void mitk::PropertyPersistence::RemoveAllInfos() +bool mitk::PropertyPersistence::HasInfo(const std::string& propertyName, bool allowNameRegEx) const { - m_Infos.clear(); + return !this->GetInfo(propertyName, allowNameRegEx).empty(); } -void mitk::PropertyPersistence::RemoveInfos(const std::string& propertyName) +void mitk::PropertyPersistence::RemoveAllInfo() +{ + m_InfoMap.clear(); + m_InfoMap.clear(); +} + +void mitk::PropertyPersistence::RemoveInfo(const std::string& propertyName) { if (!propertyName.empty()) - m_Infos.erase(propertyName); + { + m_InfoMap.erase(propertyName); + } } -void mitk::PropertyPersistence::RemoveInfos(const std::string& propertyName, const MimeTypeNameType& mime) +void mitk::PropertyPersistence::RemoveInfo(const std::string& propertyName, const MimeTypeNameType& mime) { - auto itr = m_Infos.begin(); - while (itr != m_Infos.end()) + auto itr = m_InfoMap.begin(); + while (itr != m_InfoMap.end()) { if (itr->first == propertyName && itr->second.IsNotNull() && itr->second->GetMimeTypeName() == mime) { - itr = m_Infos.erase(itr); + itr = m_InfoMap.erase(itr); } else { ++itr; } } } mitk::IPropertyPersistence* mitk::CreateTestInstancePropertyPersistence() { return new PropertyPersistence(); }; \ No newline at end of file diff --git a/Modules/Core/src/DataManagement/mitkPropertyPersistenceInfo.cpp b/Modules/Core/src/DataManagement/mitkPropertyPersistenceInfo.cpp index 73578a713e..9ac9d82282 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyPersistenceInfo.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyPersistenceInfo.cpp @@ -1,122 +1,257 @@ /*=================================================================== 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 +#include + #include #include #include namespace mitk { struct PropertyPersistenceInfo::Impl { - explicit Impl(const std::string& key); + Impl(); ~Impl(); + std::string Name; std::string Key; + bool IsRegEx; + std::string NameTemplate; + std::string KeyTemplate; DeserializationFunctionType DeSerFnc; SerializationFunctionType SerFnc; MimeTypeNameType MimeTypeName; }; - PropertyPersistenceInfo::Impl::Impl(const std::string& key) - : Key(key), DeSerFnc(PropertyPersistenceDeserialization::deserializeToStringProperty), - SerFnc(PropertyPersistenceSerialization::serializeByGetValueAsString) + PropertyPersistenceInfo::Impl::Impl() + : Name(""), Key(""), IsRegEx(false), DeSerFnc(PropertyPersistenceDeserialization::deserializeToStringProperty), + SerFnc(PropertyPersistenceSerialization::serializeByGetValueAsString), MimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME()) { - MimeTypeName = PropertyPersistenceInfo::ANY_MIMETYPE_NAME(); } PropertyPersistenceInfo::Impl::~Impl() { } } -mitk::PropertyPersistenceInfo::PropertyPersistenceInfo(const std::string& key) - : m_Impl(new Impl(key)) +mitk::PropertyPersistenceInfo::PropertyPersistenceInfo(const std::string& name) + : m_Impl(new Impl()) { + m_Impl->Name = name; + m_Impl->Key = name; } -mitk::PropertyPersistenceInfo::PropertyPersistenceInfo(const std::string& key, const std::string& mimeTypeName) - : m_Impl(new Impl(key)) +mitk::PropertyPersistenceInfo::PropertyPersistenceInfo(const std::string& name, const std::string& mimeTypeName) + : m_Impl(new Impl()) { + m_Impl->Name = name; + m_Impl->Key = name; m_Impl->MimeTypeName = mimeTypeName; } mitk::PropertyPersistenceInfo::~PropertyPersistenceInfo() { delete m_Impl; } +std::string mitk::PropertyPersistenceInfo::GetName() const +{ + return m_Impl->Name; +} + std::string mitk::PropertyPersistenceInfo::GetKey() const { return m_Impl->Key; } -void mitk::PropertyPersistenceInfo::SetKey(const std::string& key) +void mitk::PropertyPersistenceInfo::SetName(const std::string& name) +{ + m_Impl->Name = name; + m_Impl->Key = name; + m_Impl->IsRegEx = false; + m_Impl->NameTemplate.clear(); + m_Impl->KeyTemplate.clear(); +} + +void mitk::PropertyPersistenceInfo::SetNameAndKey(const std::string& name, const std::string& key) { + m_Impl->Name = name; m_Impl->Key = key; + m_Impl->IsRegEx = false; + m_Impl->NameTemplate.clear(); + m_Impl->KeyTemplate.clear(); } -const mitk::PropertyPersistenceInfo::MimeTypeNameType mitk::PropertyPersistenceInfo::GetMimeTypeName() const +void mitk::PropertyPersistenceInfo::UseRegEx(const std::string& nameRegEx, const std::string& nameTemplate) +{ + std::regex checker(nameRegEx); //no exception => valid we can change the info + m_Impl->Name = nameRegEx; + m_Impl->Key = nameRegEx; + m_Impl->IsRegEx = true; + m_Impl->NameTemplate = nameTemplate; + m_Impl->KeyTemplate = nameTemplate; +} + +void mitk::PropertyPersistenceInfo::UseRegEx(const std::string& nameRegEx, const std::string& nameTemplate, const std::string& keyRegEx, const std::string keyTemplate) +{ + std::regex nameChecker(nameRegEx); //no exception => valid we can change the info + std::regex keyChecker(keyRegEx); //no exception => valid we can change the info + m_Impl->Name = nameRegEx; + m_Impl->Key = keyRegEx; + m_Impl->IsRegEx = true; + m_Impl->NameTemplate = nameTemplate; + m_Impl->KeyTemplate = keyTemplate; +} + +bool mitk::PropertyPersistenceInfo::IsRegEx() const +{ + return m_Impl->IsRegEx; +}; + +const std::string& mitk::PropertyPersistenceInfo::GetKeyTemplate() const +{ + return m_Impl->KeyTemplate; +} + +const std::string& mitk::PropertyPersistenceInfo::GetNameTemplate() const +{ + return m_Impl->NameTemplate; +} + +const mitk::PropertyPersistenceInfo::MimeTypeNameType& mitk::PropertyPersistenceInfo::GetMimeTypeName() const { return m_Impl->MimeTypeName; }; void mitk::PropertyPersistenceInfo::SetMimeTypeName(const mitk::PropertyPersistenceInfo::MimeTypeNameType& mimeTypeName) { m_Impl->MimeTypeName = mimeTypeName; }; const mitk::PropertyPersistenceInfo::DeserializationFunctionType mitk::PropertyPersistenceInfo::GetDeserializationFunction() const { return m_Impl->DeSerFnc; }; void mitk::PropertyPersistenceInfo::SetDeserializationFunction(const mitk::PropertyPersistenceInfo::DeserializationFunctionType& fnc) { m_Impl->DeSerFnc = fnc; }; const mitk::PropertyPersistenceInfo::SerializationFunctionType mitk::PropertyPersistenceInfo::GetSerializationFunction() const { return m_Impl->SerFnc; }; void mitk::PropertyPersistenceInfo::SetSerializationFunction(const mitk::PropertyPersistenceInfo::SerializationFunctionType& fnc) { m_Impl->SerFnc = fnc; }; +std::string GenerateFromTemplate(const std::string& sourceStr, const std::string& templateStr, const std::string& regexStr) +{ + std::smatch sm; + std::regex ex(regexStr); + std::regex_match(sourceStr, sm, ex); + + std::string result = templateStr; + + int groupID = 0; + for (const auto& match : sm) + { + if (groupID) + { + std::ostringstream stream; + stream << "(\\$" << groupID << ")"; + std::regex rex(stream.str()); + result = std::regex_replace(result, rex, match.str()); + } + ++groupID; + } + + return result; +}; + +mitk::PropertyPersistenceInfo::Pointer mitk::PropertyPersistenceInfo::UnRegExByName(const std::string& propertyName) const +{ + PropertyPersistenceInfo::Pointer resultInfo = PropertyPersistenceInfo::New(); + *(resultInfo->m_Impl) = *(this->m_Impl); + + if (this->IsRegEx()) + { + std::string newKey = GenerateFromTemplate(propertyName, this->GetKeyTemplate(), this->GetName()); + resultInfo->SetNameAndKey(propertyName, newKey); + } + + return resultInfo; +}; + +mitk::PropertyPersistenceInfo::Pointer mitk::PropertyPersistenceInfo::UnRegExByKey(const std::string& key) const +{ + PropertyPersistenceInfo::Pointer resultInfo = PropertyPersistenceInfo::New(); + *(resultInfo->m_Impl) = *(this->m_Impl); + + if (this->IsRegEx()) + { + std::string newName = GenerateFromTemplate(key, this->GetNameTemplate(), this->GetKey()); + resultInfo->SetNameAndKey(newName, key); + } + + return resultInfo; +}; + mitk::PropertyPersistenceInfo::MimeTypeNameType mitk::PropertyPersistenceInfo::ANY_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".any_type"; return name; }; +void mitk::PropertyPersistenceInfo::PrintSelf(std::ostream & os, itk::Indent indent) const +{ + this->Superclass::PrintSelf(os, indent); + + os << indent << "Name: " << this->m_Impl->Name << std::endl; + os << indent << "Key: " << this->m_Impl->Key << std::endl; + os << indent << "IsRegEx: " << this->m_Impl->IsRegEx << std::endl; + os << indent << "NameTemplate: " << this->m_Impl->NameTemplate << std::endl; + os << indent << "KeyTemplate: " << this->m_Impl->KeyTemplate << std::endl; + os << indent << "MimeTypeName: " << this->m_Impl->MimeTypeName << std::endl; +}; + +std::ostream& mitk::operator << (std::ostream& os, const PropertyPersistenceInfo& info) +{ + info.Print(os); + return os; +} + + ::std::string mitk::PropertyPersistenceSerialization::serializeByGetValueAsString(const mitk::BaseProperty* prop) { std::string result = ""; if (prop) { result = prop->GetValueAsString(); } return result; } mitk::BaseProperty::Pointer mitk::PropertyPersistenceDeserialization::deserializeToStringProperty(const std::string& value) { - StringProperty::Pointer result = StringProperty::New(value); - return result.GetPointer(); + StringProperty::Pointer result = StringProperty::New(value); + return result.GetPointer(); } diff --git a/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp b/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp index 9952446a77..6e3f30fbac 100644 --- a/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp +++ b/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp @@ -1,343 +1,349 @@ /*=================================================================== 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 #include "mitkTemporoSpatialStringProperty.h" #ifdef _MSC_VER //has to be deactivated because of a bug in boost v1.59. see Boost bug ticket #11599 //as soon as MITK uses a boost version with a bug fix we can remove the disableling. # pragma warning(push) # pragma warning(disable: 4715) #endif #include #include #include mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty( const char* s ) { if (s) { SliceMapType slices{ { 0, s } }; m_Values.insert(std::make_pair(0, slices)); } } mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty( const std::string& s ) { SliceMapType slices{ { 0, s } }; m_Values.insert(std::make_pair(0, slices)); } mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty(const TemporoSpatialStringProperty& other) : BaseProperty(other) , m_Values(other.m_Values) { } bool mitk::TemporoSpatialStringProperty::IsEqual(const BaseProperty& property ) const { return this->m_Values == static_cast(property).m_Values; } bool mitk::TemporoSpatialStringProperty::Assign(const BaseProperty& property ) { this->m_Values = static_cast(property).m_Values; return true; } std::string mitk::TemporoSpatialStringProperty::GetValueAsString() const { return GetValue(); } itk::LightObject::Pointer mitk::TemporoSpatialStringProperty::InternalClone() const { itk::LightObject::Pointer result(new Self(*this)); result->UnRegister(); return result; } mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValue() const { std::string result = ""; if (!m_Values.empty()) { if (!m_Values.begin()->second.empty()) { result = m_Values.begin()->second.begin()->second; } } return result; }; std::pair mitk::TemporoSpatialStringProperty::CheckValue(const TimeStepType& timeStep, const IndexValueType& zSlice, bool allowCloseTime, bool allowCloseSlice) const { std::string value = ""; bool found = false; TimeMapType::const_iterator timeIter = m_Values.find(timeStep); TimeMapType::const_iterator timeEnd = m_Values.end(); if (timeIter == timeEnd && allowCloseTime) { //search for closest time step (earlier preverd) timeIter = m_Values.upper_bound(timeStep); if (timeIter != m_Values.begin()) { //there is a key lower than time step timeIter = std::prev(timeIter); } } if (timeIter != timeEnd) { const SliceMapType & slices = timeIter->second; SliceMapType::const_iterator sliceIter = slices.find(zSlice); SliceMapType::const_iterator sliceEnd = slices.end(); if (sliceIter == sliceEnd && allowCloseSlice) { //search for closest slice (earlier preverd) sliceIter = slices.upper_bound(zSlice); if (sliceIter != slices.begin()) { //there is a key lower than slice sliceIter = std::prev(sliceIter); } } if (sliceIter != sliceEnd) { value = sliceIter->second; found = true; } } return std::make_pair(found, value); }; mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValue(const TimeStepType& timeStep, const IndexValueType& zSlice, bool allowCloseTime, bool allowCloseSlice) const { return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).second; }; mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValueBySlice(const IndexValueType& zSlice, bool allowClose) const { return GetValue(0, zSlice, true, allowClose); }; mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValueByTimeStep(const TimeStepType& timeStep, bool allowClose) const { return GetValue(timeStep, 0, allowClose, true); }; bool mitk::TemporoSpatialStringProperty::HasValue() const { return !m_Values.empty(); }; bool mitk::TemporoSpatialStringProperty::HasValue(const TimeStepType& timeStep, const IndexValueType& zSlice, bool allowCloseTime, bool allowCloseSlice) const { return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).first; }; bool mitk::TemporoSpatialStringProperty::HasValueBySlice(const IndexValueType& zSlice, bool allowClose) const { return HasValue(0, zSlice, true, allowClose); }; bool mitk::TemporoSpatialStringProperty::HasValueByTimeStep(const TimeStepType& timeStep, bool allowClose) const { return HasValue(timeStep, 0, allowClose, true); }; std::vector mitk::TemporoSpatialStringProperty::GetAvailableSlices(const TimeStepType& timeStep) const { std::vector result; TimeMapType::const_iterator timeIter = m_Values.find(timeStep); TimeMapType::const_iterator timeEnd = m_Values.end(); if (timeIter != timeEnd) { for (auto const& element : timeIter->second) { result.push_back(element.first); } } return result; }; std::vector mitk::TemporoSpatialStringProperty::GetAvailableTimeSteps() const { std::vector result; for (auto const& element : m_Values) { result.push_back(element.first); } return result; }; void mitk::TemporoSpatialStringProperty::SetValue(const TimeStepType& timeStep, const IndexValueType& zSlice, const ValueType& value) { TimeMapType::iterator timeIter = m_Values.find(timeStep); TimeMapType::iterator timeEnd = m_Values.end(); if (timeIter == timeEnd) { SliceMapType slices{ { zSlice, value } }; m_Values.insert(std::make_pair(timeStep, slices)); } else { timeIter->second[zSlice] = value; } this->Modified(); }; void mitk::TemporoSpatialStringProperty::SetValue(const ValueType& value) { this->Modified(); m_Values.clear(); this->SetValue(0, 0, value); }; // Create necessary escape sequences from illegal characters -// the following function was copied from the json writer of boost::property_tree -std::string CreateJSONEscapes(const std::string &s) +// REMARK: This code is based upon code from boost::ptree::json_writer. +// The corresponding boost function was not used directly, because it is not part of +// the public interface of ptree::json_writer. :( +// A own serialization strategy was implemented instead of using boost::ptree::json_write because +// currently (<= boost 1.60) everything (even numbers) are converted into string representations +// by the writer, so e.g. it becomes "t":"2" instaed of "t":2 +template +std::basic_string CreateJSONEscapes(const std::basic_string &s) { - std::string result; - std::string::const_iterator b = s.begin(); - std::string::const_iterator e = s.end(); + std::basic_string result; + typename std::basic_string::const_iterator b = s.begin(); + typename std::basic_string::const_iterator e = s.end(); while (b != e) { - typedef boost::make_unsigned::type UCh; - typedef std::string::value_type Ch; - + typedef typename boost::make_unsigned::type UCh; UCh c(*b); // This assumes an ASCII superset. // We escape everything outside ASCII, because this code can't // handle high unicode characters. if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) || (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0x7F)) result += *b; else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b'); else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f'); else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n'); else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r'); else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t'); else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/'); else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"'); else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\'); else { const char *hexdigits = "0123456789ABCDEF"; unsigned long u = (std::min)(static_cast( static_cast(*b)), 0xFFFFul); int d1 = u / 4096; u -= d1 * 4096; int d2 = u / 256; u -= d2 * 256; int d3 = u / 16; u -= d3 * 16; int d4 = u; result += Ch('\\'); result += Ch('u'); result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]); result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]); } ++b; } return result; } ::std::string mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON(const mitk::BaseProperty* prop) { //REMARK: Implemented own serialization instead of using boost::ptree::json_write because - //currently everything (even numbers) are converted into string representations by the writer - //so e.g. it becomes "t":"2" instaed of "t":2 + //currently (<= boost 1.60) everything (even numbers) are converted into string representations + //by the writer, so e.g. it becomes "t":"2" instaed of "t":2 + //If this problem is fixed with boost, we shoud switch back to json_writer (and remove the custom + //implementation of CreateJSONEscapes (see above)). const mitk::TemporoSpatialStringProperty* tsProp = dynamic_cast(prop); if (!tsProp) { return ""; } std::ostringstream stream; stream << "{\"values\":["; std::vector ts = tsProp->GetAvailableTimeSteps(); bool first = true; for (auto t : ts) { std::vector zs = tsProp->GetAvailableSlices(t); for (auto z : zs) { std::string value = CreateJSONEscapes(tsProp->GetValue(t, z)); if (first) { first = false; } else { stream << ", "; } stream << "{\"t\":" << t << ", \"z\":" << z << ", \"value\":\"" << value << "\"}"; } } stream << "]}"; return stream.str(); } mitk::BaseProperty::Pointer mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty(const std::string& value) { mitk::TemporoSpatialStringProperty::Pointer prop = mitk::TemporoSpatialStringProperty::New(); boost::property_tree::ptree root; std::istringstream stream(value); boost::property_tree::read_json(stream, root); // Iterator over all animals for (boost::property_tree::ptree::value_type &element : root.get_child("values")) { std::string value = element.second.get("value", ""); mitk::TemporoSpatialStringProperty::IndexValueType z = element.second.get< mitk::TemporoSpatialStringProperty::IndexValueType>("z", 0); TimeStepType t = element.second.get("t", 0); prop->SetValue(t, z, value); } return prop.GetPointer(); } #ifdef _MSC_VER # pragma warning(pop) #endif \ No newline at end of file diff --git a/Modules/Core/src/IO/mitkItkImageIO.cpp b/Modules/Core/src/IO/mitkItkImageIO.cpp index 8a8f98dee2..0468d3a675 100644 --- a/Modules/Core/src/IO/mitkItkImageIO.cpp +++ b/Modules/Core/src/IO/mitkItkImageIO.cpp @@ -1,668 +1,671 @@ /*=================================================================== 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 "mitkItkImageIO.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { const char * const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type"; const char * const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints"; const char * const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type"; const char * const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints"; ItkImageIO::ItkImageIO(const ItkImageIO& other) : AbstractFileIO(other) , m_ImageIO(dynamic_cast(other.m_ImageIO->Clone().GetPointer())) { this->InitializeDefaultMetaDataKeys(); } std::vector ItkImageIO::FixUpImageIOExtensions(const std::string& imageIOName) { std::vector extensions; // Try to fix-up some known ITK image IO classes if (imageIOName == "GiplImageIO") { extensions.push_back("gipl"); extensions.push_back("gipl.gz"); } else if (imageIOName == "GDCMImageIO") { extensions.push_back("gdcm"); extensions.push_back("dcm"); extensions.push_back("DCM"); extensions.push_back("dc3"); extensions.push_back("DC3"); extensions.push_back("ima"); extensions.push_back("img"); } else if (imageIOName == "PNGImageIO") { extensions.push_back("png"); extensions.push_back("PNG"); } else if (imageIOName == "StimulateImageIO") { extensions.push_back("spr"); } else if (imageIOName == "HDF5ImageIO") { extensions.push_back("hdf"); extensions.push_back("h4"); extensions.push_back("hdf4"); extensions.push_back("h5"); extensions.push_back("hdf5"); extensions.push_back("he4"); extensions.push_back("he5"); extensions.push_back("hd5"); } else if (imageIOName == "GE4ImageIO" || imageIOName == "GE5ImageIO") { extensions.push_back(""); } if (!extensions.empty()) { MITK_DEBUG << "Fixing up known extensions for " << imageIOName; } return extensions; } ItkImageIO::ItkImageIO(itk::ImageIOBase::Pointer imageIO) : AbstractFileIO(Image::GetStaticNameOfClass()) , m_ImageIO(imageIO) { if (m_ImageIO.IsNull() ) { mitkThrow() << "ITK ImageIOBase argument must not be NULL"; } this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image."); this->InitializeDefaultMetaDataKeys(); std::vector readExtensions = m_ImageIO->GetSupportedReadExtensions(); if (readExtensions.empty()) { std::string imageIOName = m_ImageIO->GetNameOfClass(); MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide read extensions"; readExtensions = FixUpImageIOExtensions(imageIOName); } CustomMimeType customReaderMimeType; customReaderMimeType.SetCategory("Images"); for(std::vector::const_iterator iter = readExtensions.begin(), endIter = readExtensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(iter->begin()+1, iter->end()); } customReaderMimeType.AddExtension(extension); } this->AbstractFileReader::SetMimeType(customReaderMimeType); std::vector writeExtensions = imageIO->GetSupportedWriteExtensions(); if (writeExtensions.empty()) { std::string imageIOName = imageIO->GetNameOfClass(); MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide write extensions"; writeExtensions = FixUpImageIOExtensions(imageIOName); } if (writeExtensions != readExtensions) { CustomMimeType customWriterMimeType; customWriterMimeType.SetCategory("Images"); for(std::vector::const_iterator iter = writeExtensions.begin(), endIter = writeExtensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(iter->begin()+1, iter->end()); } customWriterMimeType.AddExtension(extension); } this->AbstractFileWriter::SetMimeType(customWriterMimeType); } std::string description = std::string("ITK ") + imageIO->GetNameOfClass(); this->SetReaderDescription(description); this->SetWriterDescription(description); this->RegisterService(); } ItkImageIO::ItkImageIO(const CustomMimeType& mimeType, itk::ImageIOBase::Pointer imageIO, int rank) : AbstractFileIO(Image::GetStaticNameOfClass(), mimeType, std::string("ITK ") + imageIO->GetNameOfClass()) , m_ImageIO(imageIO) { if (m_ImageIO.IsNull() ) { mitkThrow() << "ITK ImageIOBase argument must not be NULL"; } this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image."); this->InitializeDefaultMetaDataKeys(); if (rank) { this->AbstractFileReader::SetRanking(rank); this->AbstractFileWriter::SetRanking(rank); } this->RegisterService(); } /**Helper function that converts the content of a meta data into a time point vector. * If MetaData is not valid or cannot be converted an empty vector is returned.*/ std::vector ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase* data) { const itk::MetaDataObject* timeGeometryTimeData = dynamic_cast*>(data); std::vector result; if (timeGeometryTimeData) { std::string dataStr = timeGeometryTimeData->GetMetaDataObjectValue(); std::stringstream stream(dataStr); TimePointType tp; while (stream >> tp) { result.push_back(tp); } } return result; }; std::vector ItkImageIO::Read() { std::vector result; mitk::LocaleSwitch localeSwitch("C"); Image::Pointer image = Image::New(); const unsigned int MINDIM = 2; const unsigned int MAXDIM = 4; const std::string path = this->GetLocalFileName(); MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl; // Check to see if we can read the file given the name or prefix if (path.empty()) { mitkThrow() << "Empty filename in mitk::ItkImageIO "; } // Got to allocate space for the image. Determine the characteristics of // the image. m_ImageIO->SetFileName( path ); m_ImageIO->ReadImageInformation(); unsigned int ndim = m_ImageIO->GetNumberOfDimensions(); if ( ndim < MINDIM || ndim > MAXDIM ) { MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim << " dimensions! Reading as 4D."; ndim = MAXDIM; } itk::ImageIORegion ioRegion( ndim ); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[ MAXDIM ]; dimensions[ 0 ] = 0; dimensions[ 1 ] = 0; dimensions[ 2 ] = 0; dimensions[ 3 ] = 0; ScalarType spacing[ MAXDIM ]; spacing[ 0 ] = 1.0f; spacing[ 1 ] = 1.0f; spacing[ 2 ] = 1.0f; spacing[ 3 ] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for ( i = 0; i < ndim ; ++i ) { ioStart[ i ] = 0; ioSize[ i ] = m_ImageIO->GetDimensions( i ); if(iGetDimensions( i ); spacing[ i ] = m_ImageIO->GetSpacing( i ); if(spacing[ i ] <= 0) spacing[ i ] = 1.0f; } if(i<3) { origin[ i ] = m_ImageIO->GetOrigin( i ); } } ioRegion.SetSize( ioSize ); ioRegion.SetIndex( ioStart ); MITK_INFO << "ioRegion: " << ioRegion << std::endl; m_ImageIO->SetIORegion( ioRegion ); void* buffer = new unsigned char[m_ImageIO->GetImageSizeInBytes()]; m_ImageIO->Read( buffer ); image->Initialize( MakePixelType(m_ImageIO), ndim, dimensions ); image->SetImportChannel( buffer, 0, Image::ManageMemory ); const itk::MetaDataDictionary& dictionary = m_ImageIO->GetMetaDataDictionary(); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3? 3 : ndim); for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) matrix[i][j] = m_ImageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D* slicedGeometry = image->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2)); slicedGeometry->SetSpacing(spacing); MITK_INFO << slicedGeometry->GetCornerPoint(false,false,false); MITK_INFO << slicedGeometry->GetCornerPoint(true,true,true); // re-initialize TimeGeometry TimeGeometry::Pointer timeGeometry; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE)) { //also check for the name because of backwards compatibility. Past code version stored with the name and not with the key itk::MetaDataObject::ConstPointer timeGeometryTypeData = nullptr; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE)) { timeGeometryTypeData = dynamic_cast*>(dictionary.Get( PROPERTY_NAME_TIMEGEOMETRY_TYPE)); } else { timeGeometryTypeData = dynamic_cast*>(dictionary.Get( PROPERTY_KEY_TIMEGEOMETRY_TYPE)); } if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass()) { MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass() << std::endl; typedef std::vector TimePointVector; TimePointVector timePoints; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get( PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)); } else if(dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get( PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)); } if (timePoints.size() - 1 != image->GetDimension(3)) { MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension (" << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback" << std::endl; } else { ArbitraryTimeGeometry::Pointer arbitraryTimeGeometry = ArbitraryTimeGeometry::New(); TimePointVector::const_iterator pos = timePoints.begin(); TimePointVector::const_iterator prePos = pos++; for (; pos != timePoints.end(); ++prePos, ++pos) { arbitraryTimeGeometry->AppendTimeStepClone(slicedGeometry, *pos, *prePos); } timeGeometry = arbitraryTimeGeometry; } } } if (timeGeometry.IsNull()) { //Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass() << std::endl; ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3)); timeGeometry = propTimeGeometry; } image->SetTimeGeometry(timeGeometry); buffer = NULL; MITK_INFO << "number of image components: "<< image->GetPixelType().GetNumberOfComponents() << std::endl; for (itk::MetaDataDictionary::ConstIterator iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd; ++iter) { if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string)) { const std::string& key = iter->first; std::string assumedPropertyName = key; std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.'); std::string mimeTypeName = GetMimeType()->GetName(); - //Check of there is already a info for the key and our mime type. - IPropertyPersistence::InfoMapType infos = mitk::CoreServices::GetPropertyPersistence()->GetInfosByKey(key); + //Check if there is already a info for the key and our mime type. + IPropertyPersistence::InfoResultType infoList = mitk::CoreServices::GetPropertyPersistence()->GetInfoByKey(key); - auto predicate = [mimeTypeName](const std::pair& x){return x.second.IsNotNull() && x.second->GetMimeTypeName() == mimeTypeName; }; - auto finding = std::find_if(infos.begin(), infos.end(), predicate); + auto predicate = [mimeTypeName](const PropertyPersistenceInfo::ConstPointer& x){return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName; }; + auto finding = std::find_if(infoList.begin(), infoList.end(), predicate); - if (finding == infos.end()) + if (finding == infoList.end()) { - auto predicateWild = [](const std::pair& x){return x.second.IsNotNull() && x.second->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME(); }; - finding = std::find_if(infos.begin(), infos.end(), predicateWild); + auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer& x){return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME(); }; + finding = std::find_if(infoList.begin(), infoList.end(), predicateWild); } - PropertyPersistenceInfo::Pointer info; + PropertyPersistenceInfo::ConstPointer info; - if (finding != infos.end()) + if (finding != infoList.end()) { - assumedPropertyName = finding->first; - info = finding->second; + assumedPropertyName = (*finding)->GetName(); + info = *finding; } else { //we have not found anything suitable so we generate our own info - info = PropertyPersistenceInfo::New(key); - info->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); + PropertyPersistenceInfo::Pointer newInfo = PropertyPersistenceInfo::New(); + newInfo->SetNameAndKey(assumedPropertyName, key); + newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); + info = newInfo; } std::string value = dynamic_cast*>(iter->second.GetPointer())->GetMetaDataObjectValue(); mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value); image->SetProperty(assumedPropertyName.c_str(), loadedProp); // Read properties should be persisted unless they are default properties // which are written anyway bool isDefaultKey( false ); for( const auto &defaultKey : m_DefaultMetaDataKeys ) { if (defaultKey.length() <= assumedPropertyName.length()) { // does the start match the default key if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos) { isDefaultKey = true; break; } } } if( !isDefaultKey ) { - mitk::CoreServices::GetPropertyPersistence()->AddInfo(assumedPropertyName, info); + mitk::CoreServices::GetPropertyPersistence()->AddInfo(info); } } } MITK_INFO << "...finished!" << std::endl; result.push_back(image.GetPointer()); return result; } AbstractFileIO::ConfidenceLevel ItkImageIO::GetReaderConfidenceLevel() const { return m_ImageIO->CanReadFile(GetLocalFileName().c_str()) ? IFileReader::Supported : IFileReader::Unsupported; } void ItkImageIO::Write() { const mitk::Image* image = dynamic_cast(this->GetInput()); if (image == NULL) { mitkThrow() << "Cannot write non-image data"; } // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); // Clone the image geometry, because we might have to change it // for writing purposes BaseGeometry::Pointer geometry = image->GetGeometry()->Clone(); // Check if geometry information will be lost if (image->GetDimension() == 2 && !geometry->Is2DConvertable()) { MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might consider using Convert2Dto3DImageFilter before saving."; // set matrix to identity mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); affTrans->SetIdentity(); mitk::Vector3D spacing = geometry->GetSpacing(); mitk::Point3D origin = geometry->GetOrigin(); geometry->SetIndexToWorldTransform(affTrans); geometry->SetSpacing(spacing); geometry->SetOrigin(origin); } LocalFile localFile(this); const std::string path = localFile.GetFileName(); MITK_INFO << "Writing image: " << path << std::endl; try { // Implementation of writer using itkImageIO directly. This skips the use // of templated itkImageFileWriter, which saves the multiplexing on MITK side. const unsigned int dimension = image->GetDimension(); const unsigned int* const dimensions = image->GetDimensions(); const mitk::PixelType pixelType = image->GetPixelType(); const mitk::Vector3D mitkSpacing = geometry->GetSpacing(); const mitk::Point3D mitkOrigin = geometry->GetOrigin(); // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin, // though they are not supported in MITK itk::Vector spacing4D; spacing4D[0] = mitkSpacing[0]; spacing4D[1] = mitkSpacing[1]; spacing4D[2] = mitkSpacing[2]; spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here itk::Vector origin4D; origin4D[0] = mitkOrigin[0]; origin4D[1] = mitkOrigin[1]; origin4D[2] = mitkOrigin[2]; origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here // Set the necessary information for imageIO m_ImageIO->SetNumberOfDimensions(dimension); m_ImageIO->SetPixelType(pixelType.GetPixelType()); m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ? static_cast(pixelType.GetComponentType()) : itk::ImageIOBase::UNKNOWNCOMPONENTTYPE); m_ImageIO->SetNumberOfComponents( pixelType.GetNumberOfComponents() ); itk::ImageIORegion ioRegion( dimension ); for(unsigned int i = 0; i < dimension; i++) { m_ImageIO->SetDimensions(i, dimensions[i]); m_ImageIO->SetSpacing(i, spacing4D[i]); m_ImageIO->SetOrigin(i, origin4D[i]); mitk::Vector3D mitkDirection; mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); itk::Vector direction4D; direction4D[0] = mitkDirection[0]; direction4D[1] = mitkDirection[1]; direction4D[2] = mitkDirection[2]; // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix. if (i == 3) { direction4D[3] = 1; // homogenous component } else { direction4D[3] = 0; } vnl_vector axisDirection(dimension); for(unsigned int j = 0; j < dimension; j++) { axisDirection[j] = direction4D[j] / spacing4D[i]; } m_ImageIO->SetDirection(i, axisDirection); ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i)); ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i)); } //use compression if available m_ImageIO->UseCompressionOn(); m_ImageIO->SetIORegion(ioRegion); m_ImageIO->SetFileName(path); // Handle time geometry const ArbitraryTimeGeometry* arbitraryTG = dynamic_cast(image->GetTimeGeometry()); if (arbitraryTG) { itk::EncapsulateMetaData(m_ImageIO->GetMetaDataDictionary(), PROPERTY_KEY_TIMEGEOMETRY_TYPE, ArbitraryTimeGeometry::GetStaticNameOfClass()); std::stringstream stream; stream << arbitraryTG->GetTimeBounds(0)[0]; for (TimeStepType pos = 0; posCountTimeSteps(); ++pos) { stream << " " << arbitraryTG->GetTimeBounds(pos)[1]; } std::string data = stream.str(); itk::EncapsulateMetaData(m_ImageIO->GetMetaDataDictionary(), PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, data); } // Handle properties mitk::PropertyList::Pointer imagePropertyList = image->GetPropertyList(); for(const auto &property : *imagePropertyList->GetMap()) { - PropertyPersistenceInfo::Pointer info = mitk::CoreServices::GetPropertyPersistence()->GetInfo(property.first, GetMimeType()->GetName(), true); + IPropertyPersistence::InfoResultType infoList = mitk::CoreServices::GetPropertyPersistence()->GetInfo(property.first, GetMimeType()->GetName(), true); - if( info.IsNull()) + if (infoList.empty()) { continue; } - std::string value = info->GetSerializationFunction()(property.second); + std::string value = infoList.front()->GetSerializationFunction()(property.second); if( value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING ) { continue; } - std::string key = info->GetKey(); + std::string key = infoList.front()->GetKey(); itk::EncapsulateMetaData(m_ImageIO->GetMetaDataDictionary(), key, value); } + ImageReadAccessor imageAccess(image); m_ImageIO->Write(imageAccess.GetData()); } catch (const std::exception& e) { mitkThrow() << e.what(); } } AbstractFileIO::ConfidenceLevel ItkImageIO::GetWriterConfidenceLevel() const { // Check if the image dimension is supported const Image* image = dynamic_cast(this->GetInput()); if (image == NULL) { // We cannot write a null object, DUH! return IFileWriter::Unsupported; } if ( ! m_ImageIO->SupportsDimension(image->GetDimension())) { // okay, dimension is not supported. We have to look at a special case: // 3D-Image with one slice. We can treat that as a 2D image. if ((image->GetDimension() == 3) && (image->GetSlicedGeometry()->GetSlices() == 1)) return IFileWriter::Supported; else return IFileWriter::Unsupported; } // Check if geometry information will be lost if (image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { return IFileWriter::PartiallySupported; } return IFileWriter::Supported; } ItkImageIO* ItkImageIO::IOClone() const { return new ItkImageIO(*this); } void ItkImageIO::InitializeDefaultMetaDataKeys() { this->m_DefaultMetaDataKeys.push_back("NRRD.space"); this->m_DefaultMetaDataKeys.push_back("NRRD.kinds"); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS); this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName"); } } diff --git a/Modules/Core/test/mitkPropertyPersistenceInfoTest.cpp b/Modules/Core/test/mitkPropertyPersistenceInfoTest.cpp index 977f1f7bdf..76ba3c1e8a 100644 --- a/Modules/Core/test/mitkPropertyPersistenceInfoTest.cpp +++ b/Modules/Core/test/mitkPropertyPersistenceInfoTest.cpp @@ -1,128 +1,213 @@ /*=================================================================== 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 "mitkPropertyPersistenceInfo.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include "mitkStringProperty.h" #include "mitkIOMimeTypes.h" #include -::std::string testSerializeFunction(const mitk::BaseProperty* prop) +::std::string testSerializeFunction(const mitk::BaseProperty* /*prop*/) { return "testSerialize"; } -mitk::BaseProperty::Pointer testDeserializeFunction(const std::string& value) +mitk::BaseProperty::Pointer testDeserializeFunction(const std::string& /*value*/) { mitk::StringProperty::Pointer result = mitk::StringProperty::New("testSerialize"); return result.GetPointer(); } class mitkPropertyPersistenceInfoTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPropertyPersistenceInfoTestSuite); MITK_TEST(CheckDefaultInfo); - MITK_TEST(SetKey); + MITK_TEST(SetName); + MITK_TEST(SetNameAndKey); MITK_TEST(SetMimeTypeName); + MITK_TEST(UseRegEx); + MITK_TEST(UseRegEx2); + MITK_TEST(UnRegExByName); + MITK_TEST(UnRegExByKey); MITK_TEST(SetDeserializationFunction); MITK_TEST(SetSerializationFunction); MITK_TEST(serializeByGetValueAsString); MITK_TEST(deserializeToStringProperty); CPPUNIT_TEST_SUITE_END(); private: mitk::StringProperty::Pointer refProp; std::string refSerialization; mitk::StringProperty::Pointer refProp_testFunction; std::string refSerialization_testFunction; mitk::PropertyPersistenceInfo::Pointer info; + mitk::PropertyPersistenceInfo::Pointer regexInfo; + + std::string nameRegEx; + std::string keyRegEx; + std::string nameTemplate; + std::string keyTemplate; public: void setUp() override { refSerialization = "my_shiny_test_value"; refProp = mitk::StringProperty::New("my_shiny_test_value"); info = mitk::PropertyPersistenceInfo::New(); refSerialization_testFunction = "testSerialize"; refProp_testFunction = mitk::StringProperty::New("testSerialize"); + + nameRegEx = "name(\\d*)"; + nameTemplate = "$1_name"; + keyRegEx = "key(\\d*)"; + keyTemplate = "newkey_[$1]"; + + regexInfo = mitk::PropertyPersistenceInfo::New(); + regexInfo->UseRegEx(nameRegEx, nameTemplate, keyRegEx, keyTemplate); } void tearDown() override { } void CheckDefaultInfo() { - MITK_TEST_CONDITION_REQUIRED(mitk::PropertyPersistenceInfo::ANY_MIMETYPE_NAME() == mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".any_type", "Testing PropertyPersistenceInfo::ANY_MIMETYPE_NAME()"); - MITK_TEST_CONDITION_REQUIRED(info->GetKey() == "", "Testing PropertyPersistenceInfo::GetKey()"); - MITK_TEST_CONDITION_REQUIRED(info->GetMimeTypeName() == mitk::PropertyPersistenceInfo::ANY_MIMETYPE_NAME(), "Testing PropertyPersistenceInfo::GetMimeTypeName()"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::ANY_MIMETYPE_NAME()", mitk::PropertyPersistenceInfo::ANY_MIMETYPE_NAME() == mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".any_type"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::GetName()", info->GetName() == ""); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::GetKey()", info->GetKey() == ""); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::GetMimeTypeName()", info->GetMimeTypeName() == mitk::PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::IsRegEx()", !info->IsRegEx()); + + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::IsRegEx()", regexInfo->IsRegEx()); mitk::BaseProperty::Pointer prop = info->GetDeserializationFunction()(refSerialization); - MITK_TEST_CONDITION_REQUIRED(dynamic_cast(prop.GetPointer()), "Testing PropertyPersistenceInfo::GetDeserializationFunction() producing a StringProperty"); - MITK_TEST_CONDITION_REQUIRED(prop->GetValueAsString() == refSerialization, "Testing PropertyPersistenceInfo::GetDeserializationFunction() producing a StringProperty with correct value"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::GetDeserializationFunction() producing a StringProperty", dynamic_cast(prop.GetPointer())); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::GetDeserializationFunction() producing a StringProperty with correct value", prop->GetValueAsString() == refSerialization); std::string value = info->GetSerializationFunction()(refProp); - MITK_TEST_CONDITION_REQUIRED(value == refSerialization, "Testing PropertyPersistenceInfo::GetSerializationFunction()"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::GetSerializationFunction()", value == refSerialization); } - void SetKey() + void SetName() { - info->SetKey("newKey"); - MITK_TEST_CONDITION_REQUIRED(info->GetKey() == "newKey", "Testing PropertyPersistenceInfo::SetKey()"); + info->SetName("MyName"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::SetKey() changed name", info->GetName() == "MyName"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::SetKey() changed key", info->GetKey() == "MyName"); + + //test if setter resets to non regex + regexInfo->SetName("MyName"); + CPPUNIT_ASSERT_MESSAGE("Testing regex reset when using SetName()", !regexInfo->IsRegEx()); + } + + void SetNameAndKey() + { + info->SetNameAndKey("MyName", "MyKey"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::SetNameAndKey() changed name", info->GetName() == "MyName"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::SetNameAndKey() changed key", info->GetKey() == "MyKey"); + + //test if setter resets to non regex + regexInfo->SetNameAndKey("MyName", "MyKey"); + CPPUNIT_ASSERT_MESSAGE("Testing regex reset when using SetNameAndKey()", !regexInfo->IsRegEx()); } void SetMimeTypeName() { info->SetMimeTypeName("newMime"); - MITK_TEST_CONDITION_REQUIRED(info->GetMimeTypeName() == "newMime", "Testing PropertyPersistenceInfo::SetMimeTypeName()"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::SetMimeTypeName()", info->GetMimeTypeName() == "newMime"); + } + + void UseRegEx() + { + info->UseRegEx(nameRegEx, nameTemplate); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::IsRegEx()", info->IsRegEx()); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed name", info->GetName() == nameRegEx); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed key", info->GetKey() == nameRegEx); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed name template", info->GetNameTemplate() == nameTemplate); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed key template", info->GetKeyTemplate() == nameTemplate); + } + + void UseRegEx2() + { + info->UseRegEx(nameRegEx, nameTemplate, keyRegEx, keyTemplate); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::IsRegEx()", info->IsRegEx()); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed name", info->GetName() == nameRegEx); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed key", info->GetKey() == keyRegEx); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed name template", info->GetNameTemplate() == nameTemplate); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::UseRegEx() changed key template", info->GetKeyTemplate() == keyTemplate); + } + + void UnRegExByName() + { + mitk::PropertyPersistenceInfo::Pointer newInfo = regexInfo->UnRegExByName("name42"); + CPPUNIT_ASSERT_MESSAGE("Testing IsRegEx() of \"unreg\"ed regexInfo", !newInfo->IsRegEx()); + CPPUNIT_ASSERT_MESSAGE("Testing GetName() of \"unreg\"ed regexInfo", newInfo->GetName() == "name42"); + CPPUNIT_ASSERT_MESSAGE("Testing GetKey() of \"unreg\"ed regexInfo", newInfo->GetKey() == "newkey_[42]"); + + newInfo = info->UnRegExByName("name42"); + CPPUNIT_ASSERT_MESSAGE("Testing IsRegEx() of \"unreg\"ed info", !newInfo->IsRegEx()); + CPPUNIT_ASSERT_MESSAGE("Testing GetName() of \"unreg\"ed info", newInfo->GetName() == info->GetName()); + CPPUNIT_ASSERT_MESSAGE("Testing GetKey() of \"unreg\"ed info", newInfo->GetKey() == info->GetKey()); + } + + void UnRegExByKey() + { + mitk::PropertyPersistenceInfo::Pointer newInfo = regexInfo->UnRegExByKey("key42"); + CPPUNIT_ASSERT_MESSAGE("Testing IsRegEx() of \"unreg\"ed regexInfo", !newInfo->IsRegEx()); + CPPUNIT_ASSERT_MESSAGE("Testing GetName() of \"unreg\"ed regexInfo", newInfo->GetName() == "42_name"); + CPPUNIT_ASSERT_MESSAGE("Testing GetKey() of \"unreg\"ed regexInfo", newInfo->GetKey() == "key42"); + + newInfo = info->UnRegExByKey("key42"); + CPPUNIT_ASSERT_MESSAGE("Testing IsRegEx() of \"unreg\"ed info", !newInfo->IsRegEx()); + CPPUNIT_ASSERT_MESSAGE("Testing GetName() of \"unreg\"ed info", newInfo->GetName() == info->GetName()); + CPPUNIT_ASSERT_MESSAGE("Testing GetKey() of \"unreg\"ed info", newInfo->GetKey() == info->GetKey()); } void SetDeserializationFunction() { info->SetDeserializationFunction(testDeserializeFunction); mitk::BaseProperty::Pointer prop = info->GetDeserializationFunction()(refSerialization); - MITK_TEST_CONDITION_REQUIRED(prop->GetValueAsString() == refSerialization_testFunction, "Testing PropertyPersistenceInfo::SetDeserializationFunction() producing a StringProperty with correct value"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::SetDeserializationFunction() producing a StringProperty with correct value", prop->GetValueAsString() == refSerialization_testFunction); } void SetSerializationFunction() { info->SetSerializationFunction(testSerializeFunction); std::string value = info->GetSerializationFunction()(refProp); - MITK_TEST_CONDITION_REQUIRED(value == refSerialization_testFunction, "Testing PropertyPersistenceInfo::SetSerializationFunction()"); + CPPUNIT_ASSERT_MESSAGE("Testing PropertyPersistenceInfo::SetSerializationFunction()", value == refSerialization_testFunction); } void serializeByGetValueAsString() { std::string value = mitk::PropertyPersistenceSerialization::serializeByGetValueAsString(refProp); - MITK_TEST_CONDITION_REQUIRED(value == refSerialization, "Testing serializeByGetValueAsString()"); + CPPUNIT_ASSERT_MESSAGE("Testing serializeByGetValueAsString()", value == refSerialization); } void deserializeToStringProperty() { mitk::BaseProperty::Pointer prop = mitk::PropertyPersistenceDeserialization::deserializeToStringProperty(refSerialization); - MITK_TEST_CONDITION_REQUIRED(dynamic_cast(prop.GetPointer()), "Testing deserializeToStringProperty() producing a StringProperty"); - MITK_TEST_CONDITION_REQUIRED(prop->GetValueAsString() == refSerialization, "Testing deserializeToStringProperty() producing a StringProperty with correct value"); + CPPUNIT_ASSERT_MESSAGE("Testing deserializeToStringProperty() producing a StringProperty", dynamic_cast(prop.GetPointer())); + CPPUNIT_ASSERT_MESSAGE("Testing deserializeToStringProperty() producing a StringProperty with correct value", prop->GetValueAsString() == refSerialization); } }; MITK_TEST_SUITE_REGISTRATION(mitkPropertyPersistenceInfo) diff --git a/Modules/Core/test/mitkPropertyPersistenceTest.cpp b/Modules/Core/test/mitkPropertyPersistenceTest.cpp index 6bbe9daba8..921273a575 100644 --- a/Modules/Core/test/mitkPropertyPersistenceTest.cpp +++ b/Modules/Core/test/mitkPropertyPersistenceTest.cpp @@ -1,236 +1,304 @@ /*=================================================================== 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 +#include +#include + #include "mitkPropertyPersistence.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include "mitkStringProperty.h" #include "mitkIOMimeTypes.h" #include #include -#include -#include - class mitkPropertyPersistenceTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPropertyPersistenceTestSuite); MITK_TEST(AddInfo); - MITK_TEST(GetInfos); MITK_TEST(GetInfo); - MITK_TEST(GetInfosByKey); - MITK_TEST(HasInfos); - MITK_TEST(RemoveAllInfos); - MITK_TEST(RemoveInfos); - MITK_TEST(RemoveInfos_withMime); + MITK_TEST(GetInfo_mime); + MITK_TEST(GetInfoByKey); + MITK_TEST(HasInfo); + MITK_TEST(RemoveAllInfo); + MITK_TEST(RemoveInfo); + MITK_TEST(RemoveInfo_withMime); CPPUNIT_TEST_SUITE_END(); private: mitk::PropertyPersistenceInfo::Pointer info1; mitk::PropertyPersistenceInfo::Pointer info2; mitk::PropertyPersistenceInfo::Pointer info3; mitk::PropertyPersistenceInfo::Pointer info4; mitk::PropertyPersistenceInfo::Pointer info5; mitk::PropertyPersistenceInfo::Pointer info6; + mitk::PropertyPersistenceInfo::Pointer infoX; + mitk::PropertyPersistenceInfo::Pointer infoX2; + std::string prop1; std::string prop2; std::string prop3; std::string prop4; std::string prop5; std::string prop6; + std::string propX; + std::string keyX; + std::string propXTemplate; + std::string keyXTemplate; + std::string propX2; + mitk::IPropertyPersistence* service; - static bool checkExistance(const mitk::PropertyPersistence::InfoMapType& infos, const std::string& name, const mitk::PropertyPersistenceInfo* info) + static bool checkExistance(const mitk::PropertyPersistence::InfoResultType& infos, const mitk::PropertyPersistenceInfo* info) { - auto infoRange = infos.equal_range(name); - - auto predicate = [info](const std::pair& x){return infosAreEqual(info, x.second); }; + auto predicate = [info](const mitk::PropertyPersistenceInfo::ConstPointer& x){return infosAreEqual(info, x); }; - auto finding = std::find_if(infoRange.first, infoRange.second, predicate); + auto finding = std::find_if(infos.begin(), infos.end(), predicate); - bool result = finding != infoRange.second; + bool result = finding != infos.end(); return result; } static bool infosAreEqual(const mitk::PropertyPersistenceInfo* ref, const mitk::PropertyPersistenceInfo* info) { bool result = true; if (!info || !ref) { return false; } + result = result && ref->GetName() == info->GetName(); result = result && ref->GetKey() == info->GetKey(); result = result && ref->GetMimeTypeName() == info->GetMimeTypeName(); return result; } public: void setUp() override { service = mitk::CreateTestInstancePropertyPersistence(); - info1 = mitk::PropertyPersistenceInfo::New("key1"); - - info2 = mitk::PropertyPersistenceInfo::New("key2", "mime2"); - info3 = mitk::PropertyPersistenceInfo::New("key3", "mime3"); - info4 = mitk::PropertyPersistenceInfo::New("key2", "mime2"); - info5 = mitk::PropertyPersistenceInfo::New("key5", "mime5"); - prop1 = "prop1"; prop2 = "prop1"; prop3 = "prop1"; prop4 = "prop4"; prop5 = "prop5"; - service->AddInfo(prop1, info1, false); - service->AddInfo(prop2, info2, false); - service->AddInfo(prop3, info3, false); - service->AddInfo(prop4, info4, false); - service->AddInfo(prop5, info5, false); + propX = "prop(\\d*)"; + keyX = "key(\\d*)"; + propXTemplate = "prop$1"; + keyXTemplate = "key.$1"; + + propX2 = "otherprop(\\d*)"; + + info1 = mitk::PropertyPersistenceInfo::New(); + info1->SetNameAndKey(prop1, "key1"); + info2 = mitk::PropertyPersistenceInfo::New(prop2, "mime2"); + info2->SetNameAndKey(prop2, "key2"); + info3 = mitk::PropertyPersistenceInfo::New(prop3, "mime3"); + info3->SetNameAndKey(prop3, "key3"); + info4 = mitk::PropertyPersistenceInfo::New(prop4, "mime2"); + info4->SetNameAndKey(prop4, "key2"); + info5 = mitk::PropertyPersistenceInfo::New(prop5, "mime5"); + info5->SetNameAndKey(prop5, "key5"); + + infoX = mitk::PropertyPersistenceInfo::New("","mimeX"); + infoX->UseRegEx(propX, propXTemplate, keyX, keyXTemplate); + + infoX2 = mitk::PropertyPersistenceInfo::New(); + infoX2->UseRegEx(propX2, propXTemplate); + + service->AddInfo(info1, false); + service->AddInfo(info2, false); + service->AddInfo(info3, false); + service->AddInfo(info4, false); + service->AddInfo(info5, false); + service->AddInfo(infoX, false); + service->AddInfo(infoX2, false); } void tearDown() override { delete service; } void AddInfo() { - mitk::PropertyPersistenceInfo::Pointer info2_new = mitk::PropertyPersistenceInfo::New("newKey", "otherMime"); - mitk::PropertyPersistenceInfo::Pointer info2_otherKey = mitk::PropertyPersistenceInfo::New("otherKey", "mime2"); + mitk::PropertyPersistenceInfo::Pointer info2_new = mitk::PropertyPersistenceInfo::New(prop2, "otherMime"); + info2_new->SetNameAndKey(prop2, "newKey"); + mitk::PropertyPersistenceInfo::Pointer info2_otherKey = mitk::PropertyPersistenceInfo::New("prop2", "mime2"); + info2_otherKey->SetNameAndKey(prop2, "otherKey"); + mitk::PropertyPersistenceInfo::Pointer info_newPropNKey = mitk::PropertyPersistenceInfo::New("", "otherMime"); + info_newPropNKey->SetNameAndKey("newProp", "newKey"); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (no overwrite) -> no adding", !service->AddInfo(prop2, info2_otherKey, false)); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (no overwrite) -> no adding -> key should not be changed.", service->GetInfo(prop2, "mime2", false)->GetKey() == "key2"); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (no overwrite) -> no adding", !service->AddInfo(info2_otherKey, false)); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (no overwrite) -> no adding -> key should not be changed.", service->GetInfo(prop2, "mime2", false).front()->GetKey() == "key2"); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (overwrite) -> adding", service->AddInfo(prop2, info2_otherKey, true)); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (no overwrite) -> adding -> key should be changed.", service->GetInfo(prop2, "mime2", false)->GetKey() == "otherKey"); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (overwrite) -> adding", service->AddInfo(info2_otherKey, true)); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of already existing info (no overwrite) -> adding -> key should be changed.", service->GetInfo(prop2, "mime2", false).front()->GetKey() == "otherKey"); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (other mime type; no overwrite) -> adding", service->AddInfo(prop2, info2_new, false)); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (other mime type; no overwrite) -> adding -> info exists.", service->GetInfo(prop2, "otherMime", false).IsNotNull()); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (other mime type; no overwrite) -> adding", service->AddInfo(info2_new, false)); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (other mime type; no overwrite) -> adding -> info exists.", !service->GetInfo(prop2, "otherMime", false).empty()); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (new prop name; no overwrite) -> adding", service->AddInfo("newProp", info2_new, false)); - CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (new prop name; no overwrite) -> adding ->info exists.", service->GetInfo("newProp", "otherMime", false).IsNotNull()); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (new prop name; no overwrite) -> adding", service->AddInfo(info_newPropNKey, false)); + CPPUNIT_ASSERT_MESSAGE("Testing addinfo of info (new prop name; no overwrite) -> adding ->info exists.", !service->GetInfo("newProp", "otherMime", false).empty()); } - void GetInfos() + void GetInfo() { - mitk::PropertyPersistence::InfoMapType infos = service->GetInfos(prop1); + mitk::PropertyPersistence::InfoResultType infos = service->GetInfo(prop1, false); CPPUNIT_ASSERT(infos.size() == 3); - CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, prop1, info1)); - CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, prop2, info2)); - CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, prop3, info3)); + CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, info1)); + CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, info2)); + CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, info3)); - infos = service->GetInfos(prop4); + infos = service->GetInfo(prop4, false); CPPUNIT_ASSERT(infos.size() == 1); - CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, prop4, info4)); + CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, info4)); - infos = service->GetInfos("unkown"); + infos = service->GetInfo("unkown", false); CPPUNIT_ASSERT_MESSAGE("Check size of result for unkown prop.", infos.empty()); + + infos = service->GetInfo("prop101", false); + CPPUNIT_ASSERT(infos.empty()); + + infos = service->GetInfo("prop101", true); + CPPUNIT_ASSERT(infos.size() == 1); + CPPUNIT_ASSERT_MESSAGE("Check Name of expected element 1.", infos.front()->GetName() == "prop101"); + CPPUNIT_ASSERT_MESSAGE("Check Key of expected element 1.", infos.front()->GetKey() == "key.101"); + CPPUNIT_ASSERT_MESSAGE("Check MimeTypeName of expected element 1.", infos.front()->GetMimeTypeName() == "mimeX"); } - void GetInfosByKey() + void GetInfoByKey() { - mitk::PropertyPersistence::InfoMapType infos = service->GetInfosByKey("key2"); + mitk::PropertyPersistence::InfoResultType infos = service->GetInfoByKey("key2", false); CPPUNIT_ASSERT(infos.size() == 2); - CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, prop2, info2)); - CPPUNIT_ASSERT_MESSAGE("Check expected element 2.", checkExistance(infos, prop4, info4)); + CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, info2)); + CPPUNIT_ASSERT_MESSAGE("Check expected element 2.", checkExistance(infos, info4)); - infos = service->GetInfosByKey("key5"); + infos = service->GetInfoByKey("key5", false); CPPUNIT_ASSERT(infos.size() == 1); - CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, prop5, info5)); + CPPUNIT_ASSERT_MESSAGE("Check expected element 1.", checkExistance(infos, info5)); - infos = service->GetInfosByKey("unkownkey"); + infos = service->GetInfoByKey("unkownkey", false); CPPUNIT_ASSERT_MESSAGE("Check size of result for unkown key.", infos.empty()); + + infos = service->GetInfoByKey("key101", false); + CPPUNIT_ASSERT_MESSAGE("Check size of result for key101.", infos.empty()); + + infos = service->GetInfoByKey("key101", true); + CPPUNIT_ASSERT(infos.size() == 1); + CPPUNIT_ASSERT_MESSAGE("Check Name of expected element 1.", infos.front()->GetName() == "prop101"); + CPPUNIT_ASSERT_MESSAGE("Check Key of expected element 1.", infos.front()->GetKey() == "key101"); + CPPUNIT_ASSERT_MESSAGE("Check MimeTypeName of expected element 1.", infos.front()->GetMimeTypeName() == "mimeX"); } - void GetInfo() + void GetInfo_mime() { - mitk::PropertyPersistenceInfo::Pointer foundInfo = service->GetInfo(prop1, "mime2", false); - CPPUNIT_ASSERT_MESSAGE("Check GetInfo (existing element, no wildcard allowed, wildcard exists).", infosAreEqual(info2, foundInfo)); - foundInfo = service->GetInfo(prop1, "mime2", true); - CPPUNIT_ASSERT_MESSAGE("Check GetInfo (existing element, wildcard allowed, wildcard exists).", infosAreEqual(info2, foundInfo)); - foundInfo = service->GetInfo(prop1, "unknownmime", false); - CPPUNIT_ASSERT_MESSAGE("Check GetInfo (inexisting element, no wildcard allowed, wildcard exists).", foundInfo.IsNull()); - foundInfo = service->GetInfo(prop1, "unknownmime", true); - CPPUNIT_ASSERT_MESSAGE("Check GetInfo (inexisting element, wildcard allowed, wildcard exists).", infosAreEqual(info1, foundInfo)); - - foundInfo = service->GetInfo(prop4, "unknownmime", false); - CPPUNIT_ASSERT_MESSAGE("Check GetInfo (inexisting element, no wildcard allowed).", foundInfo.IsNull()); - foundInfo = service->GetInfo(prop4, "unknownmime", true); - CPPUNIT_ASSERT_MESSAGE("Check GetInfo (inexisting element, wildcard allowed).", foundInfo.IsNull()); + mitk::PropertyPersistence::InfoResultType infos = service->GetInfo(prop1, "mime2", false, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (existing element, no wildcard allowed, wildcard exists).", infosAreEqual(info2, infos.front())); + infos = service->GetInfo(prop1, "mime2", true, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (existing element, wildcard allowed, wildcard exists).", infosAreEqual(info2, infos.front())); + infos = service->GetInfo(prop1, "unknownmime", false, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting element, no wildcard allowed, wildcard exists).", infos.empty()); + infos = service->GetInfo(prop1, "unknownmime", true, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting element, wildcard allowed, wildcard exists).", infosAreEqual(info1, infos.front())); + + infos = service->GetInfo(prop4, "unknownmime", false, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting element, no wildcard allowed).", infos.empty()); + infos = service->GetInfo(prop4, "unknownmime", true, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting element, wildcard allowed).", infos.empty()); + + infos = service->GetInfo("prop101", "unknownmime", false, true); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting mime, no wildcard allowed, regex allowed).", infos.empty()); + + infos = service->GetInfo("prop101", "mimeX", false, true); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (existing mime, no wildcard allowed, regex allowed).", infos.size() == 1); + + infos = service->GetInfo("otherprop", "unknownmime", false, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting mime, no wildcard allowed, no regex allowed).", infos.empty()); + + infos = service->GetInfo("otherprop", "unknownmime", true, false); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting mime, wildcard allowed, no regex allowed).", infos.empty()); + + infos = service->GetInfo("otherprop", "unknownmime", false, true); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting mime, no wildcard allowed, regex allowed).", infos.empty()); + + infos = service->GetInfo("otherprop", "unknownmime", true, true); + CPPUNIT_ASSERT_MESSAGE("Check GetInfos (inexisting mime, wildcard allowed, regex allowed).", infos.size() == 1); } - void HasInfos() + void HasInfo() { - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop1)", service->HasInfos(prop1)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", service->HasInfos(prop4)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (unkown prop)", !service->HasInfos("unkownProp")); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop1)", service->HasInfo(prop1)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", service->HasInfo(prop4)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (unkown prop)", !service->HasInfo("unkownProp")); } - void RemoveAllInfos() + void RemoveAllInfo() { - CPPUNIT_ASSERT_NO_THROW(service->RemoveAllInfos()); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop1)", !service->HasInfos(prop1)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", !service->HasInfos(prop4)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", !service->HasInfos(prop5)); + CPPUNIT_ASSERT_NO_THROW(service->RemoveAllInfo()); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop1)", !service->HasInfo(prop1)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", !service->HasInfo(prop4)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", !service->HasInfo(prop5)); } - void RemoveInfos() + void RemoveInfo() { - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos(prop1)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop1)", !service->HasInfos(prop1)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", service->HasInfos(prop4)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", service->HasInfos(prop5)); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo(prop1)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop1)", !service->HasInfo(prop1,false)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", service->HasInfo(prop4, false)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", service->HasInfo(prop5, false)); - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos(prop4)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", !service->HasInfos(prop4)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", service->HasInfos(prop5)); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo(prop4)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop4)", !service->HasInfo(prop4, false)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", service->HasInfo(prop5, false)); - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos(prop5)); - CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", !service->HasInfos(prop5)); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo(prop5)); + CPPUNIT_ASSERT_MESSAGE("Check HasInfos (prop5)", !service->HasInfo(prop5, false)); - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos("unknown_prop")); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo("unknown_prop")); } - void RemoveInfos_withMime() + void RemoveInfo_withMime() { - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos(prop1, "mime2")); - CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos if info was removed",service->GetInfo(prop1, "mime2", false).IsNull()); - CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos, if other info of same property name still exists", service->GetInfo(prop1, "mime3", false).IsNotNull()); - CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos, if other info of other property name but same mime still exists", service->GetInfo(prop4, "mime2", false).IsNotNull()); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo(prop1, "mime2")); + CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos if info was removed",service->GetInfo(prop1, "mime2", false).empty()); + CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos, if other info of same property name still exists", !service->GetInfo(prop1, "mime3", false).empty()); + CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos, if other info of other property name but same mime still exists", !service->GetInfo(prop4, "mime2", false).empty()); - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos(prop5, "wrongMime")); - CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos on prop 5 with wrong mime", service->HasInfos(prop5)); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo(prop5, "wrongMime")); + CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos on prop 5 with wrong mime", service->HasInfo(prop5, false)); - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos(prop5, "mime5")); - CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos on prop 5", !service->HasInfos(prop5)); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo(prop5, "mime5")); + CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos on prop 5", !service->HasInfo(prop5, false)); - CPPUNIT_ASSERT_NO_THROW(service->RemoveInfos("unkown_prop", "mime2")); - CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos, if unkown property name but exting mime was used", service->HasInfos(prop4)); + CPPUNIT_ASSERT_NO_THROW(service->RemoveInfo("unkown_prop", "mime2")); + CPPUNIT_ASSERT_MESSAGE("Check RemoveInfos, if unkown property name but exting mime was used", service->HasInfo(prop4, false)); } }; MITK_TEST_SUITE_REGISTRATION(mitkPropertyPersistence) diff --git a/Modules/DICOMReaderServices/src/mitkDICOMTagsOfInterestService.cpp b/Modules/DICOMReaderServices/src/mitkDICOMTagsOfInterestService.cpp index ff5a40f0d3..31ec24dd5f 100644 --- a/Modules/DICOMReaderServices/src/mitkDICOMTagsOfInterestService.cpp +++ b/Modules/DICOMReaderServices/src/mitkDICOMTagsOfInterestService.cpp @@ -1,160 +1,161 @@ /*=================================================================== 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 "mitkDICOMTagsOfInterestService.h" #include "mitkDICOMTagHelper.h" #include "usModuleContext.h" #include "usGetModuleContext.h" #include "mitkIPropertyDescriptions.h" #include "mitkIPropertyPersistence.h" #include "mitkTemporoSpatialStringProperty.h" mitk::IPropertyDescriptions* GetDescriptionsService() { mitk::IPropertyDescriptions* result = nullptr; std::vector > descriptionRegisters = us::GetModuleContext()->GetServiceReferences(); if (!descriptionRegisters.empty()) { if (descriptionRegisters.size() > 1) { MITK_WARN << "Multiple property description services found. Using just one."; } result = us::GetModuleContext()->GetService(descriptionRegisters.front()); } return result; }; mitk::IPropertyPersistence* GetPersistenceService() { mitk::IPropertyPersistence* result = nullptr; std::vector > persRegisters = us::GetModuleContext()->GetServiceReferences(); if (!persRegisters.empty()) { if (persRegisters.size() > 1) { MITK_WARN << "Multiple property description services found. Using just one."; } result = us::GetModuleContext()->GetService(persRegisters.front()); } return result; }; mitk::DICOMTagsOfInterestService:: DICOMTagsOfInterestService() { }; mitk::DICOMTagsOfInterestService:: ~DICOMTagsOfInterestService() { }; void mitk::DICOMTagsOfInterestService:: AddTagOfInterest(const DICOMTag& tag, bool makePersistant) { MutexHolder lock(m_Lock); std::string propName = mitk::GeneratPropertyNameForDICOMTag(tag); this->m_TagMap.insert(std::make_pair(propName, tag)); this->m_PersMap[propName] = makePersistant; //this must be changed even if the propname already exists. this->m_KnownTags.insert(propName); mitk::IPropertyDescriptions* descriptionSrv = GetDescriptionsService(); if (descriptionSrv) { descriptionSrv->AddDescription(propName, "DICOM tag: " + tag.GetName()); } mitk::IPropertyPersistence* persSrv = GetPersistenceService(); if (persSrv) { std::string key = propName; std::replace(key.begin(), key.end(), '.', '_'); - PropertyPersistenceInfo::Pointer info = PropertyPersistenceInfo::New(key); + PropertyPersistenceInfo::Pointer info = PropertyPersistenceInfo::New(); + info->SetNameAndKey(propName, key); info->SetDeserializationFunction(mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty); info->SetSerializationFunction(mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON); - persSrv->AddInfo(propName, info); + persSrv->AddInfo(info); } }; mitk::DICOMTagsOfInterestService::DICOMTagMapType mitk::DICOMTagsOfInterestService:: GetTagsOfInterest() const { MutexHolder lock(m_Lock); DICOMTagMapType result; for (auto tag : this->m_TagMap) { InternalTagSetType::const_iterator finding = this->m_KnownTags.find(tag.first); if (finding == this->m_KnownTags.cend()) { mitkThrow() << "Invalid status. Tag is missing in the known tag set. Problematic tag:" << tag.first; } result.insert(std::make_pair(finding->c_str(), tag.second)); } return result; }; bool mitk::DICOMTagsOfInterestService:: HasTag(const DICOMTag& tag) const { std::string propName = mitk::GeneratPropertyNameForDICOMTag(tag); return this->m_TagMap.find(propName) != this->m_TagMap.cend(); }; void mitk::DICOMTagsOfInterestService:: RemoveTag(const DICOMTag& tag) { MutexHolder lock(m_Lock); std::string propName = mitk::GeneratPropertyNameForDICOMTag(tag); this->m_PersMap.erase(propName); this->m_TagMap.erase(propName); mitk::IPropertyDescriptions* descriptionSrv = GetDescriptionsService(); if (descriptionSrv && descriptionSrv->HasDescription(propName)) { descriptionSrv->RemoveDescription(propName); } mitk::IPropertyPersistence* persSrv = GetPersistenceService(); - if (persSrv && persSrv->HasInfos(propName)) + if (persSrv && persSrv->HasInfo(propName)) { - persSrv->RemoveInfos(propName); + persSrv->RemoveInfo(propName); } }; void mitk::DICOMTagsOfInterestService:: RemoveAllTags() { MutexHolder lock(m_Lock); this->m_PersMap.clear(); this->m_TagMap.clear(); }; diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp index 5a05b24557..e8b6da0f53 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp @@ -1,119 +1,128 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionCoreIOMimeTypes.h" namespace mitk { /** \brief Registers services for segmentation module. */ class DiffusionCoreIOActivator : public us::ModuleActivator { public: void Load(us::ModuleContext* context) override { us::ServiceProperties props; props[ us::ServiceConstants::SERVICE_RANKING() ] = 10; m_MimeTypes = mitk::DiffusionCoreIOMimeTypes::Get(); for (std::vector::const_iterator mimeTypeIter = m_MimeTypes.begin(), iterEnd = m_MimeTypes.end(); mimeTypeIter != iterEnd; ++mimeTypeIter) { context->RegisterService(*mimeTypeIter, props); } m_DiffusionImageNrrdReaderService = new DiffusionImageNrrdReaderService(); m_DiffusionImageNiftiReaderService = new DiffusionImageNiftiReaderService(); m_NrrdTensorImageReader = new NrrdTensorImageReader(); m_NrrdQBallImageReader = new NrrdQBallImageReader(); m_DiffusionImageNrrdWriterService = new DiffusionImageNrrdWriterService(); m_DiffusionImageNiftiWriterService = new DiffusionImageNiftiWriterService(); m_NrrdTensorImageWriter = new NrrdTensorImageWriter(); m_NrrdQBallImageWriter = new NrrdQBallImageWriter(); //register relevant properties //non-persistent properties mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME, "This map stores which b values belong to which gradients."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME, "The original gradients used during acquisition. This property may be empty."); //persistent properties mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME, "The reference b value the gradients are normalized to."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME, "The measurment frame used during acquisition."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME, "The gradients used during acquisition."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::MODALITY, "Defines the modality used for acquisition. DWMRI signifies diffusion weighted images."); - mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME, mitk::PropertyPersistenceInfo::New("DWMRI_b-value")); - mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME, mitk::PropertyPersistenceInfo::New("measurement frame")); - mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME, mitk::PropertyPersistenceInfo::New("DWMRI_gradient")); - mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::DiffusionPropertyHelper::MODALITY, mitk::PropertyPersistenceInfo::New("modality")); + mitk::PropertyPersistenceInfo::Pointer PPI_referenceBValue = mitk::PropertyPersistenceInfo::New(); + PPI_referenceBValue->SetNameAndKey(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME, "DWMRI_b-value"); + mitk::PropertyPersistenceInfo::Pointer PPI_measurementFrame = mitk::PropertyPersistenceInfo::New(); + PPI_measurementFrame->SetNameAndKey(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME, "measurement frame"); + mitk::PropertyPersistenceInfo::Pointer PPI_gradientContainer = mitk::PropertyPersistenceInfo::New(); + PPI_gradientContainer->SetNameAndKey(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME, "DWMRI_gradient"); + mitk::PropertyPersistenceInfo::Pointer PPI_modality = mitk::PropertyPersistenceInfo::New(); + PPI_modality->SetNameAndKey(mitk::DiffusionPropertyHelper::MODALITY, "modality"); + + mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_referenceBValue.GetPointer() , true); + mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_measurementFrame.GetPointer(), true); + mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_gradientContainer.GetPointer(), true); + mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_modality.GetPointer(), true); } void Unload(us::ModuleContext*) override { for (unsigned int loop(0); loop < m_MimeTypes.size(); ++loop) { delete m_MimeTypes.at(loop); } delete m_DiffusionImageNrrdReaderService; delete m_DiffusionImageNiftiReaderService; delete m_NrrdTensorImageReader; delete m_NrrdQBallImageReader; delete m_DiffusionImageNrrdWriterService; delete m_DiffusionImageNiftiWriterService; delete m_NrrdTensorImageWriter; delete m_NrrdQBallImageWriter; } private: DiffusionImageNrrdReaderService * m_DiffusionImageNrrdReaderService; DiffusionImageNiftiReaderService * m_DiffusionImageNiftiReaderService; NrrdTensorImageReader * m_NrrdTensorImageReader; NrrdQBallImageReader * m_NrrdQBallImageReader; DiffusionImageNrrdWriterService * m_DiffusionImageNrrdWriterService; DiffusionImageNiftiWriterService * m_DiffusionImageNiftiWriterService; NrrdTensorImageWriter * m_NrrdTensorImageWriter; NrrdQBallImageWriter * m_NrrdQBallImageWriter; std::vector m_MimeTypes; }; } US_EXPORT_MODULE_ACTIVATOR(mitk::DiffusionCoreIOActivator) diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkAddNewPropertyDialog.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkAddNewPropertyDialog.cpp index 7b183a0362..65a12b04a6 100644 --- a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkAddNewPropertyDialog.cpp +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkAddNewPropertyDialog.cpp @@ -1,205 +1,208 @@ /*=================================================================== 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 "QmitkAddNewPropertyDialog.h" #include "mitkGetPropertyService.h" #include #include #include #include QmitkAddNewPropertyDialog::QmitkAddNewPropertyDialog(mitk::BaseData::Pointer baseData, QWidget* parent) : QDialog(parent), m_BaseData(baseData) { this->Initialize(); } QmitkAddNewPropertyDialog::QmitkAddNewPropertyDialog(mitk::DataNode::Pointer dataNode, mitk::BaseRenderer::Pointer renderer, QWidget* parent) : QDialog(parent), m_DataNode(dataNode), m_Renderer(renderer) { this->Initialize(); } QmitkAddNewPropertyDialog::~QmitkAddNewPropertyDialog() { } void QmitkAddNewPropertyDialog::Initialize() { m_Controls.setupUi(this); QStringList types; types << "bool" << "double" << "float" << "int" << "string"; m_Controls.typeComboBox->addItems(types); m_Controls.persistentLabel->setVisible(m_BaseData.IsNotNull()); m_Controls.persistentCheckBox->setVisible(m_BaseData.IsNotNull()); connect(m_Controls.typeComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(ShowAdequateValueWidget(const QString&))); connect(m_Controls.addButton, SIGNAL(clicked()), this, SLOT(AddNewProperty())); connect(m_Controls.cancelButton, SIGNAL(clicked()), this, SLOT(reject())); this->ShowAdequateValueWidget(types[0]); } void QmitkAddNewPropertyDialog::AddNewProperty() { if (m_Controls.nameLineEdit->text().isEmpty()) { QMessageBox::critical(this, "No name specified", "Enter a property name."); return; } if (!this->ValidateValue()) { QMessageBox::critical(this, "Invalid value", "Enter a valid " + m_Controls.typeComboBox->currentText() + " value."); return; } if (m_BaseData.IsNotNull()) { mitk::BaseProperty::Pointer property = this->CreateProperty(); m_BaseData->SetProperty(m_Controls.nameLineEdit->text().toLatin1(), property); if (m_Controls.persistentCheckBox->isChecked()) { mitk::IPropertyPersistence* propertyPersistence = mitk::GetPropertyService(); if (propertyPersistence != nullptr) - propertyPersistence->AddInfo(m_Controls.nameLineEdit->text().toStdString(), mitk::PropertyPersistenceInfo::New()); + { + mitk::PropertyPersistenceInfo::Pointer info = mitk::PropertyPersistenceInfo::New(m_Controls.nameLineEdit->text().toStdString()); + propertyPersistence->AddInfo(info); + } } } else { m_DataNode->SetProperty(m_Controls.nameLineEdit->text().toLatin1(), this->CreateProperty(), m_Renderer); } this->accept(); } mitk::BaseProperty::Pointer QmitkAddNewPropertyDialog::CreateProperty() const { QString type = m_Controls.typeComboBox->currentText(); if (type == "bool") { return mitk::BoolProperty::New(m_Controls.valueCheckBox->isChecked()).GetPointer(); } else if (type == "double") { return mitk::DoubleProperty::New(m_Controls.valueLineEdit->text().toDouble()).GetPointer(); } else if (type == "float") { return mitk::FloatProperty::New(m_Controls.valueLineEdit->text().toFloat()).GetPointer(); } else if (type == "int") { return mitk::IntProperty::New(m_Controls.valueLineEdit->text().toInt()).GetPointer(); } else if (type == "string") { return mitk::StringProperty::New(m_Controls.valueLineEdit->text().toStdString()).GetPointer(); } else { assert(false && "Property creation for selected type not implemented!"); } return NULL; } bool QmitkAddNewPropertyDialog::ValidateValue() { QString type = m_Controls.typeComboBox->currentText(); if (type == "bool") { return true; } else if (type == "double") { bool ok = false; m_Controls.valueLineEdit->text().toDouble(&ok); return ok; } else if (type == "float") { bool ok = false; m_Controls.valueLineEdit->text().toFloat(&ok); return ok; } else if (type == "int") { bool ok = false; m_Controls.valueLineEdit->text().toInt(&ok); return ok; } else if (type == "string") { return true; } else { assert(false && "Value validation for selected type not implemented!"); } return false; } void QmitkAddNewPropertyDialog::ShowAdequateValueWidget(const QString& type) { m_Controls.valueLineEdit->clear(); m_Controls.valueLineEdit->hide(); m_Controls.valueCheckBox->setChecked(false); m_Controls.valueCheckBox->hide(); if (type == "bool") { m_Controls.valueCheckBox->show(); } else if (type == "double") { m_Controls.valueLineEdit->setText("0"); m_Controls.valueLineEdit->show(); } else if (type == "float") { m_Controls.valueLineEdit->setText("0"); m_Controls.valueLineEdit->show(); } else if (type == "int") { m_Controls.valueLineEdit->setText("0"); m_Controls.valueLineEdit->show(); } else if (type == "string") { m_Controls.valueLineEdit->show(); } else { assert(false && "No adequate value widget specified for selected type!"); } } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.cpp index 63dccb8316..2c4d42d0c4 100644 --- a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.cpp +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.cpp @@ -1,463 +1,463 @@ /*=================================================================== 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 "mitkGetPropertyService.h" #include "QmitkAddNewPropertyDialog.h" #include "QmitkPropertiesPreferencePage.h" #include "QmitkPropertyItemDelegate.h" #include "QmitkPropertyItemModel.h" #include "QmitkPropertyItemSortFilterProxyModel.h" #include "QmitkPropertyTreeView.h" #include #include #include #include #include #include #include const std::string QmitkPropertyTreeView::VIEW_ID = "org.mitk.views.properties"; QmitkPropertyTreeView::QmitkPropertyTreeView() : m_Parent(nullptr), m_PropertyNameChangedTag(0), m_PropertyAliases(nullptr), m_PropertyDescriptions(nullptr), m_PropertyPersistence(nullptr), m_ShowAliasesInDescription(true), m_ShowPersistenceInDescription(true), m_DeveloperMode(false), m_ProxyModel(nullptr), m_Model(nullptr), m_Delegate(nullptr), m_Renderer(nullptr) { } QmitkPropertyTreeView::~QmitkPropertyTreeView() { } void QmitkPropertyTreeView::CreateQtPartControl(QWidget* parent) { m_Parent = parent; m_Controls.setupUi(parent); m_Controls.propertyListComboBox->addItem("Data node: common"); mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); if (renderWindowPart != NULL) { QHash renderWindows = renderWindowPart->GetQmitkRenderWindows(); Q_FOREACH(QString renderWindow, renderWindows.keys()) { m_Controls.propertyListComboBox->addItem(QString("Data node: ") + renderWindow); } } m_Controls.propertyListComboBox->addItem("Base data"); m_Controls.newButton->setEnabled(false); m_Controls.description->hide(); m_Controls.propertyListLabel->hide(); m_Controls.propertyListComboBox->hide(); m_Controls.newButton->hide(); m_ProxyModel = new QmitkPropertyItemSortFilterProxyModel(m_Controls.treeView); m_Model = new QmitkPropertyItemModel(m_ProxyModel); m_ProxyModel->setSourceModel(m_Model); m_ProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); m_ProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); m_ProxyModel->setDynamicSortFilter(true); m_Delegate = new QmitkPropertyItemDelegate(m_Controls.treeView); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) m_Controls.filterLineEdit->setClearButtonEnabled(true); #endif m_Controls.treeView->setItemDelegateForColumn(1, m_Delegate); m_Controls.treeView->setModel(m_ProxyModel); m_Controls.treeView->setColumnWidth(0, 160); m_Controls.treeView->sortByColumn(0, Qt::AscendingOrder); m_Controls.treeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.treeView->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.treeView->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked); connect(m_Controls.filterLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(OnFilterTextChanged(const QString&))); connect(m_Controls.propertyListComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPropertyListChanged(int))); connect(m_Controls.newButton, SIGNAL(clicked()), this, SLOT(OnAddNewProperty())); connect(m_Controls.treeView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(OnCurrentRowChanged(const QModelIndex&, const QModelIndex&))); connect(m_Model, SIGNAL(modelReset()), this, SLOT(OnModelReset())); } QString QmitkPropertyTreeView::GetPropertyNameOrAlias(const QModelIndex& index) { QString propertyName; if (index.isValid()) { QModelIndex current = index; while (current.isValid()) { QString name = m_ProxyModel->data(m_ProxyModel->index(current.row(), 0, current.parent())).toString(); propertyName.prepend(propertyName.isEmpty() ? name : name.append('.')); current = current.parent(); } } return propertyName; } void QmitkPropertyTreeView::OnCurrentRowChanged(const QModelIndex& current, const QModelIndex&) { if (m_PropertyDescriptions != nullptr && current.isValid()) { QString name = this->GetPropertyNameOrAlias(current); if (!name.isEmpty()) { QString alias; bool isTrueName = true; if (m_PropertyAliases != nullptr) { std::string trueName = m_PropertyAliases->GetPropertyName(name.toStdString()); if (trueName.empty() && !m_SelectionClassName.empty()) trueName = m_PropertyAliases->GetPropertyName(name.toStdString(), m_SelectionClassName); if (!trueName.empty()) { alias = name; name = QString::fromStdString(trueName); isTrueName = false; } } QString description = QString::fromStdString(m_PropertyDescriptions->GetDescription(name.toStdString())); std::vector aliases; if (!isTrueName && m_PropertyAliases != nullptr) { aliases = m_PropertyAliases->GetAliases(name.toStdString(), m_SelectionClassName); if (aliases.empty() && !m_SelectionClassName.empty()) aliases = m_PropertyAliases->GetAliases(name.toStdString()); } bool isPersistent = false; // QString persistenceKey; if (m_PropertyPersistence != nullptr) { - isPersistent = m_PropertyPersistence->HasInfos(name.toStdString()); + isPersistent = m_PropertyPersistence->HasInfo(name.toStdString()); /*if (isPersistent) { persistenceKey = QString::fromStdString(m_PropertyPersistence->GetInfo(name.toStdString())->GetKey()); if (persistenceKey.isEmpty()) persistenceKey = name; }*/ } if (!description.isEmpty() || !aliases.empty() || isPersistent) { QString customizedDescription; if (m_ShowAliasesInDescription && !aliases.empty()) { customizedDescription = "

" + name + "

"; std::size_t numAliases = aliases.size(); std::size_t lastAlias = numAliases - 1; for (std::size_t i = 0; i < numAliases; ++i) { customizedDescription += i != lastAlias ? "
" : "
"; customizedDescription += QString::fromStdString(aliases[i]) + "
"; } } else { customizedDescription = "

" + name + "

"; } if (!description.isEmpty()) customizedDescription += "

" + description + "

"; if (!aliases.empty() || isPersistent) { customizedDescription += "
"; if (!aliases.empty()) { customizedDescription += aliases.size() > 1 ? "" : ""; } if (isPersistent) customizedDescription += ""; customizedDescription += "
"; } m_Controls.description->setText(customizedDescription); m_Controls.description->show(); return; } } } m_Controls.description->hide(); } void QmitkPropertyTreeView::OnFilterTextChanged(const QString& filter) { m_ProxyModel->setFilterWildcard(filter); if (filter.isEmpty()) m_Controls.treeView->collapseAll(); else m_Controls.treeView->expandAll(); } void QmitkPropertyTreeView::OnModelReset() { m_Controls.description->hide(); } void QmitkPropertyTreeView::OnPreferencesChanged(const berry::IBerryPreferences* preferences) { bool showAliases = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES, true); bool showDescriptions = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_DESCRIPTIONS, true); bool showAliasesInDescription = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES_IN_DESCRIPTION, true); bool showPersistenceInDescription = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_PERSISTENCE_IN_DESCRIPTION, true); bool developerMode = preferences->GetBool(QmitkPropertiesPreferencePage::DEVELOPER_MODE, false); bool filterProperties = preferences->GetBool(QmitkPropertiesPreferencePage::FILTER_PROPERTIES, true); m_Model->SetFilterProperties(filterProperties); m_Model->SetShowAliases(showAliases); bool updateAliases = showAliases != (m_PropertyAliases != NULL); bool updateDescriptions = showDescriptions != (m_PropertyDescriptions != NULL); bool updateAliasesInDescription = showAliasesInDescription != m_ShowAliasesInDescription; bool updatePersistenceInDescription = showPersistenceInDescription != m_ShowPersistenceInDescription; bool updateDeveloperMode = developerMode != m_DeveloperMode; if (updateAliases) m_PropertyAliases = showAliases ? mitk::GetPropertyService() : nullptr; if (updateDescriptions) m_PropertyDescriptions = showDescriptions ? mitk::GetPropertyService() : nullptr; if (showPersistenceInDescription) m_PropertyPersistence = mitk::GetPropertyService(); if (updateAliasesInDescription) m_ShowAliasesInDescription = showAliasesInDescription; if (updatePersistenceInDescription) m_ShowPersistenceInDescription = showPersistenceInDescription; if (updateDescriptions || updateAliasesInDescription || updatePersistenceInDescription) { QModelIndexList selection = m_Controls.treeView->selectionModel()->selectedRows(); if (!selection.isEmpty()) this->OnCurrentRowChanged(selection[0], selection[0]); } if (updateDeveloperMode) { m_DeveloperMode = developerMode; if (!developerMode) m_Controls.propertyListComboBox->setCurrentIndex(0); m_Controls.propertyListLabel->setVisible(developerMode); m_Controls.propertyListComboBox->setVisible(developerMode); m_Controls.newButton->setVisible(developerMode); } m_Model->OnPreferencesChanged(); } void QmitkPropertyTreeView::OnPropertyNameChanged(const itk::EventObject&) { mitk::PropertyList* propertyList = m_Model->GetPropertyList(); if (propertyList != NULL) { mitk::BaseProperty* nameProperty = propertyList->GetProperty("name"); if (nameProperty != NULL) { QString partName = "Properties ("; partName.append(QString::fromStdString(nameProperty->GetValueAsString())).append(')'); this->SetPartName(partName); } } } void QmitkPropertyTreeView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { mitk::PropertyList* propertyList = m_Model->GetPropertyList(); if (propertyList != NULL) { mitk::BaseProperty* nameProperty = propertyList->GetProperty("name"); if (nameProperty != NULL) nameProperty->RemoveObserver(m_PropertyNameChangedTag); m_PropertyNameChangedTag = 0; } if (nodes.empty() || nodes.front().IsNull()) { m_SelectedNode = NULL; this->SetPartName("Properties"); m_Model->SetPropertyList(NULL); m_Delegate->SetPropertyList(NULL); m_Controls.newButton->setEnabled(false); } else { m_SelectedNode = nodes.front(); QString selectionClassName = m_SelectedNode->GetData() != NULL ? m_SelectedNode->GetData()->GetNameOfClass() : ""; m_SelectionClassName = selectionClassName.toStdString(); mitk::PropertyList::Pointer propertyList; if (m_Renderer == NULL && m_Controls.propertyListComboBox->currentText() == "Base data") { propertyList = m_SelectedNode->GetData() != NULL ? m_SelectedNode->GetData()->GetPropertyList() : NULL; } else { propertyList = m_SelectedNode->GetPropertyList(m_Renderer); } m_Model->SetPropertyList(propertyList, selectionClassName); m_Delegate->SetPropertyList(propertyList); OnPropertyNameChanged(itk::ModifiedEvent()); mitk::BaseProperty* nameProperty = m_SelectedNode->GetProperty("name"); if (nameProperty != NULL) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkPropertyTreeView::OnPropertyNameChanged); m_PropertyNameChangedTag = nameProperty->AddObserver(itk::ModifiedEvent(), command); } m_Controls.newButton->setEnabled(true); } if (!m_ProxyModel->filterRegExp().isEmpty()) m_Controls.treeView->expandAll(); } void QmitkPropertyTreeView::SetFocus() { m_Controls.filterLineEdit->setFocus(); } void QmitkPropertyTreeView::RenderWindowPartActivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { if (m_Controls.propertyListComboBox->count() == 2) { QHash renderWindows = this->GetRenderWindowPart()->GetQmitkRenderWindows(); Q_FOREACH(QString renderWindow, renderWindows.keys()) { m_Controls.propertyListComboBox->insertItem(m_Controls.propertyListComboBox->count() - 1, QString("Data node: ") + renderWindow); } } } void QmitkPropertyTreeView::RenderWindowPartDeactivated(mitk::IRenderWindowPart*) { if (m_Controls.propertyListComboBox->count() > 2) { m_Controls.propertyListComboBox->clear(); m_Controls.propertyListComboBox->addItem("Data node: common"); m_Controls.propertyListComboBox->addItem("Base data"); } } void QmitkPropertyTreeView::OnPropertyListChanged(int index) { if (index == -1) return; QString renderer = m_Controls.propertyListComboBox->itemText(index); if (renderer.startsWith("Data node: ")) renderer = QString::fromStdString(renderer.toStdString().substr(11)); m_Renderer = renderer != "common" && renderer != "Base data" ? this->GetRenderWindowPart()->GetQmitkRenderWindow(renderer)->GetRenderer() : NULL; QList nodes; if (m_SelectedNode.IsNotNull()) nodes << m_SelectedNode; berry::IWorkbenchPart::Pointer workbenchPart; this->OnSelectionChanged(workbenchPart, nodes); } void QmitkPropertyTreeView::OnAddNewProperty() { std::unique_ptr dialog(m_Controls.propertyListComboBox->currentText() != "Base data" ? new QmitkAddNewPropertyDialog(m_SelectedNode, m_Renderer, m_Parent) : new QmitkAddNewPropertyDialog(m_SelectedNode->GetData())); if (dialog->exec() == QDialog::Accepted) this->m_Model->Update(); }