diff --git a/src/App/Document.cpp b/src/App/Document.cpp index e119b97407..367f4f46a9 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -869,6 +869,17 @@ bool Document::redo(void) return false; } +void Document::removePropertyOfObject(TransactionalObject* obj, const char* name) +{ + Property* prop = obj->getDynamicPropertyByName(name); + if (prop) { + if (d->activeUndoTransaction) + d->activeUndoTransaction->removeProperty(obj, prop); + for (auto it : mUndoTransactions) + it->removeProperty(obj, prop); + } +} + bool Document::isPerformingTransaction() const { return d->undoing || d->rollback; diff --git a/src/App/Document.h b/src/App/Document.h index 01f140ddf1..5c2197c217 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -309,6 +309,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*); //@} /** @name dependency stuff */ diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index fafc5a83e9..ce3510b340 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -402,6 +402,12 @@ void DocumentObject::setDocument(App::Document* doc) onSettingDocument(); } +void DocumentObject::onAboutToRemoveProperty(const char* prop) +{ + if (_pDoc) + _pDoc->removePropertyOfObject(this, prop); +} + void DocumentObject::onBeforeChange(const Property* prop) { // Store current name in oldLabel, to be able to easily retrieve old name of document object later diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index 8d543fd5b5..ef01a93e1a 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -255,6 +255,8 @@ 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 diff --git a/src/App/FeatureCustom.h b/src/App/FeatureCustom.h index 7d19a374b8..7802441367 100644 --- a/src/App/FeatureCustom.h +++ b/src/App/FeatureCustom.h @@ -79,6 +79,7 @@ public: return props->addDynamicProperty(type, name, group, doc, attr, ro, hidden); } virtual bool removeDynamicProperty(const char* name) { + FeatureT::onAboutToRemoveProperty(name); return props->removeDynamicProperty(name); } std::vector getDynamicPropertyNames() const { diff --git a/src/App/FeaturePython.h b/src/App/FeaturePython.h index 113a5befe7..2ef3b4cbe3 100644 --- a/src/App/FeaturePython.h +++ b/src/App/FeaturePython.h @@ -110,6 +110,7 @@ public: return props->addDynamicProperty(type, name, group, doc, attr, ro, hidden); } virtual bool removeDynamicProperty(const char* name) { + FeatureT::onAboutToRemoveProperty(name); return props->removeDynamicProperty(name); } std::vector getDynamicPropertyNames() const { diff --git a/src/App/Transactions.cpp b/src/App/Transactions.cpp index f4f4ba4982..414891be79 100644 --- a/src/App/Transactions.cpp +++ b/src/App/Transactions.cpp @@ -114,6 +114,15 @@ bool Transaction::hasObject(const TransactionalObject *Obj) const return false; } +void Transaction::removeProperty(TransactionalObject *Obj, + const Property* pcProp) +{ + for (auto it : _Objects) { + if (it.first == Obj) + it.second->removeProperty(pcProp); + } +} + //************************************************************************** // separator for other implemetation aspects @@ -277,6 +286,15 @@ void TransactionObject::setProperty(const Property* pcProp) _PropChangeMap[pcProp] = pcProp->Copy(); } +void TransactionObject::removeProperty(const Property* pcProp) +{ + std::map::iterator pos = _PropChangeMap.find(pcProp); + if (pos != _PropChangeMap.end()) { + delete pos->second; + _PropChangeMap.erase(pos); + } +} + unsigned int TransactionObject::getMemSize (void) const { return 0; diff --git a/src/App/Transactions.h b/src/App/Transactions.h index dfddd2c42a..71165e8457 100644 --- a/src/App/Transactions.h +++ b/src/App/Transactions.h @@ -66,6 +66,7 @@ public: int getPos(void) const; /// check if this object is used in a transaction bool hasObject(const TransactionalObject *Obj) const; + void removeProperty(TransactionalObject *Obj, const Property* pcProp); void addObjectNew(TransactionalObject *Obj); void addObjectDel(const TransactionalObject *Obj); @@ -94,6 +95,7 @@ public: virtual void applyChn(Document &Doc, TransactionalObject *pcObj, bool Forward); void setProperty(const Property* pcProp); + void removeProperty(const Property* pcProp); virtual unsigned int getMemSize (void) const; virtual void Save (Base::Writer &writer) const; diff --git a/src/Gui/ViewProviderDocumentObject.cpp b/src/Gui/ViewProviderDocumentObject.cpp index 89dfdb190c..6f15379c64 100644 --- a/src/Gui/ViewProviderDocumentObject.cpp +++ b/src/Gui/ViewProviderDocumentObject.cpp @@ -94,6 +94,15 @@ const char* ViewProviderDocumentObject::detachFromDocument() return ""; } +void ViewProviderDocumentObject::onAboutToRemoveProperty(const char* prop) +{ + // transactions of view providers are also managed in App::Document. + App::DocumentObject* docobject = getObject(); + App::Document* document = docobject ? docobject->getDocument() : nullptr; + if (document) + document->removePropertyOfObject(this, prop); +} + void ViewProviderDocumentObject::onBeforeChange(const App::Property* prop) { if (isAttachedToDocument()) { diff --git a/src/Gui/ViewProviderDocumentObject.h b/src/Gui/ViewProviderDocumentObject.h index c6d79d1a6b..2a263248ac 100644 --- a/src/Gui/ViewProviderDocumentObject.h +++ b/src/Gui/ViewProviderDocumentObject.h @@ -126,6 +126,8 @@ protected: /** @name Transaction handling */ //@{ + /// \internal get called when removing a property of name \a prop + void onAboutToRemoveProperty(const char* prop); virtual bool isAttachedToDocument() const; virtual const char* detachFromDocument(); //@} diff --git a/src/Gui/ViewProviderPythonFeature.h b/src/Gui/ViewProviderPythonFeature.h index b707b9fa88..4cca4fc5c1 100644 --- a/src/Gui/ViewProviderPythonFeature.h +++ b/src/Gui/ViewProviderPythonFeature.h @@ -301,6 +301,7 @@ public: return props->addDynamicProperty(type, name, group, doc, attr, ro, hidden); } virtual bool removeDynamicProperty(const char* name) { + ViewProviderT::onAboutToRemoveProperty(name); return props->removeDynamicProperty(name); } std::vector getDynamicPropertyNames() const { diff --git a/src/Mod/Spreadsheet/App/Sheet.cpp b/src/Mod/Spreadsheet/App/Sheet.cpp index 06d61f7624..4eb6b1999d 100644 --- a/src/Mod/Spreadsheet/App/Sheet.cpp +++ b/src/Mod/Spreadsheet/App/Sheet.cpp @@ -113,7 +113,7 @@ void Sheet::clearAll() std::vector propNames = props.getDynamicPropertyNames(); for (std::vector::const_iterator i = propNames.begin(); i != propNames.end(); ++i) - props.removeDynamicProperty((*i).c_str()); + this->removeDynamicProperty((*i).c_str()); propAddress.clear(); cellErrors.clear(); @@ -460,7 +460,7 @@ void Sheet::removeAliases() std::map::iterator i = removedAliases.begin(); while (i != removedAliases.end()) { - props.removeDynamicProperty(i->second.c_str()); + this->removeDynamicProperty(i->second.c_str()); ++i; } removedAliases.clear(); @@ -491,7 +491,7 @@ Property * Sheet::setFloatProperty(CellAddress key, double value) if (!prop || prop->getTypeId() != PropertyFloat::getClassTypeId()) { if (prop) { - props.removeDynamicProperty(key.toString().c_str()); + this->removeDynamicProperty(key.toString().c_str()); propAddress.erase(prop); } floatProp = freecad_dynamic_cast(props.addDynamicProperty("App::PropertyFloat", key.toString().c_str(), 0, 0, Prop_ReadOnly | Prop_Hidden | Prop_Transient)); @@ -522,7 +522,7 @@ Property * Sheet::setQuantityProperty(CellAddress key, double value, const Base: if (!prop || prop->getTypeId() != PropertySpreadsheetQuantity::getClassTypeId()) { if (prop) { - props.removeDynamicProperty(key.toString().c_str()); + this->removeDynamicProperty(key.toString().c_str()); propAddress.erase(prop); } Property * p = props.addDynamicProperty("Spreadsheet::PropertySpreadsheetQuantity", key.toString().c_str(), 0, 0, Prop_ReadOnly | Prop_Hidden | Prop_Transient); @@ -556,7 +556,7 @@ Property * Sheet::setStringProperty(CellAddress key, const std::string & value) if (!stringProp) { if (prop) { - props.removeDynamicProperty(key.toString().c_str()); + this->removeDynamicProperty(key.toString().c_str()); propAddress.erase(prop); } stringProp = freecad_dynamic_cast(props.addDynamicProperty("App::PropertyString", key.toString().c_str(), 0, 0, Prop_ReadOnly | Prop_Hidden | Prop_Transient)); @@ -590,7 +590,7 @@ void Sheet::updateAlias(CellAddress key) if (aliasProp) { // Type of alias and property must always be the same if (aliasProp->getTypeId() != prop->getTypeId()) { - props.removeDynamicProperty(alias.c_str()); + this->removeDynamicProperty(alias.c_str()); aliasProp = 0; } } @@ -882,7 +882,7 @@ void Sheet::clear(CellAddress address, bool /*all*/) // Remove alias, if defined std::string aliasStr; if (cell && cell->getAlias(aliasStr)) - props.removeDynamicProperty(aliasStr.c_str()); + this->removeDynamicProperty(aliasStr.c_str()); cells.clear(address); @@ -896,7 +896,7 @@ void Sheet::clear(CellAddress address, bool /*all*/) docDeps.setValues(dv); propAddress.erase(prop); - props.removeDynamicProperty(addr.c_str()); + this->removeDynamicProperty(addr.c_str()); } /** diff --git a/src/Mod/Spreadsheet/App/Sheet.h b/src/Mod/Spreadsheet/App/Sheet.h index d7ae903745..59becc7702 100644 --- a/src/Mod/Spreadsheet/App/Sheet.h +++ b/src/Mod/Spreadsheet/App/Sheet.h @@ -187,6 +187,7 @@ public: return props.addDynamicProperty(type, name, group, doc, attr, ro, hidden); } virtual bool removeDynamicProperty(const char* name) { + App::DocumentObject::onAboutToRemoveProperty(name); return props.removeDynamicProperty(name); } std::vector getDynamicPropertyNames() const {