diff --git a/Core/Code/DataManagement/mitkPropertyList.cpp b/Core/Code/DataManagement/mitkPropertyList.cpp index 9c74057c8f..ee4c4d25b6 100644 --- a/Core/Code/DataManagement/mitkPropertyList.cpp +++ b/Core/Code/DataManagement/mitkPropertyList.cpp @@ -1,351 +1,357 @@ /*=================================================================== 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 "mitkPropertyList.h" #include "mitkProperties.h" #include "mitkStringProperty.h" #include "mitkVector.h" mitk::BaseProperty* mitk::PropertyList::GetProperty(const std::string& propertyKey) const { PropertyMap::const_iterator it; it=m_Properties.find( propertyKey ); if(it!=m_Properties.end()) return it->second; else return NULL; } void mitk::PropertyList::SetProperty(const std::string& propertyKey, BaseProperty* property) { if (!property) return; //make sure that BaseProperty*, which may have just been created and never been //assigned to a SmartPointer, is registered/unregistered properly. If we do not //do that, it will a) not deleted in case it is identical to the old one or //b) possibly deleted when temporarily added to a smartpointer somewhere below. BaseProperty::Pointer tmpSmartPointerToProperty = property; PropertyMap::iterator it( m_Properties.find( propertyKey ) ); // Is a property with key @a propertyKey contained in the list? if( it != m_Properties.end() ) { // yes //is the property contained in the list identical to the new one? if( it->second->operator==(*property) ) { // yes? do nothing and return. return; } if (it->second->AssignProperty(*property)) { // The assignment was successfull this->Modified(); } else { MITK_ERROR << "In " __FILE__ ", l." << __LINE__ << ": Trying to set existing property " << it->first << " of type " << it->second->GetNameOfClass() << " to a property with different type " << property->GetNameOfClass() << "." << " Use ReplaceProperty() instead." << std::endl; } return; } //no? add it. PropertyMapElementType newProp; newProp.first = propertyKey; newProp.second = property; m_Properties.insert ( newProp ); this->Modified(); } void mitk::PropertyList::ReplaceProperty(const std::string& propertyKey, BaseProperty* property) { if (!property) return; PropertyMap::iterator it( m_Properties.find( propertyKey ) ); // Is a property with key @a propertyKey contained in the list? if( it != m_Properties.end() ) { it->second=NULL; m_Properties.erase(it); } //no? add/replace it. PropertyMapElementType newProp; newProp.first = propertyKey; newProp.second = property; m_Properties.insert ( newProp ); Modified(); } mitk::PropertyList::PropertyList() { } mitk::PropertyList::PropertyList(const mitk::PropertyList& other) : itk::Object() { for (PropertyMap::const_iterator i = other.m_Properties.begin(); i != other.m_Properties.end(); ++i) { m_Properties.insert(std::make_pair(i->first, i->second->Clone())); } } mitk::PropertyList::~PropertyList() { Clear(); } /** * Consider the list as changed when any of the properties has changed recently. */ unsigned long mitk::PropertyList::GetMTime() const { for ( PropertyMap::const_iterator it = m_Properties.begin() ; it != m_Properties.end(); ++it ) { if( it->second.IsNull() ) { itkWarningMacro(<< "Property '" << it->first <<"' contains nothing (NULL)."); continue; } if( Superclass::GetMTime() < it->second->GetMTime() ) { Modified(); break; } } return Superclass::GetMTime(); } bool mitk::PropertyList::DeleteProperty(const std::string& propertyKey) { PropertyMap::iterator it; it=m_Properties.find( propertyKey ); if(it!=m_Properties.end()) { it->second=NULL; m_Properties.erase(it); Modified(); return true; } return false; } void mitk::PropertyList::Clear() { PropertyMap::iterator it = m_Properties.begin(), end = m_Properties.end(); while(it!=end) { it->second = NULL; ++it; } m_Properties.clear(); } itk::LightObject::Pointer mitk::PropertyList::InternalClone() const { itk::LightObject::Pointer result(new Self(*this)); return result; } void mitk::PropertyList::ConcatenatePropertyList(PropertyList *pList, bool replace) { if (pList) { const PropertyMap* propertyMap = pList->GetMap(); for ( PropertyMap::const_iterator iter = propertyMap->begin(); // m_PropertyList is created in the constructor, so we don't check it here iter != propertyMap->end(); ++iter ) { const std::string key = iter->first; BaseProperty* value = iter->second; if (replace) { ReplaceProperty( key.c_str(), value ); } else { SetProperty( key.c_str(), value ); } } } } bool mitk::PropertyList::GetBoolProperty(const char* propertyKey, bool& boolValue) const { BoolProperty *gp = dynamic_cast( GetProperty(propertyKey) ); if ( gp != NULL ) { boolValue = gp->GetValue(); return true; } return false; // Templated Method does not work on Macs //return GetPropertyValue(propertyKey, boolValue); } bool mitk::PropertyList::GetIntProperty(const char* propertyKey, int &intValue) const { IntProperty *gp = dynamic_cast( GetProperty(propertyKey) ); if ( gp != NULL ) { intValue = gp->GetValue(); return true; } return false; // Templated Method does not work on Macs //return GetPropertyValue(propertyKey, intValue); } bool mitk::PropertyList::GetFloatProperty(const char* propertyKey, float &floatValue) const { FloatProperty *gp = dynamic_cast( GetProperty(propertyKey) ); if ( gp != NULL ) { floatValue = gp->GetValue(); return true; } return false; // Templated Method does not work on Macs //return GetPropertyValue(propertyKey, floatValue); } bool mitk::PropertyList::GetStringProperty(const char* propertyKey, std::string& stringValue) const { StringProperty* sp= dynamic_cast(GetProperty(propertyKey)); if ( sp != NULL ) { stringValue = sp->GetValue(); return true; } return false; } void mitk::PropertyList::SetIntProperty(const char* propertyKey, int intValue) { SetProperty(propertyKey, mitk::IntProperty::New(intValue)); } void mitk::PropertyList::SetBoolProperty( const char* propertyKey, bool boolValue) { SetProperty(propertyKey, mitk::BoolProperty::New(boolValue)); } void mitk::PropertyList::SetFloatProperty( const char* propertyKey, float floatValue) { SetProperty(propertyKey, mitk::FloatProperty::New(floatValue)); } void mitk::PropertyList::SetStringProperty( const char* propertyKey, const char* stringValue) { SetProperty(propertyKey, mitk::StringProperty::New(stringValue)); } void mitk::PropertyList::Set( const char* propertyKey, bool boolValue ) { this->SetBoolProperty( propertyKey, boolValue ); } void mitk::PropertyList::Set( const char* propertyKey, int intValue ) { this->SetIntProperty(propertyKey, intValue); } void mitk::PropertyList::Set( const char* propertyKey, float floatValue ) { this->SetFloatProperty(propertyKey, floatValue); } void mitk::PropertyList::Set( const char* propertyKey, double doubleValue ) { this->SetDoubleProperty(propertyKey, doubleValue); } void mitk::PropertyList::Set( const char* propertyKey, const char* stringValue ) { this->SetStringProperty(propertyKey, stringValue); } +void mitk::PropertyList::Set( const char* propertyKey, const std::string& stringValue ) +{ + this->SetStringProperty(propertyKey, stringValue.c_str()); + +} + bool mitk::PropertyList::Get( const char* propertyKey, bool& boolValue ) const { return this->GetBoolProperty( propertyKey, boolValue ); } bool mitk::PropertyList::Get( const char* propertyKey, int &intValue ) const { return this->GetIntProperty(propertyKey, intValue); } bool mitk::PropertyList::Get( const char* propertyKey, float &floatValue ) const { return this->GetFloatProperty( propertyKey, floatValue ); } bool mitk::PropertyList::Get( const char* propertyKey, double &doubleValue ) const { return this->GetDoubleProperty( propertyKey, doubleValue ); } bool mitk::PropertyList::Get( const char* propertyKey, std::string& stringValue ) const { return this->GetStringProperty( propertyKey, stringValue ); } bool mitk::PropertyList::GetDoubleProperty( const char* propertyKey, double &doubleValue ) const { DoubleProperty *gp = dynamic_cast( GetProperty(propertyKey) ); if ( gp != NULL ) { doubleValue = gp->GetValue(); return true; } return false; } void mitk::PropertyList::SetDoubleProperty( const char* propertyKey, double doubleValue ) { SetProperty(propertyKey, mitk::DoubleProperty::New(doubleValue)); } diff --git a/Core/Code/DataManagement/mitkPropertyList.h b/Core/Code/DataManagement/mitkPropertyList.h index eb5de870cc..0a1aef58cb 100644 --- a/Core/Code/DataManagement/mitkPropertyList.h +++ b/Core/Code/DataManagement/mitkPropertyList.h @@ -1,260 +1,264 @@ /*=================================================================== 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 PROPERTYLIST_H_HEADER_INCLUDED_C1C77D8D #define PROPERTYLIST_H_HEADER_INCLUDED_C1C77D8D #include #include "mitkBaseProperty.h" #include "mitkGenericProperty.h" #include "mitkUIDGenerator.h" #include #include #include namespace mitk { class XMLWriter; /** * @brief Key-value list holding instances of BaseProperty * * This list is meant to hold an arbitrary list of "properties", * which should describe the object associated with this list. * * Usually you will use PropertyList as part of a DataNode * object - in this context the properties describe the data object * held by the DataNode (e.g. whether the object is rendered at * all, which color is used for rendering, what name should be * displayed for the object, etc.) * * The values in the list are not fixed, you may introduce any kind * of property that seems useful - all you have to do is inherit * from BaseProperty. * * The list is organized as a key-value pairs, i.e. * * \li "name" : pointer to a StringProperty * \li "visible" : pointer to a BoolProperty * \li "color" : pointer to a ColorProperty * \li "volume" : pointer to a FloatProperty * * Please see the documentation of SetProperty and ReplaceProperty for two * quite different semantics. Normally SetProperty is what you want - this * method will try to change the value of an existing property and will * not allow you to replace e.g. a ColorProperty with an IntProperty. * * @ingroup DataManagement */ class MITK_CORE_EXPORT PropertyList : public itk::Object { public: mitkClassMacro(PropertyList, itk::Object) /** * Method for creation through the object factory. */ itkNewMacro(Self) /** * Map structure to hold the properties: the map key is a string, * the value consists of the actual property object (BaseProperty). */ typedef std::map< std::string, BaseProperty::Pointer> PropertyMap; typedef std::pair< std::string, BaseProperty::Pointer> PropertyMapElementType; /** * @brief Get a property by its name. */ mitk::BaseProperty* GetProperty(const std::string& propertyKey) const; /** * @brief Set a property in the list/map by value. * * The actual OBJECT holding the value of the property is not replaced, but its value * is modified to match that of @a property. To really replace the object holding the * property - which would make sense if you want to change the type (bool, string) of the property * - call ReplaceProperty. */ void SetProperty(const std::string& propertyKey, BaseProperty* property); /** * @brief Set a property object in the list/map by reference. * * The actual OBJECT holding the value of the property is replaced by this function. * This is useful if you want to change the type of the property, like from BoolProperty to StringProperty. * Another use is to share one and the same property object among several ProperyList/DataNode objects, which * makes them appear synchronized. */ void ReplaceProperty(const std::string& propertyKey, BaseProperty* property); /** * @brief Set a property object in the list/map by reference. */ void ConcatenatePropertyList(PropertyList *pList, bool replace = false); //##Documentation //## @brief Convenience access method for GenericProperty properties //## (T being the type of the second parameter) //## @return @a true property was found template bool GetPropertyValue(const char* propertyKey, T & value) const { GenericProperty* gp= dynamic_cast*>(GetProperty(propertyKey)); if ( gp != NULL ) { value = gp->GetValue(); return true; } return false; } /** * @brief Convenience method to access the value of a BoolProperty */ bool GetBoolProperty(const char* propertyKey, bool& boolValue) const; /** * @brief ShortCut for the above method */ bool Get(const char* propertyKey, bool& boolValue) const; /** * @brief Convenience method to set the value of a BoolProperty */ void SetBoolProperty( const char* propertyKey, bool boolValue); /** * @brief ShortCut for the above method */ void Set( const char* propertyKey, bool boolValue); /** * @brief Convenience method to access the value of an IntProperty */ bool GetIntProperty(const char* propertyKey, int &intValue) const; /** * @brief ShortCut for the above method */ bool Get(const char* propertyKey, int &intValue) const; /** * @brief Convenience method to set the value of an IntProperty */ void SetIntProperty(const char* propertyKey, int intValue); /** * @brief ShortCut for the above method */ void Set(const char* propertyKey, int intValue); /** * @brief Convenience method to access the value of a FloatProperty */ bool GetFloatProperty(const char* propertyKey, float &floatValue) const; /** * @brief ShortCut for the above method */ bool Get(const char* propertyKey, float &floatValue) const; /** * @brief Convenience method to set the value of a FloatProperty */ void SetFloatProperty( const char* propertyKey, float floatValue); /** * @brief ShortCut for the above method */ void Set( const char* propertyKey, float floatValue); /** * @brief Convenience method to access the value of a DoubleProperty */ bool GetDoubleProperty(const char* propertyKey, double &doubleValue) const; /** * @brief ShortCut for the above method */ bool Get(const char* propertyKey, double &doubleValue) const; /** * @brief Convenience method to set the value of a DoubleProperty */ void SetDoubleProperty( const char* propertyKey, double doubleValue); /** * @brief ShortCut for the above method */ void Set( const char* propertyKey, double doubleValue); /** * @brief Convenience method to access the value of a StringProperty */ bool GetStringProperty(const char* propertyKey, std::string& stringValue) const; /** * @brief ShortCut for the above method */ bool Get(const char* propertyKey, std::string& stringValue) const; /** * @brief Convenience method to set the value of a StringProperty */ void SetStringProperty( const char* propertyKey, const char* stringValue); /** * @brief ShortCut for the above method */ void Set( const char* propertyKey, const char* stringValue); + /** + * @brief ShortCut for the above method + */ + void Set( const char* propertyKey, const std::string& stringValue); /** * @brief Get the timestamp of the last change of the map or the last change of one of * the properties store in the list (whichever is later). */ virtual unsigned long GetMTime() const; /** * @brief Remove a property from the list/map. */ bool DeleteProperty(const std::string& propertyKey); const PropertyMap* GetMap() const { return &m_Properties; } bool IsEmpty() const { return m_Properties.empty(); } virtual void Clear(); protected: PropertyList(); PropertyList(const PropertyList& other); virtual ~PropertyList(); /** * @brief Map of properties. */ PropertyMap m_Properties; private: virtual itk::LightObject::Pointer InternalClone() const; }; } // namespace mitk #endif /* PROPERTYLIST_H_HEADER_INCLUDED_C1C77D8D */ diff --git a/Modules/Persistence/Testing/mitkPersistenceTest.cpp b/Modules/Persistence/Testing/mitkPersistenceTest.cpp index ace9971b72..bb36635fa8 100644 --- a/Modules/Persistence/Testing/mitkPersistenceTest.cpp +++ b/Modules/Persistence/Testing/mitkPersistenceTest.cpp @@ -1,65 +1,136 @@ /*=================================================================== 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 "Poco\File.h" // redefine get module context macro #define PERSISTENCE_GET_MODULE_CONTEXT\ us::ModuleContext* context = mitk::PersistenceService::GetModuleContext(); - struct PersistenceTestClass { PersistenceTestClass() : id(""), param1(1), param2(2), param3(false) { } std::string id; int param1; double param2; bool param3; - PERSISTENCE_CREATE_SAVE3(id, param1, param2, param3) - PERSISTENCE_CREATE_LOAD3(id, param1, param2, param3) + PERSISTENCE_CREATE3(id, param1, param2, param3) }; +struct TestPropertyListReplacedObserver: public mitk::PropertyListReplacedObserver +{ + TestPropertyListReplacedObserver(): counter(0) {} + virtual void BeforePropertyListReplaced( const std::string& id, mitk::PropertyList* propertyList ) + { + counter++; + } + + virtual void AfterPropertyListReplaced( const std::string& id, mitk::PropertyList* propertyList ) + { + counter++; + } + + int counter; +}; int mitkPersistenceTest(int /*argc*/, char* /*argv*/[]) { - MITK_TEST_BEGIN("PersistenceTest") + MITK_TEST_BEGIN("PersistenceTest") + Poco::File testTempFile("Test.mitk"); + if( testTempFile.exists() ) + testTempFile.remove(false); PersistenceTestClass testClass; testClass.id = "testClass"; testClass.param1 = 100; testClass.param2 = 200.56; testClass.param3 = true; MITK_TEST_CONDITION_REQUIRED( testClass.Save(), "testClass.Save()"); + MITK_TEST_CONDITION_REQUIRED( testClass.Save(testTempFile.path()), "testClass.Save(testTempFile.path())"); PersistenceTestClass testClass2; testClass2.id = "testClass"; MITK_TEST_CONDITION_REQUIRED( testClass2.Load(), "testClass.Load()"); + MITK_TEST_CONDITION_REQUIRED( testClass.param1 == testClass2.param1, "testClass.param1 == testClass2.param1" ); + MITK_TEST_CONDITION_REQUIRED( testClass.param2 == testClass2.param2, "testClass.param2 == testClass2.param2" ); + MITK_TEST_CONDITION_REQUIRED( testClass.param3 == testClass2.param3, "testClass.param3 == testClass2.param3" ); + PersistenceTestClass testClass3; + testClass3.id = "testClass"; + MITK_TEST_CONDITION_REQUIRED( testClass3.Load(testTempFile.path()), "testClass3.Load(testTempFile.path())"); + + MITK_TEST_CONDITION_REQUIRED( testClass.param1 == testClass3.param1, "testClass.param1 == testClass3.param1" ); + MITK_TEST_CONDITION_REQUIRED( testClass.param2 == testClass3.param2, "testClass.param2 == testClass3.param2" ); + MITK_TEST_CONDITION_REQUIRED( testClass.param3 == testClass3.param3, "testClass.param3 == testClass3.param3" ); + + TestPropertyListReplacedObserver testObserver; + + us::ModuleContext* context = mitk::PersistenceService::GetModuleContext(); + us::ServiceReference persistenceServiceRef = context->GetServiceReference();\ + mitk::IPersistenceService* persistenceService = dynamic_cast ( context->GetService(persistenceServiceRef) ); + persistenceService->AddPropertyListReplacedObserver( &testObserver ); + persistenceService->Load(); + + MITK_TEST_CONDITION_REQUIRED( testObserver.counter == 2, "testObserver.counter == 2" ); + + MITK_DEBUG << "Testing AutoSaveAndLoadFeature"; + if( testTempFile.exists() ) + testTempFile.remove(false); + mitk::IPersistenceService::SetDefaultPersistenceFile(testTempFile.path()); + std::string id = "newPropList"; + + { + itk::SmartPointer newService( new mitk::PersistenceService() ); + newService->UnRegister(); + newService->SetAutoLoadAndSave( true ); + + mitk::PropertyList::Pointer newPropList = newService->GetPropertyList(id); + newPropList->Set("testClass.id", testClass.id.c_str()); + newPropList->Set("testClass.param1", testClass.param1); + newPropList->Set("testClass.param2", testClass.param2); + newPropList->Set("testClass.param3", testClass.param3); + } + + { + itk::SmartPointer newService = itk::SmartPointer( new mitk::PersistenceService() ); + newService->UnRegister(); + mitk::PropertyList::Pointer newPropList = newService->GetPropertyList(id); + newPropList->Get("testClass2.id", testClass2.id); + newPropList->Get("testClass2.param1", testClass2.param1); + newPropList->Get("testClass2.param2", testClass2.param2); + newPropList->Get("testClass2.param3", testClass2.param3); + } + + MITK_TEST_CONDITION_REQUIRED( testClass.id == testClass2.id, "testClass.id == testClass2.id" ); MITK_TEST_CONDITION_REQUIRED( testClass.param1 == testClass2.param1, "testClass.param1 == testClass2.param1" ); MITK_TEST_CONDITION_REQUIRED( testClass.param2 == testClass2.param2, "testClass.param2 == testClass2.param2" ); MITK_TEST_CONDITION_REQUIRED( testClass.param3 == testClass2.param3, "testClass.param3 == testClass2.param3" ); + if( testTempFile.exists() ) + testTempFile.remove(false); + MITK_TEST_END() } diff --git a/Modules/Persistence/mitkIPersistenceService.cpp b/Modules/Persistence/mitkIPersistable.h similarity index 52% copy from Modules/Persistence/mitkIPersistenceService.cpp copy to Modules/Persistence/mitkIPersistable.h index af4f5d697e..e4b4bb483b 100644 --- a/Modules/Persistence/mitkIPersistenceService.cpp +++ b/Modules/Persistence/mitkIPersistable.h @@ -1,21 +1,35 @@ /*=================================================================== 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 mitkIPersistable_h +#define mitkIPersistable_h +#include -#include "mitkIPersistenceService.h" - -mitk::IPersistenceService::~IPersistenceService() +namespace mitk { + /// + /// Just a base class for persistable classes + /// + class Persistence_EXPORT IPersistable + { + public: + virtual bool Save(const std::string& fileName="") = 0; + virtual bool Load(const std::string& fileName="") = 0; + virtual void SetId(const std::string& id) = 0; + virtual std::string GetId() const = 0; + }; } + +#endif diff --git a/Modules/Persistence/mitkIPersistenceService.cpp b/Modules/Persistence/mitkIPersistenceService.cpp index af4f5d697e..a3702551e2 100644 --- a/Modules/Persistence/mitkIPersistenceService.cpp +++ b/Modules/Persistence/mitkIPersistenceService.cpp @@ -1,21 +1,43 @@ /*=================================================================== 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 "mitkIPersistenceService.h" +#include "Poco\Path.h" + + +std::string mitk::IPersistenceService::m_DefaultPersistenceFile(CreateDefaultFileName()); mitk::IPersistenceService::~IPersistenceService() { } + +void mitk::IPersistenceService::SetDefaultPersistenceFile( const std::string& defaultPersistenceFile ) +{ + m_DefaultPersistenceFile = defaultPersistenceFile; + +} + +std::string mitk::IPersistenceService::GetDefaultPersistenceFile() +{ + return m_DefaultPersistenceFile; +} + +std::string mitk::IPersistenceService::CreateDefaultFileName() +{ + std::string homeDir = Poco::Path::home(); + std::string file = /*homeDir +*/ "PersistentData.mitk"; + return file; +} diff --git a/Modules/Persistence/mitkIPersistenceService.h b/Modules/Persistence/mitkIPersistenceService.h index f666f84251..a28f995678 100644 --- a/Modules/Persistence/mitkIPersistenceService.h +++ b/Modules/Persistence/mitkIPersistenceService.h @@ -1,179 +1,187 @@ /*=================================================================== 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 mitkIPersistenceService_h #define mitkIPersistenceService_h // mitk #include "mitkPropertyListReplacedObserver.h" #include "usServiceReference.h" #include "usModuleContext.h" #include "usGetModuleContext.h" //for microservices #include namespace mitk { /// /// The central service for the persistence module /// Basic idea is to create PropertyLists with a unique id using AddPropertyList(). A consumer /// of this interface can write arbitrary information into this propertylist /// Calling Save() and Load() will cause the Service to save and load the current set of propertlists from /// a file in the user directory. /// Using SetAutoLoadAndSave(true) will cause the service to load/save the property lists at application /// start/stop. /// Moreover, depending on the backend type, the service is connected to the SceneSerialization module, i.e. /// the user will be asked whether to save/load the propertlists in/from the current ".mitk" file that is selected /// by the user. /// class Persistence_EXPORT IPersistenceService { public: + /// + /// Set a default directory for storage + /// + static std::string CreateDefaultFileName(); + /// + /// Get the default directory for storage + /// + static void SetDefaultPersistenceFile(const std::string& defaultPersistenceFile); + /// + /// Set a default directory for storage + /// + static std::string GetDefaultPersistenceFile(); /// /// If PropertyList with the given id exists, returns it. Otherwise creates a new one and returns it. /// If id is empty a UUID will be created and set on the variable /// If existed was passed, it is true if the PropertyList with that id existed, false otherwise /// \return a valid PropertyList with a StringProperty "Id" containing the passed id /// virtual mitk::PropertyList::Pointer GetPropertyList( std::string& id, bool* existed=0 ) = 0; /// /// Save the current PropertyLists to fileName. If fileName is empty, a special file in the users home directory will be used. + /// if appendchanges is true, the file will not replaced but first loaded, then overwritten and then replaced /// \return false if an error occured (cannot write to file), true otherwise /// - virtual bool Save(const std::string& fileName="") = 0; + virtual bool Save(const std::string& fileName="", bool appendChanges=false) = 0; /// /// Load PropertyLists from fileName. If fileName is empty, a special file in the users home directory will be used. /// *ATTENTION*: If there are PropertyLists with the same id contained in the file, existing PropertyLists will be overwritten! /// \see AddPropertyListReplacedObserver() /// \return false if an error occured (cannot load from file), true otherwise /// virtual bool Load(const std::string& fileName="") = 0; /// /// Using SetAutoLoadAndSave(true) will cause the service to load/save the property lists at application /// start/stop. /// virtual void SetAutoLoadAndSave(bool autoLoadAndSave) = 0; /// /// adds a observer which is informed if a propertyList gets replaced during a Load() procedure /// virtual void AddPropertyListReplacedObserver( PropertyListReplacedObserver* observer ) = 0; /// /// removes a specific observer /// virtual void RemovePropertyListReplacedObserver( PropertyListReplacedObserver* observer ) = 0; /// /// nothing to do here /// virtual ~IPersistenceService(); + private: + static std::string m_DefaultPersistenceFile; }; } /// MACROS FOR AUTOMATIC SAVE FUNCTION #define PERSISTENCE_GET_MODULE_CONTEXT\ us::ModuleContext* context = GetModuleContext(); #define PERSISTENCE_GET_SERVICE\ PERSISTENCE_GET_MODULE_CONTEXT\ us::ServiceReference persistenceServiceRef = context->GetServiceReference();\ mitk::IPersistenceService* persistenceService = dynamic_cast ( context->GetService(persistenceServiceRef) ); #define PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ -bool Save() { \ +bool Save(const std::string& fileName="") { \ PERSISTENCE_GET_SERVICE\ bool noError = persistenceService != 0;\ mitk::PropertyList::Pointer propList;\ if( noError ) {\ propList = persistenceService->GetPropertyList(IdMemberName); #define PERSISTENCE_CREATE_SAVE_END\ }\ - noError = persistenceService->Save();\ + noError = persistenceService->Save(fileName);\ return noError;\ } -#define PERSISTENCE_CREATE_SAVE(IdMemberName, ParamMemberName)\ - PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ - propList->Set( #ParamMemberName, ParamMemberName );\ - PERSISTENCE_CREATE_SAVE_END - -#define PERSISTENCE_CREATE_SAVE2(IdMemberName, ParamMemberName, Param2MemberName)\ - PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ - propList->Set( #ParamMemberName, ParamMemberName );\ - propList->Set( #Param2MemberName, Param2MemberName );\ - PERSISTENCE_CREATE_SAVE_END - -#define PERSISTENCE_CREATE_SAVE3(IdMemberName, ParamMemberName, Param2MemberName, Param3MemberName)\ - PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ - propList->Set( #ParamMemberName, ParamMemberName );\ - propList->Set( #Param2MemberName, Param2MemberName );\ - propList->Set( #Param3MemberName, Param3MemberName );\ - PERSISTENCE_CREATE_SAVE_END - -#define PERSISTENCE_CREATE_SAVE4(IdMemberName, ParamMemberName, Param2MemberName, Param3MemberName, Param4MemberName)\ - PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ - propList->Set( #ParamMemberName, ParamMemberName );\ - propList->Set( #Param2MemberName, Param2MemberName );\ - propList->Set( #Param3MemberName, Param3MemberName );\ - propList->Set( #Param4MemberName, Param4MemberName );\ - PERSISTENCE_CREATE_SAVE_END - -/// MACROS FOR AUTOMATIC LOAD FUNCTION #define PERSISTENCE_CREATE_LOAD_START(IdMemberName)\ -bool Load() {\ +void SetId( const std::string& ____id ) { IdMemberName = ____id; };\ +std::string GetId() { return IdMemberName; };\ +bool Load(const std::string& fileName="") {\ PERSISTENCE_GET_SERVICE\ - bool noError = persistenceService != 0 && persistenceService->Load();\ + bool noError = persistenceService != 0 && persistenceService->Load(fileName);\ if( noError ) {\ - mitk::PropertyList::Pointer propList = persistenceService->GetPropertyList(IdMemberName); + mitk::PropertyList::Pointer propList = persistenceService->GetPropertyList(IdMemberName); #define PERSISTENCE_CREATE_LOAD_END\ }\ - return noError;\ + return noError;\ } -#define PERSISTENCE_CREATE_LOAD(IdMemberName, ParamMemberName)\ +#define PERSISTENCE_CREATE(IdMemberName, ParamMemberName)\ + PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ + propList->Set( #ParamMemberName, ParamMemberName );\ + PERSISTENCE_CREATE_SAVE_END\ PERSISTENCE_CREATE_LOAD_START(IdMemberName)\ noError = propList->Get( #ParamMemberName, ParamMemberName );\ PERSISTENCE_CREATE_LOAD_END -#define PERSISTENCE_CREATE_LOAD2(IdMemberName, ParamMemberName, Param2MemberName)\ +#define PERSISTENCE_CREATE2(IdMemberName, ParamMemberName, Param2MemberName)\ + PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ + propList->Set( #ParamMemberName, ParamMemberName );\ + propList->Set( #Param2MemberName, Param2MemberName );\ + PERSISTENCE_CREATE_SAVE_END\ PERSISTENCE_CREATE_LOAD_START(IdMemberName)\ noError = propList->Get( #ParamMemberName, ParamMemberName );\ if(noError)\ - noError = propList->Get( #Param2MemberName, Param2MemberName );\ + noError = propList->Get( #Param2MemberName, Param2MemberName );\ PERSISTENCE_CREATE_LOAD_END -#define PERSISTENCE_CREATE_LOAD3(IdMemberName, ParamMemberName, Param2MemberName, Param3MemberName)\ +#define PERSISTENCE_CREATE3(IdMemberName, ParamMemberName, Param2MemberName, Param3MemberName)\ + PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ + propList->Set( #ParamMemberName, ParamMemberName );\ + propList->Set( #Param2MemberName, Param2MemberName );\ + propList->Set( #Param3MemberName, Param3MemberName );\ + PERSISTENCE_CREATE_SAVE_END\ PERSISTENCE_CREATE_LOAD_START(IdMemberName)\ noError = propList->Get( #ParamMemberName, ParamMemberName );\ if(noError)\ - noError = propList->Get( #Param2MemberName, Param2MemberName );\ + noError = propList->Get( #Param2MemberName, Param2MemberName );\ if(noError)\ - noError = propList->Get( #Param3MemberName, Param3MemberName );\ + noError = propList->Get( #Param3MemberName, Param3MemberName );\ PERSISTENCE_CREATE_LOAD_END -#define PERSISTENCE_CREATE_LOAD4(IdMemberName, ParamMemberName, Param2MemberName, Param3MemberName, Param4MemberName)\ +#define PERSISTENCE_CREATE4(IdMemberName, ParamMemberName, Param2MemberName, Param3MemberName, Param4MemberName)\ + PERSISTENCE_CREATE_SAVE_START(IdMemberName)\ + propList->Set( #ParamMemberName, ParamMemberName );\ + propList->Set( #Param2MemberName, Param2MemberName );\ + propList->Set( #Param3MemberName, Param3MemberName );\ + propList->Set( #Param4MemberName, Param4MemberName );\ + PERSISTENCE_CREATE_SAVE_END\ PERSISTENCE_CREATE_LOAD_START(IdMemberName)\ noError = propList->Get( #ParamMemberName, ParamMemberName );\ if(noError)\ - noError = propList->Get( #Param2MemberName, Param2MemberName );\ + noError = propList->Get( #Param2MemberName, Param2MemberName );\ if(noError)\ - noError = propList->Get( #Param3MemberName, Param3MemberName );\ + noError = propList->Get( #Param3MemberName, Param3MemberName );\ if(noError)\ - noError = propList->Get( #Param4MemberName, Param4MemberName );\ + noError = propList->Get( #Param4MemberName, Param4MemberName );\ PERSISTENCE_CREATE_LOAD_END US_DECLARE_SERVICE_INTERFACE(mitk::IPersistenceService, "org.mitk.services.IPersistenceService") #endif diff --git a/Modules/Persistence/mitkPersistenceService.cpp b/Modules/Persistence/mitkPersistenceService.cpp index ad0fd4e1a8..8109debba4 100644 --- a/Modules/Persistence/mitkPersistenceService.cpp +++ b/Modules/Persistence/mitkPersistenceService.cpp @@ -1,226 +1,247 @@ /*=================================================================== 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 "mitkPersistenceService.h" #include "mitkStandaloneDataStorage.h" #include "mitkUIDGenerator.h" #include "mitkNodePredicateProperty.h" #include "mitkProperties.h" #include "usModuleContext.h" #include "usGetModuleContext.h" -#include +#include "Poco\File.h" -std::string mitk::PersistenceService::CreateDefaultFileName() -{ - std::string homeDir = Poco::Path::home(); - std::string file = homeDir + "PersistenceService.mitk"; - return file; -} - -const std::string mitk::PersistenceService::DEFAULT_FILE_NAME(CreateDefaultFileName()); const std::string mitk::PersistenceService::PERSISTENCE_PROPERTY_NAME("PersistenceNode"); const std::string mitk::PersistenceService::PERSISTENCE_PROPERTYLIST_NAME("PersistenceService"); const std::string mitk::PersistenceService::ID_PROPERTY_NAME("Id"); mitk::PersistenceService::PersistenceService() : m_AutoLoadAndSave( false ), m_SceneIO( SceneIO::New() ) { { MITK_DEBUG("mitk::PersistenceService") << "constructing PersistenceService"; } MITK_DEBUG("mitk::PersistenceService") << "loading PersistenceService personal persitent data"; - this->Load( DEFAULT_FILE_NAME ); + this->Load( IPersistenceService::GetDefaultPersistenceFile() ); std::string id = PERSISTENCE_PROPERTYLIST_NAME; mitk::PropertyList::Pointer propList = this->GetPropertyList( id ); propList->GetBoolProperty("m_AutoLoadAndSave", m_AutoLoadAndSave); if( m_AutoLoadAndSave == false ) { MITK_DEBUG("mitk::PersistenceService") << "autoloading was not wished. clearing data we got so far."; m_PropertyLists.clear(); } } mitk::PersistenceService::~PersistenceService() { MITK_DEBUG("mitk::PersistenceService") << "destructing PersistenceService"; + if(m_AutoLoadAndSave) + this->Save(); } mitk::PropertyList::Pointer mitk::PersistenceService::GetPropertyList( std::string& id, bool* existed ) { mitk::PropertyList::Pointer propList; if( id.empty() ) { UIDGenerator uidGen; id = uidGen.GetUID(); } std::map::iterator it = m_PropertyLists.find( id ); if( it == m_PropertyLists.end() ) { propList = PropertyList::New(); m_PropertyLists[id] = propList; if( existed ) *existed = false; } else { propList = (*it).second; if( existed ) *existed = true; } return propList; } void mitk::PersistenceService::ClonePropertyList( mitk::PropertyList* from, mitk::PropertyList* to ) { to->Clear(); const std::map< std::string, BaseProperty::Pointer>* propMap = from->GetMap(); std::map< std::string, BaseProperty::Pointer>::const_iterator propMapIt = propMap->begin(); while( propMapIt != propMap->end() ) { mitk::BaseProperty::Pointer clonedProp = (*propMapIt).second->Clone(); to->SetProperty( (*propMapIt).first, clonedProp ); ++propMapIt; } } -bool mitk::PersistenceService::Save(const std::string& fileName) +bool mitk::PersistenceService::Save(const std::string& fileName, bool appendChanges) { bool save = false; - mitk::StandaloneDataStorage::Pointer tempDs = mitk::StandaloneDataStorage::New(); + std::string theFile = fileName; + if(theFile.empty()) + theFile = IPersistenceService::GetDefaultPersistenceFile(); + + mitk::DataStorage::Pointer tempDs; + if(appendChanges) + { + if( !Poco::File(theFile).exists() ) + return false; + DataStorage::Pointer ds = m_SceneIO->LoadScene( theFile ); + bool load = (m_SceneIO->GetFailedNodes() == 0 || m_SceneIO->GetFailedNodes()->size() == 0) && (m_SceneIO->GetFailedNodes() == 0 || m_SceneIO->GetFailedProperties()->IsEmpty()); + if( !load ) + return false; + + tempDs = ds; + } + else + tempDs = mitk::StandaloneDataStorage::New(); std::map::iterator it = m_PropertyLists.begin(); while( it != m_PropertyLists.end() ) { - mitk::DataNode::Pointer newNode = mitk::DataNode::New(); + mitk::DataNode::Pointer node; + const std::string& name = (*it).first; + if( appendChanges ) + { + mitk::NodePredicateProperty::Pointer namePred = + mitk::NodePredicateProperty::New("name", mitk::StringProperty::New(name)); + node = tempDs->GetNode(namePred); + } + if(node.IsNull()) + { + node = mitk::DataNode::New(); + tempDs->Add(node); + } - this->ClonePropertyList( (*it).second, newNode->GetPropertyList() ); + this->ClonePropertyList( (*it).second, node->GetPropertyList() ); - newNode->SetBoolProperty( PERSISTENCE_PROPERTY_NAME.c_str(), true ); - newNode->SetName( (*it).first ); - newNode->SetStringProperty(ID_PROPERTY_NAME.c_str(),(*it).first.c_str() ); + node->SetBoolProperty( PERSISTENCE_PROPERTY_NAME.c_str(), true ); + node->SetName( name ); + node->SetStringProperty(ID_PROPERTY_NAME.c_str(),name.c_str() ); - tempDs->Add(newNode); ++it; } mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New(PERSISTENCE_PROPERTY_NAME.c_str(), mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer rs = tempDs->GetSubset(pred); - std::string theFile = fileName; - if(theFile.empty()) - theFile = DEFAULT_FILE_NAME; return m_SceneIO->SaveScene( rs, tempDs, theFile ); } bool mitk::PersistenceService::Load(const std::string& fileName) { bool load = false; std::string theFile = fileName; if(theFile.empty()) - theFile = DEFAULT_FILE_NAME; + theFile = IPersistenceService::GetDefaultPersistenceFile(); + if( !Poco::File(theFile).exists() ) + return false; DataStorage::Pointer ds = m_SceneIO->LoadScene( theFile ); load = (m_SceneIO->GetFailedNodes() == 0 || m_SceneIO->GetFailedNodes()->size() == 0) && (m_SceneIO->GetFailedNodes() == 0 || m_SceneIO->GetFailedProperties()->IsEmpty()); if( !load ) { MITK_DEBUG("mitk::PersistenceService") << "loading of scene files failed"; return load; } DataStorage::SetOfObjects::ConstPointer allNodes = ds->GetAll(); for ( mitk::DataStorage::SetOfObjects::const_iterator sourceIter = allNodes->begin(); sourceIter != allNodes->end(); ++sourceIter ) { mitk::DataNode* node = *sourceIter; bool isPersistenceNode = false; node->GetBoolProperty( PERSISTENCE_PROPERTY_NAME.c_str(), isPersistenceNode ); if( isPersistenceNode ) { MITK_DEBUG("mitk::PersistenceService") << "isPersistenceNode was true"; std::string name = node->GetName(); bool existed = false; mitk::PropertyList::Pointer propList = this->GetPropertyList( name, &existed ); if( existed ) { MITK_DEBUG("mitk::PersistenceService") << "calling replace observer before replacing values"; std::set::iterator it = m_PropertyListReplacedObserver.begin(); while( it != m_PropertyListReplacedObserver.end() ) { (*it)->BeforePropertyListReplaced( name, propList ); ++it; } } // if( existed ) MITK_DEBUG("mitk::PersistenceService") << "replacing values"; this->ClonePropertyList( node->GetPropertyList(), propList ); propList->SetStringProperty(ID_PROPERTY_NAME.c_str(), name.c_str()); if( existed ) { MITK_DEBUG("mitk::PersistenceService") << "calling replace observer before replacing values"; std::set::iterator it = m_PropertyListReplacedObserver.begin(); while( it != m_PropertyListReplacedObserver.end() ) { (*it)->AfterPropertyListReplaced( name, propList ); ++it; } } // if( existed ) } // if( isPersistenceNode ) } // for ( mitk::DataStorage::SetOfObjects::const_iterator sourceIter = allNodes->begin(); ... return load; } void mitk::PersistenceService::SetAutoLoadAndSave(bool autoLoadAndSave) { m_AutoLoadAndSave = autoLoadAndSave; std::string id = PERSISTENCE_PROPERTYLIST_NAME; mitk::PropertyList::Pointer propList = this->GetPropertyList( id ); propList->Set("m_AutoLoadAndSave", m_AutoLoadAndSave); this->Save(); } void mitk::PersistenceService::AddPropertyListReplacedObserver(PropertyListReplacedObserver* observer) { m_PropertyListReplacedObserver.insert( observer ); } void mitk::PersistenceService::RemovePropertyListReplacedObserver(PropertyListReplacedObserver* observer) { m_PropertyListReplacedObserver.erase( observer ); } us::ModuleContext* mitk::PersistenceService::GetModuleContext() { return us::GetModuleContext(); } diff --git a/Modules/Persistence/mitkPersistenceService.h b/Modules/Persistence/mitkPersistenceService.h index cad2c3eac6..23a11be77c 100644 --- a/Modules/Persistence/mitkPersistenceService.h +++ b/Modules/Persistence/mitkPersistenceService.h @@ -1,61 +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 mitkPersistenceService_h #define mitkPersistenceService_h #include "mitkIPersistenceService.h" #include #include "mitkSceneIO.h" namespace mitk { /// /// implementation of the IPersistenceService /// \see IPersistenceService class Persistence_EXPORT PersistenceService: public itk::LightObject, public mitk::IPersistenceService { public: - static std::string CreateDefaultFileName(); - static const std::string DEFAULT_FILE_NAME; static const std::string PERSISTENCE_PROPERTY_NAME; static const std::string PERSISTENCE_PROPERTYLIST_NAME; static const std::string ID_PROPERTY_NAME; static us::ModuleContext* GetModuleContext(); PersistenceService(); ~PersistenceService(); mitk::PropertyList::Pointer GetPropertyList( std::string& id, bool* existed=0 ); - bool Save(const std::string& fileName=""); + bool Save(const std::string& fileName="", bool appendChanges=false); bool Load(const std::string& fileName=""); void SetAutoLoadAndSave(bool autoLoadAndSave); void AddPropertyListReplacedObserver( PropertyListReplacedObserver* observer ); void RemovePropertyListReplacedObserver( PropertyListReplacedObserver* observer ); private: void ClonePropertyList( mitk::PropertyList* from, mitk::PropertyList* to ); std::map m_PropertyLists; bool m_AutoLoadAndSave; std::set m_PropertyListReplacedObserver; SceneIO::Pointer m_SceneIO; }; } #endif