diff --git a/src/App/Application.cpp b/src/App/Application.cpp index d41c47c18a..871d0b1cb4 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -423,7 +423,7 @@ Document* Application::newDocument(const char * Name, const char * UserName) } // create the FreeCAD document - std::unique_ptr newDoc(new Document()); + std::unique_ptr newDoc(new Document(name.c_str())); // add the document to the internal list DocMap[name] = newDoc.release(); // now owned by the Application @@ -448,6 +448,8 @@ Document* Application::newDocument(const char * Name, const char * UserName) _pActiveDoc->signalAbortTransaction.connect(boost::bind(&App::Application::slotAbortTransaction, this, _1)); _pActiveDoc->signalStartSave.connect(boost::bind(&App::Application::slotStartSaveDocument, this, _1, _2)); _pActiveDoc->signalFinishSave.connect(boost::bind(&App::Application::slotFinishSaveDocument, this, _1, _2)); + _pActiveDoc->signalChangePropertyEditor.connect( + boost::bind(&App::Application::slotChangePropertyEditor, this, _1, _2)); // make sure that the active document is set in case no GUI is up { @@ -1131,6 +1133,11 @@ void Application::slotFinishSaveDocument(const App::Document& doc, const std::st this->signalFinishSaveDocument(doc, filename); } +void Application::slotChangePropertyEditor(const App::Document &doc, const App::Property &prop) +{ + this->signalChangePropertyEditor(doc,prop); +} + //************************************************************************** // Init, Destruct and singleton @@ -1410,6 +1417,7 @@ void Application::initTypes(void) App ::PropertyIntegerSet ::init(); App ::PropertyMap ::init(); App ::PropertyString ::init(); + App ::PropertyPersistentObject ::init(); App ::PropertyUUID ::init(); App ::PropertyFont ::init(); App ::PropertyStringList ::init(); diff --git a/src/App/Application.h b/src/App/Application.h index d7191dcbdc..b38e0daa7e 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -184,7 +184,7 @@ public: /// signal on about removing a dynamic property boost::signals2::signal signalRemoveDynamicProperty; /// signal on about changing the editor mode of a property - boost::signals2::signal signalChangePropertyEditor; + boost::signals2::signal signalChangePropertyEditor; //@} @@ -342,6 +342,7 @@ protected: void slotAbortTransaction(const App::Document&); void slotStartSaveDocument(const App::Document&, const std::string&); void slotFinishSaveDocument(const App::Document&, const std::string&); + void slotChangePropertyEditor(const App::Document&, const App::Property &); //@} private: diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 48c96ecf34..134201f731 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -940,15 +940,20 @@ bool Document::redo(void) return false; } -void Document::removePropertyOfObject(TransactionalObject* obj, const char* name) +void Document::addOrRemovePropertyOfObject(TransactionalObject* obj, Property *prop, bool add) { - Property* prop = obj->getDynamicPropertyByName(name); - if (prop) { - if (d->activeUndoTransaction) - d->activeUndoTransaction->removeProperty(obj, prop); - for (auto it : mUndoTransactions) - it->removeProperty(obj, prop); + if (!prop || !obj) + return; + if(d->iUndoMode && !isPerformingTransaction() && !d->activeUndoTransaction) { + if(!testStatus(Restoring) || testStatus(Importing)) { + int tid=0; + const char *name = GetApplication().getActiveTransaction(&tid); + if(name && tid>0) + _openTransaction(name,tid); + } } + if (d->activeUndoTransaction) + d->activeUndoTransaction->addOrRemoveProperty(obj, prop, add); } bool Document::isPerformingTransaction() const @@ -1202,7 +1207,8 @@ void Document::setTransactionMode(int iMode) //-------------------------------------------------------------------------- // constructor //-------------------------------------------------------------------------- -Document::Document(void) +Document::Document(const char *name) + : myName(name) { // Remark: In a constructor we should never increment a Python object as we cannot be sure // if the Python interpreter gets a reference of it. E.g. if we increment but Python don't @@ -1957,7 +1963,12 @@ bool Document::isSaved() const */ const char* Document::getName() const { - return GetApplication().getDocumentName(this); + // return GetApplication().getDocumentName(this); + return myName.c_str(); +} + +std::string Document::getFullName() const { + return myName; } /// Remove all modifications. After this call The document becomes valid again. diff --git a/src/App/Document.h b/src/App/Document.h index 4bee832e9c..a24a389ca2 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -169,6 +169,7 @@ public: boost::signals2::signal signalCommitTransaction; // signal an aborted transaction boost::signals2::signal signalAbortTransaction; + boost::signals2::signal signalChangePropertyEditor; //@} /** @name File handling of the document */ @@ -340,8 +341,8 @@ public: bool redo() ; /// returns true if the document is in an Transaction phase, e.g. currently performing a redo/undo or rollback bool isPerformingTransaction() const; - /// \internal remove property from a transactional object with name \a name - void removePropertyOfObject(TransactionalObject*, const char*); + /// \internal add or remove property from a transactional object + void addOrRemovePropertyOfObject(TransactionalObject*, Property *prop, bool add); //@} /** @name dependency stuff */ @@ -389,6 +390,8 @@ public: virtual PyObject *getPyObject(void); + virtual std::string getFullName() const override; + friend class Application; /// because of transaction handling friend class TransactionalObject; @@ -401,7 +404,7 @@ public: protected: /// Construction - Document(void); + Document(const char *name = ""); void _removeObject(DocumentObject* pcObject); void _addObject(DocumentObject* pcObject, const char* pObjectName); @@ -438,6 +441,8 @@ private: // pointer to the python class Py::Object DocumentPythonObject; struct DocumentP* d; + + std::string myName; }; template diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index fadbf1b5dd..520dfe1436 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -529,27 +529,44 @@ void DocumentObject::setDocument(App::Document* doc) onSettingDocument(); } -void DocumentObject::onAboutToRemoveProperty(const char* name) +bool DocumentObject::removeDynamicProperty(const char* name) { - if (_pDoc) { - _pDoc->removePropertyOfObject(this, name); + if (!_pDoc) + return false; - Property* prop = getDynamicPropertyByName(name); - if (prop) { - auto expressions = ExpressionEngine.getExpressions(); - std::vector removeExpr; + Property* prop = getDynamicPropertyByName(name); + if(!prop || prop->testStatus(App::Property::LockDynamic)) + return false; - for (auto it : expressions) { - if (it.first.getProperty() == prop) { - removeExpr.push_back(it.first); - } - } + if(prop->isDerivedFrom(PropertyLinkBase::getClassTypeId())) + clearOutListCache(); - for (auto it : removeExpr) { - ExpressionEngine.setValue(it, boost::shared_ptr()); - } + _pDoc->addOrRemovePropertyOfObject(this, prop, false); + + auto expressions = ExpressionEngine.getExpressions(); + std::vector removeExpr; + + for (auto it : expressions) { + if (it.first.getProperty() == prop) { + removeExpr.push_back(it.first); } } + + for (auto it : removeExpr) { + ExpressionEngine.setValue(it, boost::shared_ptr()); + } + + return TransactionalObject::removeDynamicProperty(name); +} + +App::Property* DocumentObject::addDynamicProperty( + const char* type, const char* name, const char* group, const char* doc, + short attr, bool ro, bool hidden) +{ + auto prop = TransactionalObject::addDynamicProperty(type,name,group,doc,attr,ro,hidden); + if(prop && _pDoc) + _pDoc->addOrRemovePropertyOfObject(this, prop, true); + return prop; } void DocumentObject::onBeforeChange(const Property* prop) @@ -580,8 +597,14 @@ void DocumentObject::onChanged(const Property* prop) _pDoc->signalRelabelObject(*this); // set object touched if it is an input property - if (!(prop->getType() & Prop_Output)) { - StatusBits.set(ObjectStatus::Touch); + if (!testStatus(ObjectStatus::NoTouch) + && !(prop->getType() & Prop_Output) + && !prop->testStatus(Property::Output)) + { + if(!StatusBits.test(ObjectStatus::Touch)) { + FC_TRACE("touch '" << getFullName() << "' on change of '" << prop->getName() << "'"); + StatusBits.set(ObjectStatus::Touch); + } // must execute on document recompute if (!(prop->getType() & Prop_NoRecompute)) StatusBits.set(ObjectStatus::Enforce); @@ -1008,3 +1031,9 @@ bool DocumentObject::redirectSubName(std::ostringstream &, DocumentObject *, Doc return false; } +void DocumentObject::onPropertyStatusChanged(const Property &prop, unsigned long oldStatus) { + (void)oldStatus; + if(!Document::isAnyRestoring() && getNameInDocument() && getDocument()) + getDocument()->signalChangePropertyEditor(*getDocument(),prop); +} + diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index 3a1351202f..f25362159a 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -115,7 +115,7 @@ public: /// Return the object ID that is unique within its owner document long getID() const {return _Id;} /// Return the object full name of the form DocName#ObjName - std::string getFullName() const; + virtual std::string getFullName() const override; virtual bool isAttachedToDocument() const; virtual const char* detachFromDocument(); /// gets the document in which this Object is handled @@ -365,6 +365,13 @@ public: return _pcViewProviderName.c_str(); } + virtual bool removeDynamicProperty(const char* prop) override; + + virtual App::Property* addDynamicProperty( + const char* type, const char* name=0, + const char* group=0, const char* doc=0, + short attr=0, bool ro=false, bool hidden=false) override; + /** Resolve the last document object referenced in the subname * * @param subname: dot separated subname @@ -438,8 +445,6 @@ protected: void resetError(void){StatusBits.reset(ObjectStatus::Error);} void setDocument(App::Document* doc); - /// \internal get called when removing a property of name \a prop - void onAboutToRemoveProperty(const char* prop); /// get called before the value is changed virtual void onBeforeChange(const Property* prop); /// get called by the container when a property was changed @@ -453,6 +458,9 @@ protected: /// get called when object is going to be removed from the document virtual void unsetupObject(); + /// get called when a property status has changed + virtual void onPropertyStatusChanged(const Property &prop, unsigned long oldStatus) override; + /// python object of this class and all descendent protected: // attributes Py::Object PythonObject; diff --git a/src/App/DocumentObjectPyImp.cpp b/src/App/DocumentObjectPyImp.cpp index a74742a4c7..7becef5e3e 100644 --- a/src/App/DocumentObjectPyImp.cpp +++ b/src/App/DocumentObjectPyImp.cpp @@ -672,20 +672,39 @@ PyObject* DocumentObjectPy::getPathsByOutList(PyObject *args) PyObject *DocumentObjectPy::getCustomAttributes(const char* attr) const { + // Dynamic proeprty is now directly supported in PropertyContainer. So we + // can comment out here and let PropertyContainerPy handle it. +#if 1 + (void)attr; +#else // search for dynamic property Property* prop = getDocumentObjectPtr()->getDynamicPropertyByName(attr); if (prop) return prop->getPyObject(); else +#endif return 0; } int DocumentObjectPy::setCustomAttributes(const char* attr, PyObject *obj) { + // The following code is practically the same as in PropertyContainerPy, + // especially since now dynamic proeprty is directly supported in + // PropertyContainer. So we can comment out here and let PropertyContainerPy + // handle it. +#if 1 + (void)attr; + (void)obj; +#else // explicitly search for dynamic property try { Property* prop = getDocumentObjectPtr()->getDynamicPropertyByName(attr); if (prop) { + if(prop->testStatus(Property::Immutable)) { + std::stringstream s; + s << "'DocumentObject' attribute '" << attr << "' is read-only"; + throw Py::AttributeError(s.str()); + } prop->setPyObject(obj); return 1; } @@ -700,7 +719,9 @@ int DocumentObjectPy::setCustomAttributes(const char* attr, PyObject *obj) s << "Attribute (Name: " << attr << ") error: '" << exc.what() << "' "; throw Py::AttributeError(s.str()); } - catch (...) { + catch (Py::AttributeError &) { + throw; + }catch (...) { std::stringstream s; s << "Unknown error in attribute " << attr; throw Py::AttributeError(s.str()); @@ -710,8 +731,9 @@ int DocumentObjectPy::setCustomAttributes(const char* attr, PyObject *obj) Property *prop = getDocumentObjectPtr()->getPropertyByName(attr); if (prop) { // Read-only attributes must not be set over its Python interface - short Type = getDocumentObjectPtr()->getPropertyType(prop); - if (Type & Prop_ReadOnly) { + if(prop->testStatus(Property::Immutable) || + (getDocumentObjectPtr()->getPropertyType(prop) & Prop_ReadOnly)) + { std::stringstream s; s << "'DocumentObject' attribute '" << attr << "' is read-only"; throw Py::AttributeError(s.str()); @@ -727,6 +749,7 @@ int DocumentObjectPy::setCustomAttributes(const char* attr, PyObject *obj) } return 1; } +#endif return 0; } diff --git a/src/App/DynamicProperty.cpp b/src/App/DynamicProperty.cpp index 2a0caded9b..6bcc061c7c 100644 --- a/src/App/DynamicProperty.cpp +++ b/src/App/DynamicProperty.cpp @@ -37,202 +37,117 @@ #include #include +FC_LOG_LEVEL_INIT("DynamicProperty",true,true) + using namespace App; -DynamicProperty::DynamicProperty(PropertyContainer* p) : pc(p) +DynamicProperty::DynamicProperty() { } DynamicProperty::~DynamicProperty() { + clear(); +} + +void DynamicProperty::clear() { + auto &index = props.get<0>(); + for(auto &v : index) + delete v.property; + index.clear(); } void DynamicProperty::getPropertyList(std::vector &List) const { - // get the properties of the base class first and insert the dynamic properties afterwards - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - static_cast(this->pc)->ExtensionContainer::getPropertyList(List); - else - this->pc->PropertyContainer::getPropertyList(List); - - for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) - List.push_back(it->second.property); + for (auto &v : props.get<0>()) + List.push_back(v.property); } void DynamicProperty::getPropertyMap(std::map &Map) const { - // get the properties of the base class first and insert the dynamic properties afterwards - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - static_cast(this->pc)->ExtensionContainer::getPropertyMap(Map); - else - this->pc->PropertyContainer::getPropertyMap(Map); - - for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) - Map[it->first] = it->second.property; -} - -Property *DynamicProperty::getPropertyByName(const char* name) const -{ - std::map::const_iterator it = props.find(name); - if (it != props.end()) - return it->second.property; - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyByName(name); - - return this->pc->PropertyContainer::getPropertyByName(name); + for (auto &v : props.get<0>()) + Map[v.name] = v.property; } Property *DynamicProperty::getDynamicPropertyByName(const char* name) const { - std::map::const_iterator it = props.find(name); - if (it != props.end()) - return it->second.property; + auto &index = props.get<0>(); + auto it = index.find(name); + if (it != index.end()) + return it->property; return 0; } std::vector DynamicProperty::getDynamicPropertyNames() const { std::vector names; - for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { - names.push_back(it->first); - } + auto &index = props.get<0>(); + names.reserve(index.size()); + for(auto &v : index) + names.push_back(v.name); return names; } -void DynamicProperty::addDynamicProperties(const PropertyContainer* cont) -{ - std::vector names = cont->getDynamicPropertyNames(); - for (std::vector::iterator it = names.begin(); it != names.end(); ++it) { - App::Property* prop = cont->getDynamicPropertyByName(it->c_str()); - if (prop) { - addDynamicProperty( - prop->getTypeId().getName(), - prop->getName(), - prop->getGroup(), - prop->getDocumentation(), - prop->getType(), - cont->isReadOnly(prop), - cont->isHidden(prop)); - } - } -} - -const char* DynamicProperty::getPropertyName(const Property* prop) const -{ - for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { - if (it->second.property == prop) - return it->first.c_str(); - } - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyName(prop); - - return this->pc->PropertyContainer::getPropertyName(prop); -} - -unsigned int DynamicProperty::getMemSize (void) const -{ - std::map Map; - getPropertyMap(Map); - std::map::const_iterator It; - unsigned int size = 0; - for (It = Map.begin(); It != Map.end();++It) - size += It->second->getMemSize(); - return size; -} - short DynamicProperty::getPropertyType(const Property* prop) const { - for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { - if (it->second.property == prop) { - short attr = it->second.attr; - if (it->second.hidden) - attr |= Prop_Hidden; - if (it->second.readonly) - attr |= Prop_ReadOnly; - return attr; - } - } - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyType(prop); - - return this->pc->PropertyContainer::getPropertyType(prop); + return prop?prop->getType():0; } short DynamicProperty::getPropertyType(const char *name) const { - std::map::const_iterator it = props.find(name); - if (it != props.end()) { - short attr = it->second.attr; - if (it->second.hidden) + auto &index = props.get<0>(); + auto it = index.find(name); + if (it != index.end()) { + short attr = it->attr; + if (it->hidden) attr |= Prop_Hidden; - if (it->second.readonly) + if (it->readonly) attr |= Prop_ReadOnly; return attr; } - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyType(name); - - return this->pc->PropertyContainer::getPropertyType(name); + return 0; } const char* DynamicProperty::getPropertyGroup(const Property* prop) const { - for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { - if (it->second.property == prop) - return it->second.group.c_str(); - } - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyGroup(prop); - - return this->pc->PropertyContainer::getPropertyGroup(prop); + auto &index = props.get<1>(); + auto it = index.find(const_cast(prop)); + if(it!=index.end()) + return it->group.c_str(); + return 0; } const char* DynamicProperty::getPropertyGroup(const char *name) const { - std::map::const_iterator it = props.find(name); - if (it != props.end()) - return it->second.group.c_str(); - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyGroup(name); - - return this->pc->PropertyContainer::getPropertyGroup(name); + auto &index = props.get<0>(); + auto it = index.find(name); + if (it != index.end()) + return it->group.c_str(); + return 0; } const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const { - for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { - if (it->second.property == prop) - return it->second.doc.c_str(); - } - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyDocumentation(prop); - - return this->pc->PropertyContainer::getPropertyDocumentation(prop); + auto &index = props.get<1>(); + auto it = index.find(const_cast(prop)); + if(it!=index.end()) + return it->doc.c_str(); + return 0; } const char* DynamicProperty::getPropertyDocumentation(const char *name) const { - std::map::const_iterator it = props.find(name); - if (it != props.end()) - return it->second.doc.c_str(); - - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - return static_cast(this->pc)->ExtensionContainer::getPropertyDocumentation(name); - - return this->pc->PropertyContainer::getPropertyDocumentation(name); + auto &index = props.get<0>(); + auto it = index.find(name); + if (it != index.end()) + return it->doc.c_str(); + return 0; } -Property* DynamicProperty::addDynamicProperty(const char* type, const char* name, const char* group, - const char* doc, short attr, bool ro, bool hidden) +Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char* type, + const char* name, const char* group, const char* doc, short attr, bool ro, bool hidden) { Base::BaseClass* base = static_cast(Base::Type::createInstanceByName(type,true)); if (!base) @@ -246,49 +161,76 @@ Property* DynamicProperty::addDynamicProperty(const char* type, const char* name // get unique name Property* pcProperty = static_cast(base); - std::string ObjectName; - if (name && *name != '\0') - ObjectName = getUniquePropertyName(name); - else - ObjectName = getUniquePropertyName(type); + if (!name || !name[0]) + name = type; - pcProperty->setContainer(this->pc); - PropData data; - data.property = pcProperty; - data.group = (group ? group : ""); - data.doc = (doc ? doc : ""); - data.attr = attr; - data.readonly = ro; - data.hidden = hidden; - props[ObjectName] = data; + auto res = props.get<0>().emplace(pcProperty, + getUniquePropertyName(pc,name), nullptr, group, doc, attr, ro, hidden); + + pcProperty->setContainer(&pc); + pcProperty->myName = res.first->name.c_str(); + + if(ro) attr |= Prop_ReadOnly; + if(hidden) attr |= Prop_Hidden; + + pcProperty->syncType(attr); + pcProperty->StatusBits.set((size_t)Property::PropDynamic); GetApplication().signalAppendDynamicProperty(*pcProperty); return pcProperty; } +bool DynamicProperty::addProperty(Property *prop) +{ + if(!prop || !prop->getName()) + return false; + auto &index = props.get<0>(); + if(index.count(prop->getName())) + return false; + index.emplace(prop,std::string(),prop->getName(), + prop->getGroup(),prop->getDocumentation(),prop->getType(),false,false); + return true; +} + +bool DynamicProperty::removeProperty(const Property *prop) +{ + auto &index = props.get<1>(); + auto it = index.find(const_cast(prop)); + if (it != index.end()) { + index.erase(it); + return true; + } + return false; +} + bool DynamicProperty::removeDynamicProperty(const char* name) { - std::map::iterator it = props.find(name); - if (it != props.end()) { - GetApplication().signalRemoveDynamicProperty(*it->second.property); - delete it->second.property; - props.erase(it); + auto &index = props.get<0>(); + auto it = index.find(name); + if (it != index.end()) { + if(it->property->testStatus(Property::LockDynamic)) + throw Base::RuntimeError("property is locked"); + else if(!it->property->testStatus(Property::PropDynamic)) + throw Base::RuntimeError("property is not dynamic"); + Property *prop = it->property; + GetApplication().signalRemoveDynamicProperty(*prop); + delete prop; + index.erase(it); return true; } return false; } -std::string DynamicProperty::getUniquePropertyName(const char *Name) const +std::string DynamicProperty::getUniquePropertyName(PropertyContainer &pc, const char *Name) const { std::string CleanName = Base::Tools::getIdentifier(Name); // name in use? std::map objectProps; - getPropertyMap(objectProps); - std::map::const_iterator pos; - pos = objectProps.find(CleanName); + pc.getPropertyMap(objectProps); + auto pos = objectProps.find(CleanName); if (pos == objectProps.end()) { // if not, name is OK @@ -304,151 +246,60 @@ std::string DynamicProperty::getUniquePropertyName(const char *Name) const } } -void DynamicProperty::Save (Base::Writer &writer) const +void DynamicProperty::save(const Property *prop, Base::Writer &writer) const { - //extensions must be saved first, as they need to be read and initialised before properties (as - //they have their own properties which they need to handle on restore) - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - static_cast(this->pc)->saveExtensions(writer); - - std::map Map; - getPropertyMap(Map); - - writer.incInd(); // indentation for 'Properties Count' - writer.Stream() << writer.ind() << "" << std::endl; - std::map::iterator it; - for (it = Map.begin(); it != Map.end(); ++it) - { - writer.incInd(); // indentation for 'Property name' - // check whether a static or dynamic property - std::map::const_iterator pt = props.find(it->first); - if (pt == props.end()) { - writer.Stream() << writer.ind() << "first << "\" type=\"" - << it->second->getTypeId().getName() << "\">" << std::endl; - } - else { - writer.Stream() << writer.ind() << "first - << "\" type=\"" << it->second->getTypeId().getName() - << "\" group=\"" << encodeAttribute(pt->second.group) - << "\" doc=\"" << encodeAttribute(pt->second.doc) - << "\" attr=\"" << pt->second.attr << "\" ro=\"" << pt->second.readonly - << "\" hide=\"" << pt->second.hidden << "\">" << std::endl; - } - - writer.incInd(); // indentation for the actual property - try { - // We must make sure to handle all exceptions accordingly so that - // the project file doesn't get invalidated. In the error case this - // means to proceed instead of aborting the write operation. - - // Don't write transient properties - if (!(getPropertyType(it->second) & Prop_Transient)) - it->second->Save(writer); - } - catch (const Base::Exception &e) { - Base::Console().Error("%s\n", e.what()); - } - catch (const std::exception &e) { - Base::Console().Error("%s\n", e.what()); - } - catch (const char* e) { - Base::Console().Error("%s\n", e); - } -#ifndef FC_DEBUG - catch (...) { - Base::Console().Error("DynamicProperty::Save: Unknown C++ exception thrown. Try to continue...\n"); - } -#endif - writer.decInd(); // indentation for the actual property - writer.Stream() << writer.ind() << "" << std::endl; - writer.decInd(); // indentation for 'Property name' + auto &index = props.get<1>(); + auto it = index.find(const_cast(prop)); + if(it != index.end()) { + auto &data = *it; + writer.Stream() << "\" group=\"" << Base::Persistence::encodeAttribute(data.group) + << "\" doc=\"" << Base::Persistence::encodeAttribute(data.doc) + << "\" attr=\"" << data.attr << "\" ro=\"" << data.readonly + << "\" hide=\"" << data.hidden; } - writer.Stream() << writer.ind() << "" << std::endl; - writer.decInd(); // indentation for 'Properties Count' } -void DynamicProperty::Restore(Base::XMLReader &reader) +Property *DynamicProperty::restore(PropertyContainer &pc, + const char *PropName, const char *TypeName, Base::XMLReader &reader) { - //first all extensions must be initialised so that they can handle their properties - if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) - static_cast(this->pc)->restoreExtensions(reader); + if (!reader.hasAttribute("group")) + return 0; - reader.readElement("Properties"); - int Cnt = reader.getAttributeAsInteger("Count"); - - for (int i=0 ;i