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