diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt index d3f5be1d5c..899b897d91 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt @@ -29,6 +29,9 @@ set( PROJECT_FILES cafPdmPointer.cpp cafPdmPointer.h cafPdmProxyValueField.h + cafPdmPtrArrayField.h + cafPdmPtrArrayField.inl + cafPdmPtrArrayFieldHandle.h cafPdmPtrField.h cafPdmPtrField.inl cafPdmReferenceHelper.cpp diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h index 043206a5ff..100cfcf48f 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h @@ -4,6 +4,8 @@ #include "cafPdmPointer.h" #include +#include "cafPdmPtrArrayFieldHandle.h" + namespace caf { @@ -14,21 +16,14 @@ template class PdmFieldXmlCap; /// /// //================================================================================================== -class PdmChildArrayFieldHandle : public PdmFieldHandle +class PdmChildArrayFieldHandle : public PdmPtrArrayFieldHandle { public: PdmChildArrayFieldHandle() {} virtual ~PdmChildArrayFieldHandle() {} - virtual size_t size() const = 0; - virtual bool empty() const = 0; - virtual void clear() = 0; - virtual void insertAt(int indexAfter, PdmObjectHandle* obj) = 0; - virtual void erase(size_t index) = 0; virtual void deleteAllChildObjects() = 0; - virtual PdmObjectHandle* at(size_t index) = 0; - bool hasSameFieldCountForAllObjects(); }; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h index 1536ba1c80..31c6412634 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h @@ -84,6 +84,7 @@ private: // Give access to set/removeAsParentField template < class T > friend class PdmChildArrayField; template < class T > friend class PdmChildField; + template < class T > friend class PdmPtrArrayField; template < class T > friend class PdmPtrField; template < class T > friend class PdmField; // For backwards compatibility layer diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayField.h new file mode 100644 index 0000000000..f376f333ae --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayField.h @@ -0,0 +1,93 @@ +#pragma once + +#include "cafPdmFieldHandle.h" +#include "cafPdmPointer.h" +#include + +#include "cafPdmPtrArrayFieldHandle.h" +namespace caf +{ + +template class PdmFieldXmlCap; + + +//================================================================================================== +/// PdmFieldClass to handle a collection of PdmObject derived pointers +/// The reasons for this class is to add itself as parentField into the objects being pointed to. +/// The interface is made similar to std::vector<>, and the complexity of the methods is similar too. +//================================================================================================== + +template +class PdmPtrArrayField : public PdmFieldHandle +{ +public: + PdmPtrArrayField() + { + bool doNotUsePdmPtrArrayFieldForAnythingButPointersToPdmObject = false; assert(doNotUsePdmPtrArrayFieldForAnythingButPointersToPdmObject); + } +}; + + +template +class PdmPtrArrayField : public PdmPtrArrayFieldHandle +{ + typedef DataType* DataTypePtr; +public: + typedef std::vector< PdmPointer > FieldDataType; + + PdmPtrArrayField() : m_isResolved(false) { } + virtual ~PdmPtrArrayField(); + + PdmPtrArrayField& operator() () { return *this; } + + void setValue(const std::vector< PdmPointer >& fieldValue); + const std::vector< PdmPointer >& value() const; + + // Reimplementation of PdmPointersFieldHandle methods + + virtual size_t size() const { return m_pointers.size(); } + virtual bool empty() const { return m_pointers.empty(); } + virtual void clear(); + virtual void insertAt(int indexAfter, PdmObjectHandle* obj); + virtual PdmObjectHandle* at(size_t index); + + // std::vector-like access + + DataType* operator[] (size_t index) const; + + void push_back(DataType* pointer); + void set(size_t index, DataType* pointer); + void insert(size_t indexAfter, DataType* pointer); + void insert(size_t indexAfter, const std::vector >& objects); + size_t count(const DataType* pointer) const; + + void erase(size_t index); + size_t index(DataType* pointer); + void removePtr(PdmObjectHandle* object); + + typename std::vector< PdmPointer >::iterator begin() { return m_pointers.begin(); }; + typename std::vector< PdmPointer >::iterator end() { return m_pointers.end(); }; + + typename std::vector< PdmPointer >::const_iterator begin() const { return m_pointers.begin(); }; + typename std::vector< PdmPointer >::const_iterator end() const { return m_pointers.end(); }; + + // Child objects + virtual void ptrReferencedObjects(std::vector*); + +private: //To be disabled + PDM_DISABLE_COPY_AND_ASSIGN(PdmPtrArrayField); + + void addThisAsReferencingPtrField(); + void removeThisAsReferencingPtrField(); + +private: + friend class PdmFieldXmlCap< PdmPtrArrayField >; + + std::vector< PdmPointer > m_pointers; + QString m_referenceString; + bool m_isResolved; +}; + +} // End of namespace caf + +#include "cafPdmPtrArrayField.inl" diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayField.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayField.inl new file mode 100644 index 0000000000..ab7d9d7ada --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayField.inl @@ -0,0 +1,298 @@ +#pragma once + +#include "cafClassTypeName.h" +#include "cafPdmObjectHandle.h" + +namespace caf +{ + +//================================================================================================== +/// Implementation of PdmPtrArrayField<> +//================================================================================================== + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +PdmPtrArrayField::~PdmPtrArrayField() +{ + this->removeThisAsReferencingPtrField(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::setValue(const std::vector< PdmPointer >& fieldValue) +{ + this->clear(); + this->insert(0, fieldValue); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +const std::vector< PdmPointer >& PdmPtrArrayField::value() const +{ + return m_pointers; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +DataType* PdmPtrArrayField::operator[](size_t index) const +{ + return m_pointers[index]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::push_back(DataType* pointer) +{ + assert(isInitializedByInitFieldMacro()); + + m_pointers.push_back(pointer); + if(pointer) pointer->addReferencingPtrField(this); +} + +//-------------------------------------------------------------------------------------------------- +/// Set the value at position index to pointer, overwriting any pointer already present at that +/// position without deleting the object pointed to. +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::set(size_t index, DataType* pointer) +{ + assert(isInitializedByInitFieldMacro()); + + if(m_pointers[index]) m_pointers[index]->removeReferencingPtrField(this); + m_pointers[index] = pointer; + if(m_pointers[index]) pointer->addReferencingPtrField(this); +} + +//-------------------------------------------------------------------------------------------------- +/// Insert pointer at position index, pushing the value previously at that position and all +/// the preceding values backwards +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::insert(size_t index, DataType* pointer) +{ + assert(isInitializedByInitFieldMacro()); + + m_pointers.insert(m_pointers.begin()+index, pointer); + + if(pointer) pointer->addReferencingPtrField(this); +} + + +//-------------------------------------------------------------------------------------------------- +/// Insert the pointers at position index, pushing the value previously at that position and all +/// the preceding values backwards +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::insert(size_t index, const std::vector >& objects) +{ + assert(isInitializedByInitFieldMacro()); + + m_pointers.insert(m_pointers.begin()+index, objects.begin(), objects.end()); + + typename std::vector< PdmPointer< DataType > >::iterator it; + for(it = m_pointers.begin()+index; it != m_pointers.end(); ++it) + { + if(!it->isNull()) + { + (*it)->addReferencingPtrField(this); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// Returns the number of times pointer is referenced from the container. +//-------------------------------------------------------------------------------------------------- +template +size_t PdmPtrArrayField::count(const DataType* pointer) const +{ + size_t itemCount = 0; + + typename std::vector< PdmPointer< DataType > >::const_iterator it; + for(it = m_pointers.begin(); it != m_pointers.end(); ++it) + { + if(*it == pointer) + { + itemCount++; + } + } + + return itemCount; +} + +//-------------------------------------------------------------------------------------------------- +/// Empty the container without deleting the objects pointed to. +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::clear() +{ + assert(isInitializedByInitFieldMacro()); + + this->removeThisAsReferencingPtrField(); + m_pointers.clear(); +} + + +//-------------------------------------------------------------------------------------------------- +/// Removes the pointer at index from the container. Does not delete the object pointed to. +/// Todo: This implementation can't be necessary in the new regime. Should be to just remove +/// the item at index (shrinking the array) +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::erase(size_t index) +{ + assert(isInitializedByInitFieldMacro()); + + if(m_pointers[index].rawPtr()) + { + m_pointers[index].rawPtr()->removeReferencingPtrField(this); + } + + m_pointers.erase(m_pointers.begin() + index); +} + + +//-------------------------------------------------------------------------------------------------- +/// Get the index of the given object pointer +//-------------------------------------------------------------------------------------------------- +template +size_t PdmPtrArrayField::index(DataType* pointer) +{ + for(size_t i = 0; i < m_pointers.size(); ++i) + { + if(pointer == m_pointers[i].p()) + { + return i; + } + } + + return (size_t)(-1); // Undefined size_t > m_pointers.size(); +} + + +//-------------------------------------------------------------------------------------------------- +/// Removes all instances of object pointer from the container without deleting the object. +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::removePtr(PdmObjectHandle* object) +{ + assert(isInitializedByInitFieldMacro()); + + std::vector< PdmPointer > tempPointers; + + tempPointers = m_pointers; + m_pointers.clear(); + + for(size_t index = 0; index < tempPointers.size(); ++index) + { + if(tempPointers[index].rawPtr() != object) + { + m_pointers.push_back(tempPointers[index]); + } + else + { + if(tempPointers[index].rawPtr()) + { + tempPointers[index].rawPtr()->removeReferencingPtrField(this); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::ptrReferencedObjects(std::vector* objects) +{ + if(!objects) return; + size_t i; + for(i = 0; i < m_pointers.size(); ++i) + { + objects->push_back(m_pointers[i].rawPtr()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::insertAt(int indexAfter, PdmObjectHandle* obj) +{ + assert(isInitializedByInitFieldMacro()); + + // This method should assert if obj to insert is not castable to the container type, but since this + // is a virtual method, its implementation is always created and that makes a dyn_cast add the need for + // #include of the header file "everywhere" + typename std::vector< PdmPointer >::iterator it; + + if(indexAfter == -1) + { + m_pointers.push_back(PdmPointer()); + it = m_pointers.end() - 1; + } + else + { + m_pointers.insert(m_pointers.begin() + indexAfter, PdmPointer()); + it = m_pointers.begin() + indexAfter; + } + + it->setRawPtr(obj); + obj->addReferencingPtrField(this); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +PdmObjectHandle* PdmPtrArrayField::at(size_t index) +{ + return m_pointers[index].rawPtr(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::removeThisAsReferencingPtrField() +{ + typename std::vector< PdmPointer< DataType > >::iterator it; + for(it = m_pointers.begin(); it != m_pointers.end(); ++it) + { + if(!it->isNull()) + { + it->rawPtr()->removeReferencingPtrField(this); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void PdmPtrArrayField::addThisAsReferencingPtrField() +{ + typename std::vector< PdmPointer< DataType > >::iterator it; + for(it = m_pointers.begin(); it != m_pointers.end(); ++it) + { + if(!it->isNull()) + { + (*it)->addReferencingPtrField(this); + } + } +} + +} //End of namespace caf + + + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayFieldHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayFieldHandle.h new file mode 100644 index 0000000000..574d0d61bc --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrArrayFieldHandle.h @@ -0,0 +1,29 @@ +#pragma once + +#include "cafPdmFieldHandle.h" + +namespace caf +{ + +//================================================================================================== +/// +/// +/// +//================================================================================================== +class PdmPtrArrayFieldHandle : public PdmFieldHandle +{ +public: + PdmPtrArrayFieldHandle() {} + virtual ~PdmPtrArrayFieldHandle() {} + + virtual size_t size() const = 0; + virtual bool empty() const = 0; + virtual void clear() = 0; + virtual void insertAt(int indexAfter, PdmObjectHandle* obj) = 0; + virtual void erase(size_t index) = 0; + + virtual PdmObjectHandle* at(size_t index) = 0; + +}; + +} \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h index f14cd1914b..420b115320 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h @@ -50,6 +50,34 @@ private: bool m_isResolved; }; +template class PdmPtrArrayField; + +template < typename DataType> +class PdmFieldXmlCap< PdmPtrArrayField >: public PdmXmlFieldHandle +{ + typedef PdmPtrArrayField FieldType; +public: + PdmFieldXmlCap(FieldType* field, bool giveOwnership) : PdmXmlFieldHandle(field, giveOwnership) + { + m_field = field; + m_childClassKeyword = DataType::classKeywordStatic(); + m_isResolved = false; + m_referenceString = ""; + } + + // Xml Serializing +public: + virtual void readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory* objectFactory); + virtual void writeFieldData(QXmlStreamWriter& xmlStream); + virtual void resolveReferences(); + +private: + FieldType* m_field; + + // Resolving + QString m_referenceString; + bool m_isResolved; +}; template class PdmChildField; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl index 5842df0414..b2c6135233 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl @@ -103,6 +103,78 @@ template m_isResolved = true; } + //================================================================================================== +/// XML Implementation for PdmPtrArrayField<> +//================================================================================================== + + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + + template + void caf::PdmFieldXmlCap< caf::PdmPtrArrayField >::readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory*) + { + this->assertValid(); + + PdmFieldIOHelper::skipComments(xmlStream); + if(!xmlStream.isCharacters()) return; + + QString dataString = xmlStream.text().toString(); + + // Make stream point to end of element + QXmlStreamReader::TokenType type; + type = xmlStream.readNext(); + PdmFieldIOHelper::skipCharactersAndComments(xmlStream); + + // This resolving can NOT be done here. + // It must be done when we know that the complete hierarchy is read and created, + // and then we need a traversal of the object hierarchy to resolve all references before initAfterRead. + + m_isResolved = false; + m_referenceString = dataString; + m_field->clear(); + } + + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + + template + void caf::PdmFieldXmlCap< caf::PdmPtrArrayField >::writeFieldData(QXmlStreamWriter& xmlStream) + { + this->assertValid(); + + QString dataString; + size_t pointerCount = m_field->m_pointers.size(); + for (size_t i = 0; i < pointerCount; ++i) + { + dataString += PdmReferenceHelper::referenceFromFieldToObject(m_field, m_field->m_pointers[i].rawPtr()); + if (i < pointerCount-1) dataString += "|\n"; + } + xmlStream.writeCharacters(dataString); + } + + + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + template < typename DataType> + void caf::PdmFieldXmlCap< PdmPtrArrayField >::resolveReferences() + { + if(m_isResolved) return; + if(m_referenceString.isEmpty()) return; + m_field->clear(); + QStringList tokens = m_referenceString.split('|'); + for(int i = 0; i < tokens.size(); ++i) + { + PdmObjectHandle* objHandle = PdmReferenceHelper::objectFromFieldReference(this->fieldHandle(), tokens[i]); + m_field->m_pointers.push_back(NULL); + m_field->m_pointers.back().setRawPtr(objHandle); + } + + m_isResolved = true; + } + //================================================================================================== /// XML Implementation for PdmChildField<>