Salome HOME
Debug of movement of part results
[modules/shaper.git] / src / Model / Model_Update.cpp
index 1e5bb3fed0a9da0e32f878ab40d0cbbddff24fbc..561882b7c28d3157111c3cff3df98d6bbb186620 100644 (file)
@@ -33,6 +33,7 @@
 using namespace std;
 
 Model_Update MY_UPDATER_INSTANCE;  /// the only one instance initialized on load of the library
+//#define DEB_UPDATE
 
 Model_Update::Model_Update()
 {
@@ -100,13 +101,18 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
       // created objects are always must be up to date (python box feature)
       // and updated not in internal uptation chain
       myJustUpdated.insert(*anObjIter);
+      #ifdef DEB_UPDATE
+      if ((*anObjIter)->data() && (*anObjIter)->data()->isValid()) {
+        std::cout<<"Add updated "<<(*anObjIter)->groupName()<<" "
+          <<(*anObjIter)->data()->name()<<std::endl;
+      }
+      #endif
     }
-    // this event is for solver update, not here, do not react immideately
+    // this event is for solver update, not here, do not react immediately
     if (!isOnlyResults && !(theMessage->eventID() == kMovedEvent))
       processOperation(false);
   } else if (theMessage->eventID() == kOpFinishEvent || theMessage->eventID() == kOpAbortEvent ||
       theMessage->eventID() == kOpStartEvent) {
-    myIsParamUpdated = false;
 
     if (!(theMessage->eventID() == kOpStartEvent)) {
       myIsFinish = true;
@@ -135,6 +141,7 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
     }
     // in the end of transaction everything is updated, so clear the old objects (the only one
     // place where results are cleared)
+    myIsParamUpdated = false;
     myJustUpdated.clear();
     myWaitForFinish.clear();
   }
@@ -163,6 +170,9 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin
   }
   // perform update of everything if needed
   if (!myIsExecuted) {
+    #ifdef DEB_UPDATE
+      std::cout<<"****** Start processing"<<std::endl;
+    #endif
     myIsExecuted = true;
 
     bool isAutomaticChanged = false;
@@ -176,10 +186,17 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin
     DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
     Model_Objects* anObjs = std::dynamic_pointer_cast<Model_Document>(aRootDoc)->objects();
     if (!anObjs) return;
+    // two cycles: parameters are first to process
     FeaturePtr aFeatureIter = anObjs->firstFeature();
     std::set<FeaturePtr> aProcessedFeatures; // to avoid processing twice
     for (; aFeatureIter.get(); aFeatureIter = anObjs->nextFeature(aFeatureIter)) {
-      updateFeature(aFeatureIter, aProcessedFeatures);
+      if (aFeatureIter->getKind() == "Parameter")
+        updateFeature(aFeatureIter, aProcessedFeatures);
+    }
+    aFeatureIter = anObjs->firstFeature();
+    for (; aFeatureIter.get(); aFeatureIter = anObjs->nextFeature(aFeatureIter)) {
+      if (aFeatureIter->getKind() != "Parameter")
+        updateFeature(aFeatureIter, aProcessedFeatures);
     }
 
     if (isAutomaticChanged) myIsAutomatic = false;
@@ -189,6 +206,9 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin
     static Events_Loop* aLoop = Events_Loop::loop();
     static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
     aLoop->flush(EVENT_DISP);
+    #ifdef DEB_UPDATE
+      std::cout<<"****** End processing"<<std::endl;
+    #endif
   }
 }
 
