Salome HOME
Fix for the issue #577
[modules/shaper.git] / src / Model / Model_Objects.cpp
index 5e5151bcf79d1d8d2e73eaa43828ab11817adce6..1361a931a49baca81ba39b0b83ee3ac10d237a62 100644 (file)
@@ -43,8 +43,14 @@ static const int TAG_FEATURE_RESULTS = 2;  ///< where the results are located
 
 Model_Objects::Model_Objects(TDF_Label theMainLab) : myMain(theMainLab)
 {
+}
+
+void Model_Objects::setOwner(DocumentPtr theDoc)
+{
+  myDoc = theDoc;
   // update all fields and recreate features and result objects if needed
   synchronizeFeatures(false, true, true);
+  myHistory.clear();
 }
 
 Model_Objects::~Model_Objects()
@@ -99,11 +105,8 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT
   if (!theFeature->isAction()) {  // do not add action to the data model
     TDF_Label aFeaturesLab = featuresLabel();
     TDF_Label aFeatureLab = aFeaturesLab.NewChild();
-    initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
-    // keep the feature ID to restore document later correctly
-    TDataStd_Comment::Set(aFeatureLab, theFeature->getKind().c_str());
-    myFeatures.Bind(aFeatureLab, theFeature);
-    // store feature in the features array
+    // store feature in the features array: before "initData" because in macro features
+    // in initData it creates new features, appeared later than this
     TDF_Label aPrevFeateureLab;
     if (theAfterThis.get()) { // searching for the previous feature label
       std::shared_ptr<Model_Data> aPrevData = 
@@ -113,11 +116,19 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT
       }
     }
     AddToRefArray(aFeaturesLab, aFeatureLab, aPrevFeateureLab);
+
+    initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
+    // keep the feature ID to restore document later correctly
+    TDataStd_Comment::Set(aFeatureLab, theFeature->getKind().c_str());
+    myFeatures.Bind(aFeatureLab, theFeature);
     // event: feature is added
     static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
     ModelAPI_EventCreator::get()->sendUpdated(theFeature, anEvent);
     theFeature->setDisabled(false); // by default created feature is enabled
     updateHistory(ModelAPI_Feature::group());
+  } else { // make feature has not-null data anyway
+    theFeature->setData(Model_Data::invalidData());
+    theFeature->setDoc(myDoc);
   }
 }
 
@@ -195,14 +206,7 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature,
 void Model_Objects::removeFeature(FeaturePtr theFeature)
 {
   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theFeature->data());
-  if (aData) {
-    TDF_Label aFeatureLabel = aData->label().Father();
-    if (myFeatures.IsBound(aFeatureLabel))
-      myFeatures.UnBind(aFeatureLabel);
-    else
-      return;  // not found feature => do not remove
-
-    clearHistory(theFeature);
+  if (aData && aData->isValid()) {
     // checking that the sub-element of composite feature is removed: if yes, inform the owner
     std::set<std::shared_ptr<ModelAPI_Feature> > aRefs;
     refsToFeature(theFeature, aRefs, false);
@@ -214,16 +218,23 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
         aComposite->removeFeature(theFeature);
       }
     }
+    // this must be before erase since theFeature erasing removes all information about
+    // the feature results and groups of results
+    // To reproduce: create sketch, extrusion, remove sketch => constructions tree is not updated
+    clearHistory(theFeature);
     // erase fields
     theFeature->erase();
+
+    TDF_Label aFeatureLabel = aData->label().Father();
+    if (myFeatures.IsBound(aFeatureLabel))
+      myFeatures.UnBind(aFeatureLabel);
+
     static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
     ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
     // erase all attributes under the label of feature
     aFeatureLabel.ForgetAllAttributes();
     // remove it from the references array
-    if (theFeature->isInHistory()) {
-      RemoveFromRefArray(featuresLabel(), aFeatureLabel);
-    }
+    RemoveFromRefArray(featuresLabel(), aFeatureLabel);
     // event: feature is deleted
     ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
     // the redisplay signal should be flushed in order to erase the feature presentation in the viewer
@@ -241,8 +252,13 @@ void Model_Objects::clearHistory(ObjectPtr theObj)
       myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
     if (theObj->groupName() == ModelAPI_Feature::group()) { // clear results group of the feature
       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
-      if (aFeature->firstResult().get())
-        clearHistory(aFeature->firstResult());
+      std::string aResultGroup = featureResultGroup(aFeature);
+      if (!aResultGroup.empty()) {
+        std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = 
+          myHistory.find(aResultGroup);
+        if (aHIter != myHistory.end())
+          myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
+      }
     }
   }
 }
@@ -293,7 +309,7 @@ void Model_Objects::updateHistory(const std::string theGroup)
     myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
 }
 
-FeaturePtr Model_Objects::feature(TDF_Label& theLabel) const
+FeaturePtr Model_Objects::feature(TDF_Label theLabel) const
 {
   if (myFeatures.IsBound(theLabel))
     return myFeatures.Find(theLabel);
@@ -323,6 +339,8 @@ ObjectPtr Model_Objects::object(TDF_Label theLabel)
 
 ObjectPtr Model_Objects::object(const std::string& theGroupID, const int theIndex)
 {
+  if (theIndex == -1)
+    return ObjectPtr();
   createHistory(theGroupID);
   return myHistory[theGroupID][theIndex];
 }
@@ -361,6 +379,29 @@ int Model_Objects::size(const std::string& theGroupID)
   return myHistory[theGroupID].size();
 }
 
