Salome HOME
Merge remote-tracking branch 'remotes/origin/EDF_2020_Lot2'
[modules/shaper.git] / src / Model / Model_Update.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <Model_Update.h>
21 #include <Model_Document.h>
22 #include <Model_Data.h>
23 #include <Model_Objects.h>
24 #include <ModelAPI_Feature.h>
25 #include <ModelAPI_Data.h>
26 #include <ModelAPI_Document.h>
27 #include <ModelAPI_Events.h>
28 #include <ModelAPI_AttributeReference.h>
29 #include <ModelAPI_AttributeRefList.h>
30 #include <ModelAPI_AttributeRefAttr.h>
31 #include <ModelAPI_AttributeSelection.h>
32 #include <ModelAPI_AttributeSelectionList.h>
33 #include <ModelAPI_Result.h>
34 #include <ModelAPI_ResultPart.h>
35 #include <ModelAPI_Validator.h>
36 #include <ModelAPI_CompositeFeature.h>
37 #include <ModelAPI_Session.h>
38 #include <ModelAPI_Tools.h>
39 #include <ModelAPI_ResultBody.h>
40 #include <ModelAPI_ResultPart.h>
41 #include <ModelAPI_ResultConstruction.h>
42 #include <GeomAPI_Shape.h>
43 #include <GeomDataAPI_Point.h>
44 #include <GeomDataAPI_Dir.h>
45 #include <GeomDataAPI_Point2D.h>
46 #include <Events_Loop.h>
47 #include <Events_LongOp.h>
48 #include <Events_InfoMessage.h>
49 #include <Config_PropManager.h>
50
51 Model_Update MY_UPDATER_INSTANCE;  /// the only one instance initialized on load of the library
52 //#define DEB_UPDATE
53
54 #ifdef DEB_UPDATE
55 #include <Locale_Convert.h>
56 #endif
57
58 Model_Update::Model_Update()
59 {
60   Events_Loop* aLoop = Events_Loop::loop();
61   static const Events_ID kChangedEvent = aLoop->eventByName("PreferenceChanged");
62   aLoop->registerListener(this, kChangedEvent);
63   static const Events_ID kCreatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED);
64   aLoop->registerListener(this, kCreatedEvent);
65   static const Events_ID kUpdatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED);
66   aLoop->registerListener(this, kUpdatedEvent);
67   static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation");
68   aLoop->registerListener(this, kOpFinishEvent);
69   static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation");
70   aLoop->registerListener(this, kOpAbortEvent);
71   static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation");
72   aLoop->registerListener(this, kOpStartEvent);
73   static const Events_ID kStabilityEvent = aLoop->eventByName(EVENT_STABILITY_CHANGED);
74   aLoop->registerListener(this, kStabilityEvent);
75   static const Events_ID kPreviewBlockedEvent = aLoop->eventByName(EVENT_PREVIEW_BLOCKED);
76   aLoop->registerListener(this, kPreviewBlockedEvent);
77   static const Events_ID kPreviewRequestedEvent = aLoop->eventByName(EVENT_PREVIEW_REQUESTED);
78   aLoop->registerListener(this, kPreviewRequestedEvent);
79   static const Events_ID kReorderEvent = aLoop->eventByName(EVENT_ORDER_UPDATED);
80   aLoop->registerListener(this, kReorderEvent);
81   static const Events_ID kUpdatedSel = aLoop->eventByName(EVENT_UPDATE_SELECTION);
82   aLoop->registerListener(this, kUpdatedSel);
83   static const Events_ID kAutoRecomp = aLoop->eventByName(EVENT_AUTOMATIC_RECOMPUTATION_ENABLE);
84   aLoop->registerListener(this, kAutoRecomp);
85
86   //  Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true";
87   myIsParamUpdated = false;
88   myIsFinish = false;
89   myIsProcessed = false;
90   myIsPreviewBlocked = false;
91   myUpdateBlocked = false;
92 }
93
94 bool Model_Update::addModified(FeaturePtr theFeature, FeaturePtr theReason) {
95
96   if (!theFeature->data()->isValid())
97     return false; // delete an extrusion created on the sketch
98
99
100   bool isNotExecuted = theFeature->isPersistentResult() &&
101     !std::dynamic_pointer_cast<Model_Document>((theFeature)->document())->executeFeatures();
102   if (isNotExecuted) {
103     redisplayWithResults(theFeature, ModelAPI_StateNothing, false); // redisplay even not executed
104     if (!theReason.get()) // no reason => no construction reason
105       return false;
106     if (myNotPersistentRefs.find(theFeature) == myNotPersistentRefs.end()) {
107       myNotPersistentRefs[theFeature].insert(theReason);
108     } else {
109       std::set<std::shared_ptr<ModelAPI_Feature> > aNewSet;
110       aNewSet.insert(theReason);
111       myNotPersistentRefs[theFeature] = aNewSet;
112     }
113     return false;
114   }
115
116   // update arguments for "apply button" state change
117   if ((!theFeature->isPreviewNeeded() && !myIsFinish) || myIsPreviewBlocked) {
118     if (theReason.get())
119       myProcessOnFinish[theFeature].insert(theReason);
120     else if (myProcessOnFinish.find(theFeature) == myProcessOnFinish.end())
121       myProcessOnFinish[theFeature] = std::set<std::shared_ptr<ModelAPI_Feature> >();
122 #ifdef DEB_UPDATE
123       std::wcout<<L"*** Add process on finish "<<theFeature->name()<<std::endl;
124 #endif
125     // keeps the currently updated features to avoid infinitive cycling here: where feature on
126     // "updateArguments" sends "updated" (in selection attribute) and goes here again
127     static std::set<FeaturePtr> aCurrentlyUpdated;
128     if (aCurrentlyUpdated.find(theFeature) == aCurrentlyUpdated.end()) {
129       aCurrentlyUpdated.insert(theFeature);
130       updateArguments(theFeature);
131       aCurrentlyUpdated.erase(theFeature);
132     }
133     // make it without conditions otherwise the apply button may have a bad state
134     theFeature->data()->execState(ModelAPI_StateDone);
135     static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
136      // need to be validated to update the "Apply" state if not previewed
137     aFactory->validate(theFeature);
138
139     // to redisplay split's arguments presentation, even result is not computed
140     if (!theFeature->isPreviewNeeded()) {
141       static Events_Loop* aLoop = Events_Loop::loop();
142       static const Events_ID kRedisplayEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
143       ModelAPI_EventCreator::get()->sendUpdated(theFeature, kRedisplayEvent);
144       aLoop->flush(kRedisplayEvent);
145     }
146
147     if (!myIsPreviewBlocked)
148       return true;
149   }
150   if (myModified.find(theFeature) != myModified.end()) {
151     if (theReason.get()) {
152 #ifdef DEB_UPDATE
153       //std::cout<<"*** Add already modified "
154       //   <<theFeature->name()<<" reason "<<theReason->name()<<std::endl;
155 #endif
156       myModified[theFeature].insert(theReason);
157     }
158     return true;
159   }
160   // do not add the disabled, but possibly the sub-elements are not disabled
161   bool aIsDisabled = theFeature->isDisabled();
162   if (!aIsDisabled) {
163     std::set<std::shared_ptr<ModelAPI_Feature> > aNewSet;
164     if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated ||
165         theFeature->data()->execState() == ModelAPI_StateInvalidArgument || // issue 1519
166         theFeature->data()->execState() == ModelAPI_StateExecFailed) {
167       // do not forget that in this case all were the reasons
168       aNewSet.insert(theFeature);
169     } else {
170       if (theReason.get())
171         aNewSet.insert(theReason);
172     }
173     myModified[theFeature] = aNewSet;
174 #ifdef DEB_UPDATE
175     if (theReason.get()) {
176       //std::cout<<"*** Add modified "<<theFeature->name()
177       //  <<" reason "<<theReason->name()<<std::endl;
178     } else {
179       //std::cout<<"*** Add modified "<<theFeature->name()<<std::endl;
180     }
181 #endif
182   } else { // will be updated during the finish of the operation, or when it becomes enabled
183     if (theFeature->data()->execState() == ModelAPI_StateDone ||
184         theFeature->data()->execState() == ModelAPI_StateExecFailed) // fix issue 1819
185       theFeature->data()->execState(ModelAPI_StateMustBeUpdated);
186     else
187       return true; // do not need iteration deeply if it is already marked as modified or so
188 #ifdef DEB_UPDATE
189     //std::cout<<"*** Set modified state "<<theFeature->name()<<std::endl;
190 #endif
191   }
192   // clear processed and fill modified recursively
193   const std::set<std::shared_ptr<ModelAPI_Attribute> >& aRefs = theFeature->data()->refsToMe();
194   std::set<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aRefIter = aRefs.cbegin();
195   for(; aRefIter != aRefs.cend(); aRefIter++) {
196     if ((*aRefIter)->isArgument()) {
197       FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIter)->owner());
198       if (aReferenced.get()) {
199         addModified(aReferenced, theFeature);
200       }
201     }
202   }
203   // process also results
204   std::list<ResultPtr> allResults; // list of this feature and results
205   ModelAPI_Tools::allResults(theFeature, allResults);
206   std::list<ResultPtr>::iterator aRes = allResults.begin();
207   for(; aRes != allResults.end(); aRes++) {
208     const std::set<std::shared_ptr<ModelAPI_Attribute> >& aResRefs = (*aRes)->data()->refsToMe();
209     std::set<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aRIter = aResRefs.cbegin();
210     for(; aRIter != aResRefs.cend(); aRIter++) {
211       if ((*aRIter)->isArgument()) {
212         FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRIter)->owner());
213         if (aReferenced.get()) {
214           addModified(aReferenced, theFeature);
215         }
216       }
217     }
218   }
219
220   // also add part feature that contains this feature to the modified
221   if (theFeature->document()->kind() != "PartSet") {
222     FeaturePtr aPart = ModelAPI_Tools::findPartFeature(
223       ModelAPI_Session::get()->moduleDocument(), theFeature->document());
224     if (aPart.get())
225       addModified(aPart, theFeature);
226   }
227   return true;
228 }
229
230 void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessage)
231 {
232   static Events_Loop* aLoop = Events_Loop::loop();
233   //static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
234   static const Events_ID kCreatedEvent = aLoop->eventByName(EVENT_OBJECT_CREATED);
235   static const Events_ID kUpdatedEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED);
236   static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation");
237   static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation");
238   static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation");
239   static const Events_ID kStabilityEvent = aLoop->eventByName(EVENT_STABILITY_CHANGED);
240   static const Events_ID kPreviewBlockedEvent = aLoop->eventByName(EVENT_PREVIEW_BLOCKED);
241   static const Events_ID kPreviewRequestedEvent = aLoop->eventByName(EVENT_PREVIEW_REQUESTED);
242   static const Events_ID kReorderEvent = aLoop->eventByName(EVENT_ORDER_UPDATED);
243   static const Events_ID kRedisplayEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
244   static const Events_ID kUpdatedSel = aLoop->eventByName(EVENT_UPDATE_SELECTION);
245
246 #ifdef DEB_UPDATE
247   std::cout<<"****** Event "<<theMessage->eventID().eventText()<<std::endl;
248 #endif
249   // check the automatic update flag on any event
250   bool aNewAutomaticState = ModelAPI_Session::get()->isAutoUpdateBlocked();
251   if (myUpdateBlocked != aNewAutomaticState) {
252     myUpdateBlocked = aNewAutomaticState;
253     if (!myUpdateBlocked) { // process all modified features, even if preview is blocked
254       bool aPreviewBlockedState = myIsPreviewBlocked; // to update the selected arguments
255       myIsPreviewBlocked = false;
256       // iterate everything and add features in state "MustBeUpdated" into modified
257       std::list<std::shared_ptr<ModelAPI_Document> > allDocs =
258         ModelAPI_Session::get()->allOpenedDocuments();
259       std::list<std::shared_ptr<ModelAPI_Document> >::iterator aDoc = allDocs.begin();
260       for(; aDoc != allDocs.end(); aDoc++) {
261         std::list<std::shared_ptr<ModelAPI_Feature> > allFeats = (*aDoc)->allFeatures();
262         std::list<std::shared_ptr<ModelAPI_Feature> >::iterator aFeat = allFeats.begin();
263         for(; aFeat != allFeats.end(); aFeat++) {
264           if ((*aFeat)->data()->isValid() &&
265             (*aFeat)->data()->execState() == ModelAPI_StateMustBeUpdated) {
266             addModified(*aFeat, FeaturePtr());
267           }
268         }
269       }
270       processFeatures();
271       myIsPreviewBlocked = aPreviewBlockedState;
272     }
273   }
274
275   if (theMessage->eventID() == kStabilityEvent) {
276     updateStability(theMessage->sender());
277     return;
278   }
279   if (theMessage->eventID() == kPreviewBlockedEvent) {
280     myIsPreviewBlocked = true;
281     return;
282   }
283   if (theMessage->eventID() == kPreviewRequestedEvent) {
284     if (myIsPreviewBlocked) {
285       bool anUpdateState = myUpdateBlocked;
286       myUpdateBlocked = false;
287       myIsPreviewBlocked = false;
288       processFeatures();
289       myIsPreviewBlocked = true;
290       myUpdateBlocked = anUpdateState;
291     }
292     return;
293   }
294   if (theMessage->eventID() == kUpdatedSel) {
295     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
296         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
297     updateSelection(aMsg->objects());
298   }
299   // creation is added to "update" to avoid recomputation twice:
300   // on create and immediately after on update
301   if (theMessage->eventID() == kCreatedEvent) {
302     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
303         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
304     const std::set<ObjectPtr>& anObjs = aMsg->objects();
305     std::set<ObjectPtr>::const_iterator anObjIter = anObjs.cbegin();
306     std::list<ObjectPtr> aFeatures, aResults;
307     for(; anObjIter != anObjs.cend(); anObjIter++) {
308       if (std::dynamic_pointer_cast<Model_Document>((*anObjIter)->document())->executeFeatures()) {
309         if ((*anObjIter)->groupName() == ModelAPI_Feature::group()) {
310           // results creation means enabling, not update
311           aFeatures.push_back(*anObjIter);
312         } else {
313           aResults.push_back(*anObjIter);
314           ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*anObjIter);
315           if (aPart.get() && aPart->data().get() && aPart->data()->isValid()) {
316             aPart->shape(); // to update the shape on creation of the result
317           }
318         }
319       }
320     }
321     ModelAPI_EventCreator::get()->sendUpdated(aFeatures, kUpdatedEvent);
322     ModelAPI_EventCreator::get()->sendUpdated(aResults, kRedisplayEvent);
323     return;
324   }
325   if (theMessage->eventID() == kUpdatedEvent) {
326     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
327         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
328     const std::set<ObjectPtr>& anObjs = aMsg->objects();
329     std::set<ObjectPtr>::const_iterator anObjIter = anObjs.cbegin();
330     bool aSomeModified = false; // check that features not changed: only redisplay is needed
331     for(; anObjIter != anObjs.cend(); anObjIter++) {
332       if (!(*anObjIter)->data()->isValid())
333         continue;
334 #ifdef DEB_UPDATE
335       std::wcout<<L">>> in event updated "<<Locale::Convert::toWString((*anObjIter)->groupName())
336                 <<L" "<<(*anObjIter)->data()->name()<<std::endl;
337 #endif
338       if ((*anObjIter)->groupName() == ModelAPI_ResultParameter::group()) {
339         myIsParamUpdated = true;
340       }
341       // on undo/redo, abort do not update persistent features
342       FeaturePtr anUpdated = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
343       if (anUpdated.get()) {
344         if (addModified(anUpdated, FeaturePtr()))
345           aSomeModified = true;
346         if (myUpdateBlocked) { // execute this feature anyway to show the current result
347           /*if (!anUpdated->isStable() && anUpdated->results().size() && (
348               anUpdated->firstResult()->groupName() == ModelAPI_ResultBody::group() ||
349               anUpdated->firstResult()->groupName() == ModelAPI_ResultPart::group())) {
350             if (aFactory->validate(anUpdated)) {
351               executeFeature(anUpdated);
352               redisplayWithResults(anUpdated, ModelAPI_StateNothing, false);
353               static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
354               aLoop->flush(EVENT_DISP);
355             }
356           }*/
357         }
358       } else {
359         // process the updated result as update of features that refers to this result
360         const std::set<std::shared_ptr<ModelAPI_Attribute> >&
361           aRefs = (*anObjIter)->data()->refsToMe();
362         std::set<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aRefIter = aRefs.cbegin();
363         FeaturePtr aReason;
364         ResultPtr aReasonResult = std::dynamic_pointer_cast<ModelAPI_Result>(*anObjIter);
365         if (aReasonResult.get())
366           aReason = (*anObjIter)->document()->feature(aReasonResult);
367         for(; aRefIter != aRefs.cend(); aRefIter++) {
368           if (!(*aRefIter)->owner()->data()->isValid())
369             continue;
370           anUpdated = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIter)->owner());
371           if (anUpdated.get()) {
372             if (addModified(anUpdated, aReason))
373               aSomeModified = true;
374           }
375         }
376       }
377     }
378     // this event is for solver update, not here, do not react immediately
379     if (aSomeModified) {
380         processFeatures();
381     }
382   } else if (theMessage->eventID() == kOpFinishEvent || theMessage->eventID() == kOpAbortEvent ||
383       theMessage->eventID() == kOpStartEvent) {
384     myIsPreviewBlocked = false;
385
386     if (theMessage->eventID() == kOpFinishEvent) {// if update is blocked, skip
387       myIsFinish = true;
388       // add features that wait for finish as modified
389       std::map<std::shared_ptr<ModelAPI_Feature>, std::set<std::shared_ptr<ModelAPI_Feature> > >::
390         iterator aFeature = myProcessOnFinish.begin();
391       for(; aFeature != myProcessOnFinish.end(); aFeature++) {
392         if (aFeature->first->data()->isValid()) {// there may be already removed while wait
393           if (aFeature->second.empty()) {
394             addModified(aFeature->first, FeaturePtr());
395             continue;
396           }
397           std::set<std::shared_ptr<ModelAPI_Feature> >::iterator aReasons;
398           for(aReasons = aFeature->second.begin(); aReasons != aFeature->second.end(); aReasons++){
399             addModified(aFeature->first, *aReasons);
400           }
401         }
402       }
403       myIsFinish = false;
404     }
405     // processed features must be only on finish, so clear anyway (to avoid re-import on load)
406     myProcessOnFinish.clear();
407
408     // #2156: current must be sketch, left after the macro execution
409     DocumentPtr anActiveDoc = ModelAPI_Session::get()->activeDocument();
410     FeaturePtr aCurrent;
411     if (anActiveDoc.get())
412       aCurrent = anActiveDoc->currentFeature(false);
413
414     if (!(theMessage->eventID() == kOpStartEvent)) {
415       processFeatures(false);
416     }
417
418     if (anActiveDoc.get() && aCurrent.get() && aCurrent->data()->isValid()) {
419       if (anActiveDoc->currentFeature(false) != aCurrent &&
420           ModelAPI_Tools::compositeOwner(anActiveDoc->currentFeature(false)) == aCurrent)
421         anActiveDoc->setCurrentFeature(aCurrent, false); // #2156 make the current feature back
422     }
423
424     // remove all macros before clearing all created
425     std::set<FeaturePtr>::iterator anUpdatedIter = myWaitForFinish.begin();
426     while(anUpdatedIter != myWaitForFinish.end()) {
427       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anUpdatedIter);
428       if (aFeature.get()) {
429         // remove macro on finish
430         if (aFeature->isMacro()) {
431           aFeature->document()->removeFeature(aFeature);
432           myWaitForFinish.erase(aFeature);
433         }
434         // to avoid the map update problems on "remove"
435         if (myWaitForFinish.find(aFeature) == myWaitForFinish.end()) {
436           anUpdatedIter = myWaitForFinish.begin();
437         } else {
438           anUpdatedIter++;
439         }
440       } else {
441         anUpdatedIter++;
442       }
443     }
444     // the redisplay signal should be flushed in order
445     // to erase the feature presentation in the viewer
446     // if should be done after removeFeature() of document,
447     // by this reason, upper processFeatures() do not perform this flush
448     Events_Loop::loop()->flush(kRedisplayEvent);
449
450     // in the end of transaction everything is updated, so clear the old objects
451     //myIsParamUpdated = false; // to avoid problems in sprocket.py parameter update
452     myWaitForFinish.clear();
453   } else if (theMessage->eventID() == kReorderEvent) {
454     std::shared_ptr<ModelAPI_OrderUpdatedMessage> aMsg =
455       std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
456     if (aMsg->reordered().get())
457       addModified(aMsg->reordered(), aMsg->reordered()); // to update all attributes
458   }
459 }
460
461 void Model_Update::processFeatures(const bool theFlushRedisplay)
462 {
463    // perform update of everything if it is not performed right now or any preview is blocked
464   if (!myIsProcessed && !myIsPreviewBlocked) {
465     myIsProcessed = true;
466     #ifdef DEB_UPDATE
467       std::cout<<"****** Start processing"<<std::endl;
468     #endif
469
470     while(!myModified.empty()) {
471       processFeature(myModified.begin()->first);
472     }
473     myIsProcessed = false;
474
475     // to update the object browser if something is updated/created during executions
476     static Events_Loop* aLoop = Events_Loop::loop();
477     static const Events_ID kCreatedEvent= aLoop->eventByName(EVENT_OBJECT_CREATED);
478     aLoop->flush(kCreatedEvent);
479     static const Events_ID kUpdatedEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED);
480     aLoop->flush(kUpdatedEvent);
481
482     // flush to update display
483     if (theFlushRedisplay) {
484       static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
485       aLoop->flush(EVENT_DISP);
486     }
487     #ifdef DEB_UPDATE
488       std::cout<<"****** End processing"<<std::endl;
489     #endif
490     myProcessed.clear();
491   }
492 }
493
494 // collects all the features this feature depends on: reasons
495 static void allReasons(FeaturePtr theFeature, std::set<FeaturePtr>& theReasons) {
496   std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aDeps;
497   theFeature->data()->referencesToObjects(aDeps);
498   std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > >::iterator
499     anAttrsIter = aDeps.begin();
500   for(; anAttrsIter != aDeps.end(); anAttrsIter++) {
501     if (theFeature->attribute(anAttrsIter->first)->isArgument()) {
502       std::list<std::shared_ptr<ModelAPI_Object> >::iterator aDepIter = anAttrsIter->second.begin();
503       for(; aDepIter != anAttrsIter->second.end(); aDepIter++) {
504         FeaturePtr aDepFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(*aDepIter);
505         if (!aDepFeat.get()) { // so, it depends on the result and process the feature owner of it
506           ResultPtr aDepRes = std::dynamic_pointer_cast<ModelAPI_Result>(*aDepIter);
507           if (aDepRes.get()) {
508             aDepFeat = (*aDepIter)->document()->feature(aDepRes);
509           }
510         }
511         if (aDepFeat.get() && aDepFeat->data()->isValid()) {
512           theReasons.insert(aDepFeat);
513         }
514       }
515     }
516   }
517   if (theFeature->getKind() == "Part") {
518     // part is not depended on its subs directly, but subs must be iterated anyway
519     CompositeFeaturePtr aPart = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
520     int aNum = aPart->numberOfSubs();
521     for(int a = 0; a < aNum; a++) {
522       FeaturePtr aSub = aPart->subFeature(a);
523       if (aSub.get() && aSub->data()->isValid()) {
524         theReasons.insert(aSub);
525       }
526     }
527   }
528 }
529
530 bool Model_Update::processFeature(FeaturePtr theFeature)
531 {
532   static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
533
534   if (!theFeature->data()->isValid()) { // deleted feature, just remove from all containers
535     if (myModified.find(theFeature) != myModified.end())
536       myModified.erase(theFeature);
537     return false;
538   }
539
540   if (theFeature->isPersistentResult()) {
541     if (!std::dynamic_pointer_cast<Model_Document>((theFeature)->document())->executeFeatures())
542       return false;
543   }
544
545   // check this feature is not yet checked or processed
546   bool aIsModified = myModified.find(theFeature) != myModified.end();
547   if (!aIsModified && myIsFinish) { // get info about the modification for features without preview
548     if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) {
549       aIsModified = true;
550       std::set<std::shared_ptr<ModelAPI_Feature> > aNewSet;
551       // contains itself, so, we don't know which was the reason and the reason is any
552       aNewSet.insert(theFeature);
553       myModified[theFeature] = aNewSet;
554     }
555   }
556
557   if (myProcessed.find(theFeature) == myProcessed.end()) {
558     myProcessed[theFeature] = 0;
559   } else if (aIsModified) {
560     int aCount = myProcessed[theFeature];
561     if (aCount > 100) {
562       // too many repetition of processing (in VS it may crash on 330 with stack overflow)
563       Events_InfoMessage("Model_Update",
564         "Feature '%1' is updated in infinitive loop").arg(theFeature->data()->name()).send();
565       // to stop iteration
566       myModified.clear();
567       return false;
568     }
569     myProcessed[theFeature] = aCount + 1;
570   }
571
572 #ifdef DEB_UPDATE
573     std::wcout<<L"* Process feature "<<theFeature->name()<<std::endl;
574 #endif
575
576   // update the sketch plane before the sketch sub-elements are recomputed
577   // (otherwise sketch will update plane, modify subs, after executed, but with old subs edges)
578     if (aIsModified && theFeature->getKind() == "Sketch") {
579 #ifdef DEB_UPDATE
580       std::wcout << L"****** Update sketch args " << theFeature->name() << std::endl;
581 #endif
582       AttributeSelectionPtr anExtSel = theFeature->selection("External");
583       if (anExtSel.get()) {
584         ResultPtr aContext = anExtSel->context();
585         if (aContext.get() && aContext->document().get()) {
586           FeaturePtr anExtBase = aContext->document()->feature(aContext);
587           if (anExtBase.get()) {
588             processFeature(anExtBase);
589           }
590           std::shared_ptr<GeomDataAPI_Point> anOrigin =
591             std::dynamic_pointer_cast<GeomDataAPI_Point>(theFeature->attribute("Origin"));
592           double anOX = anOrigin->x(), anOY = anOrigin->y(), anOZ = anOrigin->z();
593           std::shared_ptr<GeomDataAPI_Dir> aDir =
594             std::dynamic_pointer_cast<GeomDataAPI_Dir>(theFeature->attribute("DirX"));
595           double aDX = aDir->x(), aDY = aDir->y(), aDZ = aDir->z();
596           std::shared_ptr<GeomDataAPI_Dir> aNorm =
597             std::dynamic_pointer_cast<GeomDataAPI_Dir>(theFeature->attribute("Norm"));
598           double aNX = aNorm->x(), aNY = aNorm->y(), aNZ = aNorm->z();
599           // update sketch plane
600           updateArguments(theFeature);
601           theFeature->attributeChanged("External"); // to recompute origin, direction and normal
602           // check it is updated, so all must be changed
603           if (anOrigin->x() != anOX || anOrigin->y() != anOY || anOrigin->z() != anOZ ||
604               aDir->x() != aDX || aDir->y() != aDY || aDir->z() != aDZ ||
605               aNorm->x() != aNX || aNorm->y() != aNY || aNorm->z() != aNZ)
606           {
607             std::set<FeaturePtr> aWholeR;
608             allReasons(theFeature, aWholeR);
609             std::set<FeaturePtr>::iterator aRIter = aWholeR.begin();
610             for (; aRIter != aWholeR.end(); aRIter++) {
611               if ((*aRIter)->data()->selection("External").get())
612                 (*aRIter)->attributeChanged("External");
613             }
614           }
615         }
616       }
617     }
618
619   if (!aIsModified) { // no modification is needed
620     return false;
621   }
622
623   // evaluate parameter before the sub-elements update:
624   // it updates dependencies on evaluation (#1085)
625   if (theFeature->getKind() == "Parameter") {
626     theFeature->execute();
627   }
628
629   bool isReferencedInvalid = false;
630   // check all features this feature depended on (recursive call of updateFeature)
631   std::set<FeaturePtr>& aReasons = myModified[theFeature];
632   bool allSubsUsed = aReasons.find(theFeature) != aReasons.end();
633   if (allSubsUsed) {
634     // add all subs in aReasons and temporary remove "theFeature" to avoid processing itself
635     allReasons(theFeature, aReasons);
636     aReasons.erase(theFeature);
637   }
638   // take reasons one by one (they may be added during the feature process
639   // (circle by the radius of sketch)
640   std::set<FeaturePtr> aProcessedReasons;
641   while(!aReasons.empty()) {
642     FeaturePtr aReason = *(aReasons.begin());
643 #ifdef DEB_UPDATE
644     //cout<<theFeature->name()<<" process next reason "<<aReason->name()<<endl;
645 #endif
646     if (aReason != theFeature && (aReason)->data()->isValid()) {
647       if (processFeature(aReason))
648         aIsModified = true;
649       // check validity of aReason once again because it may be removed by dependent feature
650       // (e.g. by SketchPlugin_IntersectionPoint)
651       if (!aReason->data()->isValid() ||
652           aReason->data()->execState() == ModelAPI_StateInvalidArgument)
653         isReferencedInvalid = true;
654     }
655     // searching for the next not used reason
656     aProcessedReasons.insert(aReason);
657     // check theFeature is still in the list of modified, because it may be removed sometimes
658     // while updating SketchPlugin_Ellipse
659     if (myModified.find(theFeature) != myModified.end())
660       aReasons.erase(aReason);
661     else
662       break;
663   }
664   // restore the modified reasons: they will be used in the update of arguments
665   if (allSubsUsed) { // restore theFeature in this set
666     aProcessedReasons.insert(theFeature);
667   }
668   myModified[theFeature] = aProcessedReasons;
669
670   // do not execute the composite that contains the current
671   bool isPostponedMain = false;
672   CompositeFeaturePtr aCompos = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
673   if (theFeature->getKind() == "ExtrusionSketch" && aCompos.get()) {
674     CompositeFeaturePtr aCurrentOwner =
675       ModelAPI_Tools::compositeOwner(theFeature->document()->currentFeature(false));
676     isPostponedMain = aCurrentOwner.get() && aCompos->isSub(aCurrentOwner);
677   } else if (theFeature->getKind() == "Sketch" &&
678     std::dynamic_pointer_cast<Model_Document>((theFeature)->document())->executeFeatures()) {
679     // send event that sketch is prepared to be recomputed
680     static Events_ID anID = Events_Loop::eventByName("SketchPrepared");
681     std::shared_ptr<Events_Message> aMsg(new Events_Message(anID, this));
682     Events_Loop* aLoop = Events_Loop::loop();
683     // in case it is finish operation, flush for the sketch other events (#2450)
684     aLoop->flush(aLoop->eventByName(EVENT_OBJECT_UPDATED));
685     aLoop->send(aMsg);
686     // check that sub-elements of sketch are updated => sketch must be re-processed
687     std::set<FeaturePtr> aWholeR;
688     allReasons(theFeature, aWholeR);
689     std::set<FeaturePtr>::iterator aRIter = aWholeR.begin();
690     for(; aRIter != aWholeR.end(); aRIter++) {
691       if (myModified.find(*aRIter) != myModified.end()) {
692         processFeature(theFeature);
693         return true;
694       }
695     }
696   }
697
698 #ifdef DEB_UPDATE
699   std::wcout<<L"Update args "<<theFeature->name()<<std::endl;
700 #endif
701   // TestImport.py : after arguments are updated, theFeature may be removed
702   if (!theFeature->data()->isValid())
703     return false;
704   // Update selection and parameters attributes first, before sub-features analysis (sketch plane).
705   updateArguments(theFeature);
706
707   // add this feature to the processed right now to be able remove it from this list on
708   // update signal during this feature execution
709   myModified.erase(theFeature);
710   if (myNotPersistentRefs.find(theFeature) != myNotPersistentRefs.end())
711     myNotPersistentRefs.erase(theFeature);
712   if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated)
713     theFeature->data()->execState(ModelAPI_StateDone);
714
715   // this checking must be after the composite feature sub-elements processing:
716   // composite feature status may depend on it's sub-elements
717   if ((theFeature->data()->execState() == ModelAPI_StateInvalidArgument || isReferencedInvalid) &&
718     theFeature->getKind() != "Part") {
719       // don't disable Part because it will make disabled all the features
720       // (performance and problems with the current feature)
721   #ifdef DEB_UPDATE
722     std::wcout<<L"Invalid args "<<theFeature->name()<<std::endl;
723   #endif
724     theFeature->eraseResults(false);
725     redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
726     return true; // so, feature is modified (results are erased)
727   }
728
729   // execute feature if it must be updated
730   ModelAPI_ExecState aState = theFeature->data()->execState();
731   if (aFactory->validate(theFeature)) {
732     if (!isPostponedMain) {
733       bool aDoExecute = true;
734       if (myUpdateBlocked) {
735         if (!theFeature->isStable()) {
736           aDoExecute = true;
737         } else if (theFeature->results().size()) { // execute only not persistent results features
738           aDoExecute = !theFeature->isPersistentResult();
739         } else {
740           aDoExecute = aState != ModelAPI_StateInvalidArgument;
741         }
742       }
743       if (aDoExecute) {
744         executeFeature(theFeature);
745       } else {
746         // store information that this feature must be executed later
747         theFeature->data()->execState(ModelAPI_StateMustBeUpdated);
748       }
749     }
750   } else {
751     #ifdef DEB_UPDATE
752       std::wcout<<L"Feature is not valid, erase results "<<theFeature->name()<<std::endl;
753     #endif
754     theFeature->eraseResults(false);
755     redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
756   }
757   return true;
758 }
759
760 void Model_Update::redisplayWithResults(
761   FeaturePtr theFeature, const ModelAPI_ExecState theState, bool theUpdateState)
762 {
763   // make updated and redisplay all results
764   static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
765
766   std::list<ResultPtr> allResults;
767   ModelAPI_Tools::allResults(theFeature, allResults);
768   std::list<ResultPtr>::iterator aRIter = allResults.begin();
769   for (; aRIter != allResults.cend(); aRIter++) {
770     std::shared_ptr<ModelAPI_Result> aRes = *aRIter;
771     if (!aRes->isDisabled()) {
772       // update state only for enabled results
773       // (Placement Result Part may make the original Part Result as invalid)
774       if (theUpdateState)
775         aRes->data()->execState(theState);
776     }
777     if (theFeature->data()->updateID() > aRes->data()->updateID()) {
778       aRes->data()->setUpdateID(theFeature->data()->updateID());
779     }
780     ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
781   }
782   // to redisplay "presentable" feature (for ex. distance constraint)
783   ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
784   if (theUpdateState)
785     theFeature->data()->execState(theState);
786 }
787
788 /// Updates the state by the referenced object: if something bad with it, set state for this one
789 ModelAPI_ExecState stateByReference(ObjectPtr theTarget, const ModelAPI_ExecState theCurrent)
790 {
791   if (theTarget) {
792     ModelAPI_ExecState aRefState = theTarget->data()->execState();
793     if (aRefState == ModelAPI_StateMustBeUpdated) {
794       if (theCurrent == ModelAPI_StateDone)
795         return ModelAPI_StateMustBeUpdated;
796     } else if (aRefState != ModelAPI_StateDone) {
797       return ModelAPI_StateInvalidArgument;
798     }
799   }
800   return theCurrent;
801 }
802
803 void Model_Update::updateArguments(FeaturePtr theFeature) {
804   // perform this method also for disabled features: to make "not done" state for
805   // features referenced to the active and modified features
806   static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
807
808   ModelAPI_ExecState aState = theFeature->data()->execState();
809   if (aState == ModelAPI_StateExecFailed) { // try again failed feature: issue 577
810     aState = ModelAPI_StateMustBeUpdated;
811   }
812   if (aState == ModelAPI_StateInvalidArgument) // a chance to be corrected
813     aState = ModelAPI_StateMustBeUpdated;
814   // check the parameters state
815   // Integer
816   {
817     std::list<AttributePtr> anAttrinbutes =
818       theFeature->data()->attributes(ModelAPI_AttributeInteger::typeId());
819     std::list<AttributePtr>::iterator anIter = anAttrinbutes.begin();
820     for(; anIter != anAttrinbutes.end(); anIter++) {
821       AttributeIntegerPtr anAttribute =
822         std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(*anIter);
823       if (anAttribute.get() && !anAttribute->text().empty()) {
824         if (myIsParamUpdated) {
825           ModelAPI_AttributeEvalMessage::send(anAttribute, this);
826         }
827         if (anAttribute->expressionInvalid()) {
828           aState = ModelAPI_StateInvalidArgument;
829         }
830       }
831     }
832   }
833   // Double
834   {
835     std::list<AttributePtr> aDoubles =
836       theFeature->data()->attributes(ModelAPI_AttributeDouble::typeId());
837     std::list<AttributePtr>::iterator aDoubleIter = aDoubles.begin();
838     for(; aDoubleIter != aDoubles.end(); aDoubleIter++) {
839       AttributeDoublePtr aDouble =
840         std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(*aDoubleIter);
841       if (aDouble.get() && !aDouble->text().empty()) {
842         if (myIsParamUpdated) {
843           ModelAPI_AttributeEvalMessage::send(aDouble, this);
844         }
845         if (aDouble->expressionInvalid()) {
846           aState = ModelAPI_StateInvalidArgument;
847         }
848       }
849     }
850   }
851   // Point
852   {
853     std::list<AttributePtr> anAttributes =
854       theFeature->data()->attributes(GeomDataAPI_Point::typeId());
855     std::list<AttributePtr>::iterator anIter = anAttributes.begin();
856     for(; anIter != anAttributes.end(); anIter++) {
857       AttributePointPtr aPointAttribute =
858         std::dynamic_pointer_cast<GeomDataAPI_Point>(*anIter);
859       if (aPointAttribute.get() && (!aPointAttribute->textX().empty() ||
860           !aPointAttribute->textY().empty() || !aPointAttribute->textZ().empty())) {
861         if (myIsParamUpdated) {
862           ModelAPI_AttributeEvalMessage::send(aPointAttribute, this);
863         }
864         if ((!aPointAttribute->textX().empty() && aPointAttribute->expressionInvalid(0)) ||
865           (!aPointAttribute->textY().empty() && aPointAttribute->expressionInvalid(1)) ||
866           (!aPointAttribute->textZ().empty() && aPointAttribute->expressionInvalid(2)))
867           aState = ModelAPI_StateInvalidArgument;
868       }
869     }
870   }
871   // Point2D
872   {
873     std::list<AttributePtr> anAttributes =
874       theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
875     std::list<AttributePtr>::iterator anIter = anAttributes.begin();
876     for(; anIter != anAttributes.end(); anIter++) {
877       AttributePoint2DPtr aPoint2DAttribute =
878         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIter);
879       if (aPoint2DAttribute.get()) {
880         if (myIsParamUpdated && (!aPoint2DAttribute->textX().empty() ||
881             !aPoint2DAttribute->textY().empty())) {
882           ModelAPI_AttributeEvalMessage::send(aPoint2DAttribute, this);
883         }
884         if ((!aPoint2DAttribute->textX().empty() && aPoint2DAttribute->expressionInvalid(0)) ||
885           (!aPoint2DAttribute->textY().empty() && aPoint2DAttribute->expressionInvalid(1)))
886           aState = ModelAPI_StateInvalidArgument;
887       }
888     }
889   }
890   // update the selection attributes if any
891   std::list<AttributePtr> aRefs =
892     theFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
893   std::list<AttributePtr>::iterator aRefsIter = aRefs.begin();
894   for (; aRefsIter != aRefs.end(); aRefsIter++) {
895     std::shared_ptr<ModelAPI_AttributeSelection> aSel =
896       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*aRefsIter);
897     ObjectPtr aContext = aSel->context();
898     // update argument only if the referenced object is ready to use
899     if (aContext.get() && !aContext->isDisabled()) {
900       if (isReason(theFeature, aContext)) {
901         if (!aSel->update()) { // this must be done on execution since it may be long operation
902           bool isObligatory = !aFactory->isNotObligatory(
903             theFeature->getKind(), theFeature->data()->id(aSel)) &&
904             aFactory->isCase(theFeature, theFeature->data()->id(aSel));
905           if (isObligatory)
906             aState = ModelAPI_StateInvalidArgument;
907         }
908       }
909     } else if (aContext.get()) {
910       // here it may be not obligatory, but if the reference is wrong, it should not be correct
911       bool isObligatory = aFactory->isCase(theFeature, theFeature->data()->id(aSel));
912       if (isObligatory)
913         aState = ModelAPI_StateInvalidArgument;
914     } else if (theFeature->getKind() == "Sketch" && aSel->id() == "External" &&
915                aSel->isInitialized()) {
916       // #19703 : if sketch plane was selected, but after context disappears, it must become invalid
917       aSel->update();
918       if (aSel->isInvalid()) {
919           aState = ModelAPI_StateInvalidArgument;
920       }
921     }
922   }
923   // update the selection list attributes if any
924   aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
925   for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
926     std::shared_ptr<ModelAPI_AttributeSelectionList> aSel =
927       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aRefsIter);
928     // #19071 : avoid sending of update event in cycle
929     bool aWasBlocked = theFeature->data()->blockSendAttributeUpdated(true);
930     // list to keep the shared pointers while update is blocked (in messages raw poiters are used)
931     std::list<AttributeSelectionPtr> anAttrList;
932     for(int a = aSel->size() - 1; a >= 0; a--) {
933       std::shared_ptr<ModelAPI_AttributeSelection> aSelAttr =
934         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aSel->value(a));
935       if (aSelAttr) {
936         ObjectPtr aContext = aSelAttr->context();
937         // update argument only if the referenced object is ready to use
938         if (aContext.get() && !aContext->isDisabled()) {
939           if (isReason(theFeature, aContext)) {
940             anAttrList.push_back(aSelAttr);
941             if (!aSelAttr->update()) {
942               bool isObligatory = !aFactory->isNotObligatory(
943                 theFeature->getKind(), theFeature->data()->id(aSel)) &&
944                 aFactory->isCase(theFeature, theFeature->data()->id(aSel));
945               if (isObligatory)
946                 aState = ModelAPI_StateInvalidArgument;
947             }
948           }
949         } else if (aContext.get()) {
950           // here it may be not obligatory, but if the reference is wrong, it should not be correct
951           bool isObligatory = aFactory->isCase(theFeature, theFeature->data()->id(aSel));
952           if (isObligatory)
953             aState = ModelAPI_StateInvalidArgument;
954         }
955       }
956     }
957     if (!aWasBlocked)
958       theFeature->data()->blockSendAttributeUpdated(false);
959   }
960
961   if (aState != ModelAPI_StateDone)
962     theFeature->data()->execState(aState);
963 }
964
965 bool Model_Update::isReason(std::shared_ptr<ModelAPI_Feature>& theFeature,
966      std::shared_ptr<ModelAPI_Object> theReason)
967 {
968   std::map<std::shared_ptr<ModelAPI_Feature>, std::set<std::shared_ptr<ModelAPI_Feature> > >
969     ::iterator aReasonsIt = myModified.find(theFeature);
970   if (aReasonsIt != myModified.end()) {
971     if (aReasonsIt->second.find(theFeature) != aReasonsIt->second.end())
972       return true; // any is reason if it contains itself
973     FeaturePtr aReasFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(theReason);
974     if (!aReasFeat.get()) { // try to get feature of this result
975       ResultPtr aReasRes = std::dynamic_pointer_cast<ModelAPI_Result>(theReason);
976       if (aReasRes.get())
977         aReasFeat = theReason->document()->feature(aReasRes);
978     }
979     if (aReasonsIt->second.find(aReasFeat) != aReasonsIt->second.end())
980       return true;
981   }
982   // another try: postponed modification by not-persistences
983   std::map<std::shared_ptr<ModelAPI_Feature>, std::set<std::shared_ptr<ModelAPI_Feature> > >
984     ::iterator aNotPersist = myNotPersistentRefs.find(theFeature);
985   if (aNotPersist != myNotPersistentRefs.end()) {
986     FeaturePtr aReasFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(theReason);
987     if (!aReasFeat.get()) { // try to get feature of this result
988       ResultPtr aReasRes = std::dynamic_pointer_cast<ModelAPI_Result>(theReason);
989       if (aReasRes.get())
990         aReasFeat = theReason->document()->feature(aReasRes);
991     }
992     if (aNotPersist->second.find(aReasFeat) != aNotPersist->second.end())
993       return true;
994   }
995
996   // this case only for not-previewed items update state, nothing is changed in args for it
997   return false;
998 }
999
1000 void Model_Update::executeFeature(FeaturePtr theFeature)
1001 {
1002 #ifdef DEB_UPDATE
1003   std::wcout<<L"Execute Feature "<<theFeature->name()<<std::endl;
1004 #endif
1005   // execute in try-catch to avoid internal problems of the feature
1006   ModelAPI_ExecState aState = ModelAPI_StateDone;
1007   theFeature->data()->execState(ModelAPI_StateDone);
1008   try {
1009     theFeature->execute();
1010     if (theFeature->data()->execState() != ModelAPI_StateDone) {
1011       aState = ModelAPI_StateExecFailed;
1012     } else {
1013       aState = ModelAPI_StateDone;
1014     }
1015   } catch(...) {
1016     aState = ModelAPI_StateExecFailed;
1017     Events_InfoMessage("Model_Update",
1018       "Feature %1 has failed during the execution").arg(theFeature->getKind()).send();
1019   }
1020   // The macro feature has to be deleted in any case even its execution is failed
1021   myWaitForFinish.insert(theFeature);
1022   if (aState != ModelAPI_StateDone) {
1023     theFeature->eraseResults(false);
1024   }
1025   theFeature->data()->setUpdateID(ModelAPI_Session::get()->transactionID());
1026   redisplayWithResults(theFeature, aState);
1027 }
1028
1029 // it is called on GUI edit of feature start
1030 // LCOV_EXCL_START
1031 void Model_Update::updateStability(void* theSender)
1032 {
1033   static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
1034   if (theSender) {
1035     bool added = false; // object may be was crated
1036     ModelAPI_Object* aSender = static_cast<ModelAPI_Object*>(theSender);
1037     if (aSender && aSender->document()) {
1038       FeaturePtr aFeatureSender =
1039         std::dynamic_pointer_cast<ModelAPI_Feature>(aSender->data()->owner());
1040       if (aFeatureSender.get()) {
1041         Model_Objects* aDocObjects =
1042           std::dynamic_pointer_cast<Model_Document>(aSender->document())->objects();
1043         if (aDocObjects) {
1044           //aDocObjects->synchronizeBackRefs();
1045           // remove or add all concealment refs from this feature
1046           std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
1047           aSender->data()->referencesToObjects(aRefs);
1048           std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator
1049             aRefIt = aRefs.begin();
1050           for(; aRefIt != aRefs.end(); aRefIt++) {
1051             if (!aFactory->isConcealed(aFeatureSender->getKind(), aRefIt->first))
1052               // take into account only concealed references
1053               // (do not remove the sketch constraint and the edge on constraint edit)
1054               continue;
1055             std::list<ObjectPtr>& aRefFeaturesList = aRefIt->second;
1056             std::list<ObjectPtr>::iterator aReferenced = aRefFeaturesList.begin();
1057             for(; aReferenced != aRefFeaturesList.end(); aReferenced++) {
1058                // stability is only on results: feature to feature reference mean nested
1059               // features, that will remove nesting references
1060               if (aReferenced->get() && (*aReferenced)->data()->isValid() &&
1061                 (*aReferenced)->groupName() != ModelAPI_Feature::group()) {
1062                 std::shared_ptr<Model_Data> aData =
1063                   std::dynamic_pointer_cast<Model_Data>((*aReferenced)->data());
1064                 if (aFeatureSender->isStable()) {
1065                   aData->addBackReference(aFeatureSender, aRefIt->first);
1066                 } else {
1067                   aData->removeBackReference(aFeatureSender, aRefIt->first);
1068                   added = true; // remove of concealment may be caused creation of some result
1069                 }
1070               }
1071             }
1072           }
1073         }
1074       }
1075     }
1076     if (added) {
1077       static Events_Loop* aLoop = Events_Loop::loop();
1078       static Events_ID kEventCreated = aLoop->eventByName(EVENT_OBJECT_CREATED);
1079       aLoop->flush(kEventCreated);
1080     }
1081   }
1082 }
1083 // LCOV_EXCL_STOP
1084
1085 void Model_Update::updateSelection(const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects)
1086 {
1087   std::set<std::shared_ptr<ModelAPI_Object> >::iterator anObj = theObjects.begin();
1088   for(; anObj != theObjects.end(); anObj++) {
1089     std::list<AttributePtr> aRefs =
1090       (*anObj)->data()->attributes(ModelAPI_AttributeSelection::typeId());
1091     std::list<AttributePtr>::iterator aRefsIter = aRefs.begin();
1092     for (; aRefsIter != aRefs.end(); aRefsIter++) {
1093       AttributeSelectionPtr aSel =
1094         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*aRefsIter);
1095       bool aRemove = false;
1096       aSel->updateInHistory(aRemove);
1097     }
1098     // update the selection list attributes if any
1099     aRefs = (*anObj)->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
1100     for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
1101       std::set<int> aRemoveSet;
1102       std::shared_ptr<ModelAPI_AttributeSelectionList> aSel =
1103         std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aRefsIter);
1104       for(int a = aSel->size() - 1; a >= 0; a--) {
1105         AttributeSelectionPtr aSelAttr =
1106           std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aSel->value(a));
1107         if (aSelAttr.get()) {
1108           bool aRemove = false;
1109           aSelAttr->updateInHistory(aRemove);
1110           if (aRemove) {
1111             aRemoveSet.insert(a);
1112           }
1113         }
1114       }
1115       aSel->remove(aRemoveSet);
1116     }
1117   }
1118 }