@@ -203,6 +223,9 @@ void Model_Update::updateFeature(FeaturePtr theFeature, std::set<FeaturePtr>& th
   if (theFeature->isDisabled())
     return;
 
+  #ifdef DEB_UPDATE
+    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.
@@ -219,10 +242,17 @@ void Model_Update::updateFeature(FeaturePtr theFeature, std::set<FeaturePtr>& th
 
   // composite feature must be executed after sub-features execution
   if (aCompos) {
+    // two cycles: parameters must be processed first
+    for(int a = 0; a < aCompos->numberOfSubs(); a++) {
+      FeaturePtr aSub = aCompos->subFeature(a);
+      if (aSub->getKind() == "Parameter")
+        updateFeature(aSub, theProcessed);
+    }
     // number of subs can be changed in execution: like fillet
     for(int a = 0; a < aCompos->numberOfSubs(); a++) {
       FeaturePtr aSub = aCompos->subFeature(a);
-      updateFeature(aSub, theProcessed);
+      if (aSub->getKind() != "Parameter")
+       updateFeature(aSub, theProcessed);
     }
   }
   // this checking must be after the composite feature sub-elements processing:
@@ -238,17 +268,40 @@ void Model_Update::updateFeature(FeaturePtr theFeature, std::set<FeaturePtr>& th
   if (myIsAutomatic && theFeature->data()->execState() == ModelAPI_StateMustBeUpdated)
     aJustUpdated = true;
 
+  // On abort, undo or redo execute is not needed: results in document are updated automatically
+  // But redisplay is needed: results are updated, must be also updated in the viewer.
+  if (aJustUpdated && 
+      !std::dynamic_pointer_cast<Model_Document>(theFeature->document())->executeFeatures()) {
+    if (!theFeature->isPersistentResult()) { // not persistent must be re-executed on abort, etc.
+      ModelAPI_ExecState aState = theFeature->data()->execState();
+      if (aFactory->validate(theFeature)) {
+        executeFeature(theFeature);
+      } else {
+        theFeature->eraseResults();
+        redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
+      }
+    } else {
+      redisplayWithResults(theFeature, ModelAPI_StateNothing);
+      if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) { // it is done (in the tree)
+        theFeature->data()->execState(ModelAPI_StateDone);
+      }
+    }
+    return;
+  }
+
   // execute feature if it must be updated
   if (theFeature->isPreviewNeeded() || myIsFinish) {
-    if (aJustUpdated &&
-      std::dynamic_pointer_cast<Model_Document>(theFeature->document())->executeFeatures()) {
-        ModelAPI_ExecState aState = theFeature->data()->execState();
-        if (aFactory->validate(theFeature)) {
-          executeFeature(theFeature);
-        } else {
-          theFeature->eraseResults();
-          redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
-        }
+    if (aJustUpdated) {
+      ModelAPI_ExecState aState = theFeature->data()->execState();
+      if (aFactory->validate(theFeature)) {
+        #ifdef DEB_UPDATE
+          std::cout<<"Execute Feature "<<theFeature->name()<<std::endl;
+        #endif
+        executeFeature(theFeature);
+      } else {
+        theFeature->eraseResults();
+        redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
+      }
     }
   } else { // preview is not needed => make state Done
     if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) {
@@ -267,7 +320,8 @@ void Model_Update::redisplayWithResults(FeaturePtr theFeature, const ModelAPI_Ex
   std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
   for (; aRIter != aResults.cend(); aRIter++) {
     std::shared_ptr<ModelAPI_Result> aRes = *aRIter;
-    aRes->data()->execState(theState);
+    if (!aRes->isDisabled()) // update state only for enabled results (Placement Result Part may make the original Part Result as invalid)
+      aRes->data()->execState(theState);
     if (theFeature->data()->updateID() > aRes->data()->updateID()) {
       aRes->data()->setUpdateID(theFeature->data()->updateID());
     }
@@ -295,7 +349,7 @@ ModelAPI_ExecState stateByReference(ObjectPtr theTarget, const ModelAPI_ExecStat
 
 void Model_Update::updateArguments(FeaturePtr theFeature) {
   // perform this method also for disabled features: to make "not done" state for
-  // featuers referenced to the active and modified features
+  // features referenced to the active and modified features
 
   static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
 
@@ -372,7 +426,8 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
     ObjectPtr aContext = aSel->context();
     // update argument onlt if the referenced object is changed
     if (aContext.get() && !aContext->isDisabled() && 
-      aContext->data()->updateID() > theFeature->data()->updateID()) {
+      (myJustUpdated.find(aContext) != myJustUpdated.end() ||
+      aContext->data()->updateID() > theFeature->data()->updateID())) {
         if (aState == ModelAPI_StateDone)
           aState = ModelAPI_StateMustBeUpdated;
         if (!aSel->update()) { // this must be done on execution since it may be long operation
@@ -393,7 +448,8 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
         ObjectPtr aContext = aSelAttr->context();
         // update argument onlt if the referenced object is changed
         if (aContext.get() && !aContext->isDisabled() &&
-          aContext->data()->updateID() > theFeature->data()->updateID()) {
+            (myJustUpdated.find(aContext) != myJustUpdated.end() ||
+             aContext->data()->updateID() > theFeature->data()->updateID())) {
             if (aState == ModelAPI_StateDone)
               aState = ModelAPI_StateMustBeUpdated;
             if (!aSelAttr->update()) {
@@ -436,10 +492,21 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
     // number of subs can be changed in execution: like fillet
     for(int a = 0; a < aCompos->numberOfSubs(); a++) {
       FeaturePtr aSub = aCompos->subFeature(a);
-      if (myJustUpdated.find(aSub) != myJustUpdated.end() || 
-             (aSub.get() && aSub->data()->updateID() > theFeature->data()->updateID())) {
-          if (aState == ModelAPI_StateDone)
+      if (aSub.get() && aState == ModelAPI_StateDone) {
+        if (myJustUpdated.find(aSub) != myJustUpdated.end() || 
+              (aSub->data()->updateID() > theFeature->data()->updateID())) {
+          aState = ModelAPI_StateMustBeUpdated;
+        }
+        // also check that all results of subs were updated: composite also depends on the results
+        const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
+        std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter = aResults.begin();
+        for(; aResIter != aResults.end(); aResIter++) {
+          if (aResIter->get() && (*aResIter)->data()->isValid() && !(*aResIter)->isDisabled() &&
+                (myJustUpdated.find(*aResIter) != myJustUpdated.end() || 
+                  ((*aResIter)->data()->updateID() > theFeature->data()->updateID()))) {
             aState = ModelAPI_StateMustBeUpdated;
+          }
+        }
       }
     }
   }