+void Model_Objects::allResults(const std::string& theGroupID, std::list<ResultPtr>& theResults)
+{
+  // iterate the array of references and get feature by feature from the array
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+    for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
+      FeaturePtr aFeature = feature(aRefs->Value(a));
+      if (aFeature.get()) {
+        const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
+        std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
+        for (; aRIter != aResults.cend(); aRIter++) {
+          ResultPtr aRes = *aRIter;
+          if (aRes->groupName() != theGroupID) break; // feature have only same group results
+          if (aRes->isInHistory() && !aRes->isConcealed()) {
+            theResults.push_back(*aRIter);
+          }
+        }
+      }
+    }
+  }
+}
+
+
 TDF_Label Model_Objects::featuresLabel() const
 {
   return myMain.FindChild(TAG_OBJECTS);
@@ -434,7 +475,7 @@ void Model_Objects::synchronizeFeatures(
   static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
   static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
   static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-  aLoop->activateFlushes(false);
+  bool isActive = aLoop->activateFlushes(false);
 
   // update all objects by checking are they on labels or not
   std::set<FeaturePtr> aNewFeatures, aKeptFeatures;
@@ -457,6 +498,7 @@ void Model_Objects::synchronizeFeatures(
       aNewFeatures.insert(aFeature);
       initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
       updateHistory(aFeature);
+      aFeature->setDisabled(false); // by default created feature is enabled (this allows to recreate the results before "setCurrent" is called)
 
       // event: model is updated
       ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent);
@@ -516,7 +558,7 @@ void Model_Objects::synchronizeFeatures(
   }
 
   anOwner->executeFeatures() = false;
-  aLoop->activateFlushes(true);
+  aLoop->activateFlushes(isActive);
 
   if (theFlush) {
     aLoop->flush(aCreateEvent);
@@ -571,6 +613,15 @@ void Model_Objects::synchronizeBackRefs()
             std::shared_ptr<Model_Data> aRefData = 
               std::dynamic_pointer_cast<Model_Data>((*aRefTo)->data());
             aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated
+            // update enable/disable status: the nested status must be equal to the composite
+            CompositeFeaturePtr aComp = 
+              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
+            if (aComp.get()) {
+              FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>(*aRefTo);
+              if (aReferenced.get()) {
+                aReferenced->setDisabled(aComp->isDisabled());
+              }
+            }
           }
         }
       }
@@ -712,6 +763,22 @@ std::shared_ptr<ModelAPI_Feature> Model_Objects::feature(
   return FeaturePtr();
 }
 
+std::string Model_Objects::featureResultGroup(FeaturePtr theFeature)
+{
+  if (theFeature->data()->isValid()) {
+    TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
+    if (aLabIter.More()) {
+      TDF_Label anArgLab = aLabIter.Value();
+      Handle(TDataStd_Comment) aGroup;
+      if (aLabIter.Value().FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
+        return TCollection_AsciiString(aGroup->Get()).ToCString();
+      }
+    }
+  }
+  static std::string anEmpty;
+  return anEmpty; // not found
+}
+
 void Model_Objects::updateResults(FeaturePtr theFeature)
 {
   // for not persistent is will be done by parametric updater automatically
@@ -720,10 +787,10 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
   std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
   while(aResIter != theFeature->results().cend()) {
     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(*aResIter);
-    if (aBody) {
+    if (aBody.get()) {
       if (!aBody->data()->isValid()) { 
         // found a disappeared result => remove it
-        theFeature->removeResult(aBody);
+        theFeature->eraseResultFromList(aBody);
         // start iterate from beginning because iterator is corrupted by removing
         aResIter = theFeature->results().cbegin();
         continue;
@@ -732,7 +799,7 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
     aResIter++;
   }
   // it may be on undo
-  if (!theFeature->data() || !theFeature->data()->isValid())
+  if (!theFeature->data() || !theFeature->data()->isValid() || theFeature->isDisabled())
     return;
   // check that results are presented on all labels
   int aResSize = theFeature->results().size();
@@ -748,7 +815,11 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
         if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) {
           aNewBody = createBody(theFeature->data(), aResIndex);
         } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) {
-          aNewBody = createPart(theFeature->data(), aResIndex);
+          std::shared_ptr<ModelAPI_ResultPart> aNewP = createPart(theFeature->data(), aResIndex); 
+          theFeature->setResult(aNewP, aResIndex);
+          if (!aNewP->partDoc().get())
+            theFeature->execute(); // create the part result: it is better to restore the previous result if it is possible
+          break;
         } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
           theFeature->execute(); // construction shapes are needed for sketch solver
           break;
@@ -793,7 +864,7 @@ ResultPtr Model_Objects::findByName(const std::string theName)
 FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theReverse)
 {
   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
-  if (aData) {
+  if (aData && aData->isValid()) {
     TDF_Label aFeatureLabel = aData->label().Father();
     Handle(TDataStd_ReferenceArray) aRefs;
     if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
@@ -828,6 +899,20 @@ FeaturePtr Model_Objects::lastFeature()
   return FeaturePtr(); // no features at all
 }
 
+std::list<std::shared_ptr<ModelAPI_Feature> > Model_Objects::allFeatures()
+{
+  std::list<std::shared_ptr<ModelAPI_Feature> > aResult;
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+    for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
+      FeaturePtr aFeature = feature(aRefs->Value(a));
+      if (aFeature.get())
+        aResult.push_back(aFeature);
+    }
+  }
+  return aResult;
+}
+
 Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper)
 {
   return TDF_LabelMapHasher::HashCode(theLab, theUpper);