From 149dcd65a901bded64e17047cd5bf91921fa8bba Mon Sep 17 00:00:00 2001 From: nds Date: Wed, 1 Apr 2015 18:48:46 +0300 Subject: [PATCH] Issue #427, 420 - crash during work through external edges. It is necessary to add/remove back references during set an object to the attribute. The external object should not be removed by widget if there is a feature, which already uses this object. An additional check for the feature's data during analize the creation event from the model. --- src/Model/Model_AttributeRefAttr.cpp | 18 ++++++++++++++++++ src/Model/Model_Data.cpp | 19 +++++++++++++++++++ src/Model/Model_Data.h | 4 ++++ src/PartSet/PartSet_WidgetShapeSelector.cpp | 20 ++++++++++++++++++++ src/XGUI/XGUI_Workshop.cpp | 13 ++++++++++--- 5 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/Model/Model_AttributeRefAttr.cpp b/src/Model/Model_AttributeRefAttr.cpp index b6f9e3e67..2d900eb14 100644 --- a/src/Model/Model_AttributeRefAttr.cpp +++ b/src/Model/Model_AttributeRefAttr.cpp @@ -41,11 +41,29 @@ std::shared_ptr Model_AttributeRefAttr::attr() void Model_AttributeRefAttr::setObject(ObjectPtr theObject) { + // the back reference from the previous object to the attribute should be removed + ObjectPtr anObject = object(); + if (anObject.get() && anObject != theObject) { + FeaturePtr anOwnerFeature = std::dynamic_pointer_cast(owner()); + if (anOwnerFeature.get()) { + std::shared_ptr aData = std::dynamic_pointer_cast( + anObject->data()); + aData->removeBackReference(anOwnerFeature, id()); + } + } + if (theObject && (!myIsInitialized || myID->Get().Length() != 0 || object() != theObject)) { std::shared_ptr aData = std::dynamic_pointer_cast( theObject->data()); myRef->Set(aData->label().Father()); myID->Set(""); // feature is identified by the empty ID + + // do it before the transaction finish to make just created/removed objects know dependencies + // and reference from composite feature is removed automatically + FeaturePtr anOwnerFeature = std::dynamic_pointer_cast(owner()); + if (anOwnerFeature.get()) { + aData->addBackReference(anOwnerFeature, id(), false); + } owner()->data()->sendAttributeUpdated(this); } else if (theObject.get() == NULL) { myRef->Set(myRef->Label()); // reference to itself means that object is null diff --git a/src/Model/Model_Data.cpp b/src/Model/Model_Data.cpp index b3baaea43..53444bb6d 100644 --- a/src/Model/Model_Data.cpp +++ b/src/Model/Model_Data.cpp @@ -259,9 +259,28 @@ void Model_Data::eraseBackReferences() aRes->setIsConcealed(false); } +void Model_Data::removeBackReference(FeaturePtr theFeature, std::string theAttrID) +{ + AttributePtr anAttribute = theFeature->data()->attribute(theAttrID); + if (myRefsToMe.find(anAttribute) == myRefsToMe.end()) + return; + + myRefsToMe.erase(anAttribute); + // TODO: check whether the concealed should be thrown down to the false value + std::shared_ptr aRes = + std::dynamic_pointer_cast(myObject); + if (aRes) + aRes->setIsConcealed(false); +} + void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID, const bool theApplyConcealment) { + // do not add the same attribute twice + AttributePtr anAttribute = theFeature->data()->attribute(theAttrID); + if (myRefsToMe.find(anAttribute) != myRefsToMe.end()) + return; + myRefsToMe.insert(theFeature->data()->attribute(theAttrID)); if (theApplyConcealment && ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) { diff --git a/src/Model/Model_Data.h b/src/Model/Model_Data.h index 8a45cfe64..c057cede3 100644 --- a/src/Model/Model_Data.h +++ b/src/Model/Model_Data.h @@ -185,6 +185,10 @@ private: /// Adds a back reference (with identifier which attribute references to this object /// \param theFeature feature referenced to this /// \param theAttrID identifier of the attribute that is references from theFeature to this + void removeBackReference(FeaturePtr theFeature, std::string theAttrID); + /// Adds a back reference (with identifier which attribute references to this object + /// \param theFeature feature referenced to this + /// \param theAttrID identifier of the attribute that is references from theFeature to this /// \param theApplyConcealment applies consealment flag changes void addBackReference(FeaturePtr theFeature, std::string theAttrID, const bool theApplyConcealment = true); diff --git a/src/PartSet/PartSet_WidgetShapeSelector.cpp b/src/PartSet/PartSet_WidgetShapeSelector.cpp index 7352c1344..8b1865829 100644 --- a/src/PartSet/PartSet_WidgetShapeSelector.cpp +++ b/src/PartSet/PartSet_WidgetShapeSelector.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include PartSet_WidgetShapeSelector::PartSet_WidgetShapeSelector(QWidget* theParent, @@ -109,6 +111,24 @@ void PartSet_WidgetShapeSelector::removeExternal() DocumentPtr aDoc = myExternalObject->document(); FeaturePtr aFeature = ModelAPI_Feature::feature(myExternalObject); if (aFeature.get() != NULL) { + // 1. check whether the external object can be deleted + // It should not be deleted if there are references to the object from other features, + // which are not the sketch or a rigid constraints. + std::set aRefFeatures; + aFeature->document()->refsToFeature(aFeature, aRefFeatures, false); + std::set::const_iterator anIt = aRefFeatures.begin(), + aLast = aRefFeatures.end(); + bool aReferenceExist = false; + CompositeFeaturePtr aSketch = sketch(); + for (; anIt != aLast && !aReferenceExist; anIt++) { + FeaturePtr aFeature = (*anIt); + aReferenceExist = aFeature != aSketch && + aFeature->getKind() != SketchPlugin_ConstraintRigid::ID(); + } + if (aReferenceExist) + return; + + // 2. delete external object QObjectPtrList anObjects; anObjects.append(aFeature); // the external feature should be removed with all references, sketch feature should be ignored diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index 7498ab831..4b26dd4ee 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -562,8 +562,8 @@ void XGUI_Workshop::onFeatureRedisplayMsg(const std::shared_ptrisVisible(aObj); #ifdef DEBUG_FEATURE_REDISPLAY - QString anObjInfo = objectInfo((aObj)); - qDebug(QString("visible=%1 : display= %2").arg(isVisibleObject).arg(anObjInfo).toStdString().c_str()); + //QString anObjInfo = objectInfo((aObj)); + //qDebug(QString("visible=%1 : display= %2").arg(isVisibleObject).arg(anObjInfo).toStdString().c_str()); #endif if (isVisibleObject) { // redisplay visible object @@ -607,7 +607,11 @@ void XGUI_Workshop::onFeatureCreatedMsg(const std::shared_ptrdata() || !anObject->data()->isValid()) + continue; //ResultPartPtr aPart = std::dynamic_pointer_cast(*aIt); //if (aPart) { //aHasPart = true; @@ -1454,6 +1458,9 @@ These features will be deleted also. Would you like to continue?")).arg(aNames), aDoc->removeFeature(aFeature); } } + // the update signal should be emitted obligatory in order to have a redisplay + // signal and hide the removed presentations in the viewer + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); return true; } -- 2.39.2