From 784d687fe1671ba7856b721b8958889b4d426c29 Mon Sep 17 00:00:00 2001 From: mpv Date: Mon, 22 Sep 2014 11:50:29 +0400 Subject: [PATCH] Add checking that object is used before the delete operation --- src/Model/Model_Data.cpp | 40 ++++++++++++++++++++++++ src/Model/Model_Data.h | 3 ++ src/Model/Model_Document.cpp | 34 +++++++++++++------- src/Model/Model_Document.h | 3 +- src/ModelAPI/ModelAPI_Data.h | 4 +++ src/ModelAPI/ModelAPI_Document.h | 6 ++-- src/SketchPlugin/SketchPlugin_Sketch.cpp | 6 ++-- 7 files changed, 79 insertions(+), 17 deletions(-) diff --git a/src/Model/Model_Data.cpp b/src/Model/Model_Data.cpp index 26f537d68..495bd04bc 100644 --- a/src/Model/Model_Data.cpp +++ b/src/Model/Model_Data.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -285,6 +287,7 @@ void Model_Data::erase() myLab.ForgetAllAttributes(); } +/// identifeir of the "must be updated" flag in the data tree Standard_GUID kMustBeUpdatedGUID("baede74c-31a6-4416-9c4d-e48ce65f2005"); void Model_Data::mustBeUpdated(const bool theFlag) @@ -299,3 +302,40 @@ bool Model_Data::mustBeUpdated() { return myLab.IsAttribute(kMustBeUpdatedGUID) == Standard_True; } + +bool Model_Data::referencesTo(const boost::shared_ptr& theFeature) +{ + // collect results of this feature first to check references quickly in the cycle + std::set aFeatureObjs; + aFeatureObjs.insert(theFeature); + std::list >::const_iterator aRIter = + theFeature->results().cbegin(); + for(; aRIter != theFeature->results().cend(); aRIter++) { + if (*aRIter) + aFeatureObjs.insert(*aRIter); + } + + std::map >::iterator anAttrsIter = + myAttrs.begin(); + for (; anAttrsIter != myAttrs.end(); anAttrsIter++) { + if (anAttrsIter->second->attributeType() == ModelAPI_AttributeRefAttr::type()) { + boost::shared_ptr aRefAttr = + boost::dynamic_pointer_cast(anAttrsIter->second); + if (aRefAttr && aRefAttr->isObject()) { // check referenced object + if (aFeatureObjs.find(aRefAttr->object()) != aFeatureObjs.end()) + return true; + } else { // check object of referenced attribute + boost::shared_ptr anAttr = aRefAttr->attr(); + if (anAttr && aFeatureObjs.find(anAttr->owner()) != aFeatureObjs.end()) + return true; + } + } else if (anAttrsIter->second->attributeType() == ModelAPI_AttributeReference::type()) { + boost::shared_ptr aRef = + boost::dynamic_pointer_cast(anAttrsIter->second); + if (aFeatureObjs.find(aRef->value()) != aFeatureObjs.end()) { + return true; + } + } + } + return false; +} diff --git a/src/Model/Model_Data.h b/src/Model/Model_Data.h index 136e4504f..559fc12ad 100644 --- a/src/Model/Model_Data.h +++ b/src/Model/Model_Data.h @@ -136,6 +136,9 @@ class Model_Data : public ModelAPI_Data /// Returns true if feature must be updated (re-executed) on rebuild MODEL_EXPORT virtual bool mustBeUpdated(); + + /// Returns true if this data attributes are referenced to the given feature or its results + MODEL_EXPORT virtual bool referencesTo(const boost::shared_ptr& theFeature); }; #endif diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 57241b6b5..08eb944fa 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -459,16 +459,27 @@ static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, co return aResult; } -void Model_Document::removeFeature(FeaturePtr theFeature) -{ - // check the feature: it must have no depended objects on it - std::list::const_iterator aResIter = theFeature->results().cbegin(); - for(; aResIter != theFeature->results().cend(); aResIter++) { - if (myConcealedResults.find(*aResIter) != myConcealedResults.end()) { - Events_Error::send("Feature '" + theFeature->data()->name() + "' is used and can not be deleted"); - return; +void Model_Document::removeFeature(FeaturePtr theFeature, const bool theCheck) +{ + if (theCheck) { + // check the feature: it must have no depended objects on it + std::list::const_iterator aResIter = theFeature->results().cbegin(); + for(; aResIter != theFeature->results().cend(); aResIter++) { + if (myConcealedResults.find(*aResIter) != myConcealedResults.end()) { + Events_Error::send("Feature '" + theFeature->data()->name() + "' is used and can not be deleted"); + return; + } + } + NCollection_DataMap::Iterator anObjIter(myObjs); + for(; anObjIter.More(); anObjIter.Next()) { + DataPtr aData = anObjIter.Value()->data(); + if (aData->referencesTo(theFeature)) { + Events_Error::send("Feature '" + theFeature->data()->name() + "' is used and can not be deleted"); + return; + } } } + boost::shared_ptr aData = boost::static_pointer_cast(theFeature->data()); TDF_Label aFeatureLabel = aData->label().Father(); if (myObjs.IsBound(aFeatureLabel)) @@ -745,9 +756,6 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated) if (aKeptFeatures.find(aFIter.Value()) == aKeptFeatures.end() && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) { FeaturePtr aFeature = aFIter.Value(); - TDF_Label aLab = aFIter.Key(); - aFIter.Next(); - myObjs.UnBind(aLab); // event: model is updated //if (aFeature->isInHistory()) { ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group()); @@ -767,6 +775,10 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated) // redisplay also removed feature (used for sketch and AISObject) ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP); aFeature->erase(); + // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter + TDF_Label aLab = aFIter.Key(); + aFIter.Next(); + myObjs.UnBind(aLab); } else aFIter.Next(); } diff --git a/src/Model/Model_Document.h b/src/Model/Model_Document.h index 38625983c..6f813bd23 100644 --- a/src/Model/Model_Document.h +++ b/src/Model/Model_Document.h @@ -77,7 +77,8 @@ class Model_Document : public ModelAPI_Document MODEL_EXPORT virtual FeaturePtr addFeature(std::string theID); //! Removes the feature from the document (with result) - MODEL_EXPORT virtual void removeFeature(FeaturePtr theFeature); + //! \param theCheck if it is false, do not check the references + MODEL_EXPORT virtual void removeFeature(FeaturePtr theFeature, const bool theCheck = true); //! Returns the existing feature by the label //! \param theLabel base label of the feature diff --git a/src/ModelAPI/ModelAPI_Data.h b/src/ModelAPI/ModelAPI_Data.h index e82a4c44a..1265a51bd 100644 --- a/src/ModelAPI/ModelAPI_Data.h +++ b/src/ModelAPI/ModelAPI_Data.h @@ -20,6 +20,7 @@ class ModelAPI_AttributeBoolean; class ModelAPI_AttributeString; class ModelAPI_Document; class ModelAPI_Attribute; +class ModelAPI_Feature; class GeomAPI_Shape; /**\class ModelAPI_Data @@ -98,6 +99,9 @@ class MODELAPI_EXPORT ModelAPI_Data /// Returns true if feature must be updated (re-executed) on rebuild virtual bool mustBeUpdated() = 0; + /// Returns true if this data attributes are referenced to the given feature or its results + virtual bool referencesTo(const boost::shared_ptr& theFeature) = 0; + protected: /// Objects are created for features automatically ModelAPI_Data() diff --git a/src/ModelAPI/ModelAPI_Document.h b/src/ModelAPI/ModelAPI_Document.h index 6e432ae02..1a5aee9bf 100644 --- a/src/ModelAPI/ModelAPI_Document.h +++ b/src/ModelAPI/ModelAPI_Document.h @@ -41,11 +41,11 @@ public: virtual boost::shared_ptr addFeature(std::string theID) = 0; //! Removes the feature from the document - virtual void removeFeature(boost::shared_ptr theFeature) = 0; + virtual void removeFeature( + boost::shared_ptr theFeature, const bool theCheck = true) = 0; ///! Adds a new sub-document by the identifier, or returns existing one if it is already exist - virtual boost::shared_ptr - subDocument(std::string theDocID) = 0; + virtual boost::shared_ptr subDocument(std::string theDocID) = 0; ///! Returns the id of the document virtual const std::string& id() const = 0; diff --git a/src/SketchPlugin/SketchPlugin_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index 256ba9d5e..1bc1b469c 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -176,8 +176,10 @@ void SketchPlugin_Sketch::erase() std::list::const_iterator anIt = aFeatures.begin(); for (; anIt != aFeatures.end(); anIt++) { FeaturePtr aFeature = boost::dynamic_pointer_cast(*anIt); - if (aFeature) - document()->removeFeature(aFeature); + if (aFeature) { + // subs are referenced from sketch, but must be removed for sure, so not checkings + document()->removeFeature(aFeature, false); + } } SketchPlugin_Feature::erase(); } -- 2.39.2