Salome HOME
Fix for the issue #937 and crashes:
[modules/shaper.git] / src / Model / Model_Update.cpp
index 0abbf501441d9effabc1e14051668558073e8cfd..93205e353fbcb3c23a4b50db0c7326f1256e6acc 100644 (file)
@@ -33,7 +33,7 @@
 using namespace std;
 
 Model_Update MY_UPDATER_INSTANCE;  /// the only one instance initialized on load of the library
-#define DEB_UPDATE
+//#define DEB_UPDATE
 
 Model_Update::Model_Update()
 {
@@ -102,24 +102,30 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
       if ((*anObjIter)->groupName() == ModelAPI_ResultParameter::group()) {
         myIsParamUpdated = true;
       }
-      // created objects are always must be up to date (python box feature)
-      // and updated not in internal uptation chain
-      myUpdated[*anObjIter] = myModification;
-
-      // something is updated during the execution: re-execute it (sketch update by parameters or
-      // Box macro that updates the upper features during the execution)
-      if (myIsExecuted) { 
-        FeaturePtr anUpdated = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
-        if (anUpdated.get() &&  anUpdated->data()->isValid())
-          iterateUpdateBreak(anUpdated);
-      }
-      #ifdef DEB_UPDATE
-      if (myIsExecuted) std::cout<<"During execution ";
-      if ((*anObjIter)->data() && (*anObjIter)->data()->isValid()) {
-        std::cout<<"add updated "<<(*anObjIter)->groupName()<<" "
-          <<(*anObjIter)->data()->name()<<std::endl;
+      // on undo/redo, abort do not update persisten features
+      FeaturePtr anUpdated = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
+      if (std::dynamic_pointer_cast<Model_Document>((*anObjIter)->document())->executeFeatures() ||
+          (anUpdated.get() && !anUpdated->isPersistentResult())) {
+        // created objects are always must be up to date (python box feature)
+        // and updated not in internal uptation chain
+        myUpdated[*anObjIter] = myModification;
+
+        // something is updated during the execution: re-execute it (sketch update by parameters or
+        // Box macro that updates the upper features during the execution)
+        if (myIsExecuted) { 
+          FeaturePtr anUpdated = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
+          if (anUpdated.get() &&  anUpdated->data()->isValid())
+            iterateUpdateBreak(anUpdated);
+        }
+#ifdef DEB_UPDATE
+        if (myIsExecuted) std::cout<<"During execution ";
+        if ((*anObjIter)->data() && (*anObjIter)->data()->isValid()) {
+          std::cout<<"add updated "<<(*anObjIter)->groupName()<<" "
+            <<(*anObjIter)->data()->name()<<std::endl;
+        }
+#endif
       }
-      #endif
+
     }
     // this event is for solver update, not here, do not react immediately
     if (!isOnlyResults && !(theMessage->eventID() == kMovedEvent))
@@ -196,7 +202,7 @@ void Model_Update::iterateUpdateBreak(std::shared_ptr<ModelAPI_Feature> theFeatu
         }
         // for the current breaked, set iteration to this feature precisely
         aBreaked->setCurrentBefore(theFeature);
-        myModification++;
+        //myModification++;
       }
       // the iterator that contains breaked is found, so, nothing else is needed
       return;
@@ -216,7 +222,8 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin
     for(aFIter = myWaitForFinish.begin(); aFIter != myWaitForFinish.end(); aFIter++)
     {
       FeaturePtr aF = std::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter);
