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..7e83b73263 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 + * (GetInfos and GetInfosByKey) 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. * * \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 infos with regexs are be checked. * \return Property persistence info or null pointer if no persistence info is available. */ - virtual InfoMapType GetInfos(const std::string& propertyName) = 0; + virtual InfoResultType GetInfos(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 infos with regexs are be checked. * \return Property persistence info or null pointer if no persistence info is available. */ - virtual InfoMapType GetInfosByKey(const std::string& persistenceKey) = 0; + virtual InfoResultType GetInfos(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 infos with regexs for the key are be 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 GetInfosByKey(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 infos with regexs are be checked. * \return True if the property has persistence info, false otherwise. */ - virtual bool HasInfos(const std::string& propertyName) = 0; + virtual bool HasInfos(const std::string& propertyName, bool allowNameRegEx = true) const = 0; /** \brief Remove all persistence info. */ virtual void RemoveAllInfos() = 0; - /** \brief Remove persistence infos of a specific property name. + /** \brief Remove persistence infos 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; - /** \brief Remove persistence infos of a specific property name and mime type. + /** \brief Remove persistence infos 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; }; } 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..28b3c3c083 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; + bool AddInfo(const PropertyPersistenceInfo* info, bool overwrite) override; + InfoResultType GetInfos(const std::string& propertyName, bool allowNameRegEx) const override; + InfoResultType GetInfos(const std::string& propertyName, const MimeTypeNameType& mime, bool allowMimeWildCard, bool allowNameRegEx) const override; + InfoResultType GetInfosByKey(const std::string& persistenceKey, bool allowKeyRegEx) const override; + bool HasInfos(const std::string& propertyName, bool allowNameRegEx) const override; void RemoveAllInfos() override; void RemoveInfos(const std::string& propertyName) override; void RemoveInfos(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 SelectInfos(const InfoMap& infos, const SelectFunctionType& selectFunction); PropertyPersistence(const PropertyPersistence&); PropertyPersistence& operator=(const PropertyPersistence&); InfoMap m_Infos; }; /**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..91b489942c 100644 --- a/Modules/Core/include/mitkPropertyPersistenceInfo.h +++ b/Modules/Core/include/mitkPropertyPersistenceInfo.h @@ -1,104 +1,123 @@ /*=================================================================== 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.*/ 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(); private: PropertyPersistenceInfo(const Self& other); Self& operator=(const Self& other); struct Impl; Impl* m_Impl; }; 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..a415c06f72 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyPersistence.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyPersistence.cpp @@ -1,157 +1,250 @@ /*=================================================================== 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_Infos.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); } result = true; - m_Infos.insert(std::make_pair(propertyName, info)); + m_Infos.insert(std::make_pair(info->GetName(), info)); } return result; } -mitk::PropertyPersistence::InfoMapType mitk::PropertyPersistence::GetInfos(const std::string& propertyName) +mitk::PropertyPersistence::InfoMap mitk::PropertyPersistence::SelectInfos(const InfoMap& infos, const SelectFunctionType& selectFunction) { - auto infoRange = m_Infos.equal_range(propertyName); + InfoMap result; - InfoMapType result; - - for (auto pos = infoRange.first; pos != infoRange.second; ++pos) + for (auto pos : infos) { - 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::GetInfos(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; + }; + + InfoMap selection = SelectInfos(m_Infos, select); + + InfoResultType result; + for (const auto & pos : selection) + { + result.push_back(pos.second->UnRegExByName(propertyName).GetPointer()); + } - for (auto pos : m_Infos) + if (allowNameRegEx) { - if (pos.second.IsNotNull() && pos.second->GetKey() == persistenceKey) + select = [propertyName](const InfoMap::value_type& x) { - result.insert(std::make_pair(pos.first, pos.second)); + if (x.second.IsNotNull() && x.second->IsRegEx()) + { + std::regex ex(x.second->GetName()); + return std::regex_match(propertyName, ex); + } + return false; + }; + + selection = SelectInfos(m_Infos, select); + + for (const auto & pos : selection) + { + 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::GetInfos(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 = SelectInfos(m_Infos, 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 = SelectInfos(m_Infos, 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 = SelectInfos(m_Infos, select); + + if (allowNameRegEx) + { + select = [propertyName](const InfoMap::value_type& x) + { + return infoPredicateRegEx(x, propertyName, PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); + }; + + InfoMap regExSelection = SelectInfos(m_Infos, 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::GetInfosByKey(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_Infos) + { + 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; +} + +bool mitk::PropertyPersistence::HasInfos(const std::string& propertyName, bool allowNameRegEx) const +{ + return !this->GetInfos(propertyName, allowNameRegEx).empty(); } void mitk::PropertyPersistence::RemoveAllInfos() { m_Infos.clear(); + m_Infos.clear(); } void mitk::PropertyPersistence::RemoveInfos(const std::string& propertyName) { if (!propertyName.empty()) + { m_Infos.erase(propertyName); + } } void mitk::PropertyPersistence::RemoveInfos(const std::string& propertyName, const MimeTypeNameType& mime) { auto itr = m_Infos.begin(); while (itr != m_Infos.end()) { if (itr->first == propertyName && itr->second.IsNotNull() && itr->second->GetMimeTypeName() == mime) { itr = m_Infos.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..8af93ea925 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyPersistenceInfo.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyPersistenceInfo.cpp @@ -1,122 +1,237 @@ /*=================================================================== 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 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; }; +mitk::BaseProperty::Pointer mitk::PropertyPersistenceDeserialization::deserializeToStringProperty(const std::string& value) +{ + StringProperty::Pointer result = StringProperty::New(value); + return result.GetPointer(); +} + +std::string GenerateFromTemplate(const std::string& sourceStr, const std::string& templateStr, const std::string& regexStr) +{ + std::smatch sm; + std::regex ex(regexStr); + assert(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; }; ::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(); -}