]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #427, 420 - crash during work through external edges.
authornds <natalia.donis@opencascade.com>
Wed, 1 Apr 2015 15:48:46 +0000 (18:48 +0300)
committernds <natalia.donis@opencascade.com>
Wed, 1 Apr 2015 15:48:46 +0000 (18:48 +0300)
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
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/PartSet/PartSet_WidgetShapeSelector.cpp
src/XGUI/XGUI_Workshop.cpp

index b6f9e3e67ee5fa6dffa1427c44f52232e1b5ddf3..2d900eb142221d089617a372e714d182ebf54aa2 100644 (file)
@@ -41,11 +41,29 @@ std::shared_ptr<ModelAPI_Attribute> 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<ModelAPI_Feature>(owner());
+    if (anOwnerFeature.get()) {
+      std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
+                                          anObject->data());
+      aData->removeBackReference(anOwnerFeature, id());
+    }
+  }
+
   if (theObject && (!myIsInitialized || myID->Get().Length() != 0 || object() != theObject)) {
     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
         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<ModelAPI_Feature>(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
index b3baaea43867efe74c0fa09eef6c3a1e6f1b1b7f..53444bb6d45845a17f5d46e7d783fec7fa0bb36f 100644 (file)
@@ -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<ModelAPI_Result> aRes = 
+    std::dynamic_pointer_cast<ModelAPI_Result>(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)) {
index 8a45cfe64bc5d8fecd62fb73db28049c2a9bde64..c057cede3f2aa85d5cb2dcc95acf7c91d8caa3b2 100644 (file)
@@ -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);
index 7352c1344cb42c50241b3fea9b8a860804f78c07..8b18658297b86d0a1874a1357fd12856422c99a9 100644 (file)
@@ -15,6 +15,8 @@
 #include <PartSet_Tools.h>
 #include <SketchPlugin_Feature.h>
 
+#include <SketchPlugin_ConstraintRigid.h>
+
 #include <XGUI_Workshop.h>
 
 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<FeaturePtr> aRefFeatures;
+      aFeature->document()->refsToFeature(aFeature, aRefFeatures, false);
+      std::set<FeaturePtr>::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
index 7498ab8317aadecd9375858cb631334984ddb6b4..4b26dd4ee8d7eab122b36123a8510c3378517f52 100644 (file)
@@ -562,8 +562,8 @@ void XGUI_Workshop::onFeatureRedisplayMsg(const std::shared_ptr<ModelAPI_ObjectU
       // Redisplay the visible object or the object of the current operation
       bool isVisibleObject = myDisplayer->isVisible(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_ptr<ModelAPI_ObjectUpd
   //bool aHasPart = false;
   bool isDisplayed = false;
   for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
-
+    ObjectPtr anObject = *aIt;
+    // the validity of the data should be checked here in order to avoid display of the objects,
+    // which were created, then deleted, but flush for the creation event happens after that
+    if (!anObject->data() || !anObject->data()->isValid())
+      continue;
     //ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*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;
 }