-      if (aF && aF->data()->isValid() && aF->getKind() == "Extrusion") {
+      if (aF && aF->data()->isValid() && 
+           (aF->getKind() == "Extrusion" || aF->getKind() == "Revolution")) {
         AttributeSelectionListPtr aBase = aF->selectionList("base");
         if (aBase.get()) {
           for(int a = aBase->size() - 1; a >= 0; a--) {
@@ -268,12 +275,14 @@ void Model_Update::updateFeature(FeaturePtr theFeature)
     return;
 
   #ifdef DEB_UPDATE
-    //std::cout<<"Update Feature "<<theFeature->name()<<std::endl;
+    std::cout<<"Update Feature "<<theFeature->name()<<std::endl;
   #endif
   CompositeFeaturePtr aCompos = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
   // If automatice update is not needed and feature attributes were not updated right now,
   // do not execute it and do not update arguments.
-  if (!myIsAutomatic && myUpdated.find(theFeature) == myUpdated.end() && !aCompos.get()) {
+  if (!myIsAutomatic && 
+       (myUpdated.find(theFeature) == myUpdated.end() || myUpdated[theFeature] != myModification)
+       && !aCompos.get()) {
     // execute will be performed later, but some features may have not-result 
     // presentations, so call update for them (like coincidence in the sketcher)
     static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
@@ -300,7 +309,14 @@ void Model_Update::updateFeature(FeaturePtr theFeature)
     return;
   }
 
+  // only the currently updated features are executed
   bool aJustUpdated = myUpdated.find(theFeature) != myUpdated.end();
+  if (aJustUpdated) {
+    // if preview is not needed, the created feature was not updated before, so, myModification is not actual for this
+    if (theFeature->isPreviewNeeded()) {
+      aJustUpdated = myUpdated[theFeature] == myModification;
+    }
+  }
 
   if (myIsAutomatic && theFeature->data()->execState() == ModelAPI_StateMustBeUpdated)
     aJustUpdated = true;
@@ -322,6 +338,10 @@ void Model_Update::updateFeature(FeaturePtr theFeature)
       if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) { // it is done (in the tree)
         theFeature->data()->execState(ModelAPI_StateDone);
       }
+      // it will be not updated with new modifications: only the currently updated features are updated
+      //if (myUpdated.find(theFeature) != myUpdated.end()) {
+      //  myUpdated.erase(theFeature); // do not update this persistent feature even in the future
+      //}
     }
     return;
   }
@@ -336,6 +356,9 @@ void Model_Update::updateFeature(FeaturePtr theFeature)
         #endif
         executeFeature(theFeature);
       } else {
+        #ifdef DEB_UPDATE
+          std::cout<<"Feature is not valid, erase results "<<theFeature->name()<<std::endl;
+        #endif
         theFeature->eraseResults();
         redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
       }
@@ -366,6 +389,23 @@ void Model_Update::redisplayWithResults(FeaturePtr theFeature, const ModelAPI_Ex
       aRes->data()->setUpdateID(theFeature->data()->updateID());
     }
     ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
+    // iterate sub-bodies of compsolid
+    ResultCompSolidPtr aComp = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aRes);
+    if (aComp.get()) {
+      int aNumSub = aComp->numberOfSubs();
+      for(int a = 0; a < aNumSub; a++) {
+        ResultPtr aSub = aComp->subResult(a);
+        if (!aSub->isDisabled()) {// update state only for enabled results (Placement Result Part may make the original Part Result as invalid)
+          aSub->data()->execState(theState);
+          if (theState == ModelAPI_StateDone) // feature become "done", so execution changed results
+            myUpdated[aSub] = myModification;
+        }
+        if (theFeature->data()->updateID() > aSub->data()->updateID()) {
+          aSub->data()->setUpdateID(theFeature->data()->updateID());
+        }
+        ModelAPI_EventCreator::get()->sendUpdated(aSub, EVENT_DISP);
+      }
+    }
   }
   // to redisplay "presentable" feature (for ex. distance constraint)
   ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
@@ -552,7 +592,8 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
   // composite feature must be executed after sub-features execution
   if (aCompos) {
     // number of subs can be changed in execution: like fillet
-    for(int a = 0; a < aCompos->numberOfSubs(); a++) {
+    int aNumSubs = aCompos->numberOfSubs();
+    for(int a = 0; a < aNumSubs; a++) {
       FeaturePtr aSub = aCompos->subFeature(a);
       if (aSub.get() && aState == ModelAPI_StateDone) {
         if (isOlder(theFeature, aSub)) {
@@ -568,6 +609,8 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
           }
         }
       }
+      if (a == aNumSubs - 1) // in case number of subs is changed, just recheck before end
+        aNumSubs = aCompos->numberOfSubs();
     }
   }
 
@@ -640,7 +683,14 @@ void Model_Update::IterationItem::next()
           break;
       }
     } else if (mySub.get()) {
-      mySub = myObjects->nextFeature(mySub);
+      while(mySub.get()) {
+        mySub = myObjects->nextFeature(mySub);
+        CompositeFeaturePtr anOwner = ModelAPI_Tools::compositeOwner(mySub);
+        // skip sub-objects, that are subs not only for this: sketch elements relatively to PartSet
+        if (!anOwner.get()) {
+          break;
+        }
+      }
     }
   }
 }