]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_Update.cpp
Salome HOME
Merge branch 'master' of newgeom:newgeom
[modules/shaper.git] / src / Model / Model_Update.cpp
1 // File:        Model_Update.cxx
2 // Created:     25 Jun 2014
3 // Author:      Mikhail PONIKAROV
4
5 #include <Model_Update.h>
6 #include <Model_Document.h>
7 #include <ModelAPI_Feature.h>
8 #include <ModelAPI_Data.h>
9 #include <ModelAPI_Document.h>
10 #include <ModelAPI_Events.h>
11 #include <ModelAPI_AttributeReference.h>
12 #include <ModelAPI_AttributeRefList.h>
13 #include <ModelAPI_AttributeRefAttr.h>
14 #include <ModelAPI_AttributeSelection.h>
15 #include <ModelAPI_AttributeSelectionList.h>
16 #include <ModelAPI_Result.h>
17 #include <ModelAPI_Validator.h>
18 #include <ModelAPI_CompositeFeature.h>
19 #include <Events_Loop.h>
20 #include <Events_LongOp.h>
21 #include <Events_Error.h>
22 #include <Config_PropManager.h>
23
24 using namespace std;
25
26 Model_Update MY_UPDATER_INSTANCE;  /// the only one instance initialized on load of the library
27
28 Model_Update::Model_Update()
29 {
30   Events_Loop* aLoop = Events_Loop::loop();
31   static const Events_ID kChangedEvent = aLoop->eventByName("PreferenceChanged");
32   aLoop->registerListener(this, kChangedEvent);
33   static const Events_ID kRebuildEvent = aLoop->eventByName("Rebuild");
34   aLoop->registerListener(this, kRebuildEvent);
35   static const Events_ID kCreatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED);
36   aLoop->registerListener(this, kCreatedEvent);
37   static const Events_ID kUpdatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED);
38   aLoop->registerListener(this, kUpdatedEvent);
39   static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation");
40   aLoop->registerListener(this, kOpFinishEvent);
41   static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation");
42   aLoop->registerListener(this, kOpAbortEvent);
43
44   Config_PropManager::registerProp("Model update", "automatic_rebuild", "Rebuild automatically",
45                                    Config_Prop::Bool, "false");
46   isAutomatic = Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true";
47 }
48
49 void Model_Update::processEvent(const boost::shared_ptr<Events_Message>& theMessage)
50 {
51   static Events_Loop* aLoop = Events_Loop::loop();
52   static const Events_ID kChangedEvent = aLoop->eventByName("PreferenceChanged");
53   static const Events_ID kRebuildEvent = aLoop->eventByName("Rebuild");
54   static const Events_ID kCreatedEvent = aLoop->eventByName(EVENT_OBJECT_CREATED);
55   static const Events_ID kUpdatedEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED);
56   static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation");
57   static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation");
58   bool isAutomaticChanged = false;
59   if (theMessage->eventID() == kChangedEvent) { // automatic and manual rebuild flag is changed
60     isAutomatic = 
61       Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true";
62   } else if (theMessage->eventID() == kRebuildEvent) { // the rebuild command
63     if (isAutomatic == false) {
64       isAutomaticChanged = true;
65       isAutomatic = true;
66     }
67   } else if (theMessage->eventID() == kCreatedEvent || theMessage->eventID() == kUpdatedEvent) {
68     boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
69         boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
70     const std::set<ObjectPtr>& anObjs = aMsg->objects();
71     std::set<ObjectPtr>::const_iterator anObjIter = anObjs.cbegin();
72     for(; anObjIter != anObjs.cend(); anObjIter++)
73       myJustCreatedOrUpdated.insert(*anObjIter);
74   } else if (theMessage->eventID() == kOpFinishEvent || theMessage->eventID() == kOpAbortEvent) {
75     myJustCreatedOrUpdated.clear();
76     return;
77   }
78
79   if (isExecuted)
80     return;  // nothing to do: it is executed now
81
82   //Events_LongOp::start(this);
83   isExecuted = true;
84   list<boost::shared_ptr<ModelAPI_Document> > aDocs;
85   boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
86       boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
87   if (aMsg) myInitial = aMsg->objects();
88   else {
89     myInitial.clear();
90     // on change flag all documents must be updated
91     if (isAutomatic) {
92       aDocs = ModelAPI_Session::get()->allOpenedDocuments();
93     }
94   }
95   // collect all documents involved into the update process
96   set<boost::shared_ptr<ModelAPI_Object> >::iterator aFIter = myInitial.begin();
97   for (; aFIter != myInitial.end(); aFIter++) {
98     aDocs.push_back((*aFIter)->document());
99   }
100   // iterate all features of features-documents to update them (including hidden)
101   list<boost::shared_ptr<ModelAPI_Document> >::iterator aDIter = aDocs.begin();
102   for (; aDIter != aDocs.end(); aDIter++) {
103     int aNbFeatures = (*aDIter)->size(ModelAPI_Feature::group(), true);
104     for (int aFIndex = 0; aFIndex < aNbFeatures; aFIndex++) {
105       FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(
106           (*aDIter)->object(ModelAPI_Feature::group(), aFIndex, true));
107       if (aFeature)
108         updateFeature(aFeature);
109     }
110   }
111   myUpdated.clear();
112   // flush
113   static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
114   aLoop->flush(EVENT_DISP);
115   //Events_LongOp::end(this);
116   if (isAutomaticChanged) isAutomatic = false;
117   isExecuted = false;
118 }
119
120 bool Model_Update::updateFeature(FeaturePtr theFeature)
121 {
122   // check it is already processed
123   if (myUpdated.find(theFeature) != myUpdated.end())
124     return myUpdated[theFeature];
125   // check all features this feature depended on (recursive call of updateFeature)
126   bool aMustbeUpdated = myInitial.find(theFeature) != myInitial.end();
127   if (theFeature) {  // only real feature contains references to other objects
128     if (theFeature->data()->mustBeUpdated()) aMustbeUpdated = true;
129
130     // composite feature must be executed after sub-features execution
131     CompositeFeaturePtr aComposite = 
132       boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
133     if (aComposite) {
134       int aSubsNum = aComposite->numberOfSubs();
135       for(int a = 0; a < aSubsNum; a++) {
136         if (updateFeature(aComposite->subFeature(a)))
137           aMustbeUpdated = true;
138       }
139     }
140
141     // references
142     list<boost::shared_ptr<ModelAPI_Attribute> > aRefs = theFeature->data()->attributes(
143         ModelAPI_AttributeReference::type());
144     list<boost::shared_ptr<ModelAPI_Attribute> >::iterator aRefsIter = aRefs.begin();
145     for (; aRefsIter != aRefs.end(); aRefsIter++) {
146       boost::shared_ptr<ModelAPI_Object> aSub = boost::dynamic_pointer_cast<
147           ModelAPI_AttributeReference>(*aRefsIter)->value();
148       if (updateObject(aSub)) {
149         aMustbeUpdated = true;
150       }
151     }
152     // reference to attribute or object
153     list<boost::shared_ptr<ModelAPI_Attribute> > aRefAttrs = theFeature->data()->attributes(
154         ModelAPI_AttributeRefAttr::type());
155     for (aRefsIter = aRefAttrs.begin(); aRefsIter != aRefAttrs.end(); aRefsIter++) {
156       boost::shared_ptr<ModelAPI_AttributeRefAttr> aRef = 
157         boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefsIter);
158       if (!aRef) continue;
159       if (aRef->isObject()) {
160         boost::shared_ptr<ModelAPI_Object> aSub = aRef->object();
161         if (updateObject(aSub)) {
162           aMustbeUpdated = true;
163         }
164       } else if (aRef->attr()) { // reference to the attribute
165         boost::shared_ptr<ModelAPI_Object> aSub = aRef->attr()->owner();
166         if (updateObject(aSub)) {
167           aMustbeUpdated = true;
168         }
169       }
170     }
171     // lists of references
172     aRefs = theFeature->data()->attributes(ModelAPI_AttributeRefList::type());
173     for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
174       list<ObjectPtr> aListRef = boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*aRefsIter)
175           ->list();
176       list<ObjectPtr>::iterator aListIter = aListRef.begin();
177       for (; aListIter != aListRef.end(); aListIter++) {
178         boost::shared_ptr<ModelAPI_Object> aSub = *aListIter;
179         if (updateObject(aSub)) {
180           aMustbeUpdated = true;
181         }
182       }
183     }
184     // selection attributes: must be called "update" methods if needed
185     aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelection::type());
186     for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
187       boost::shared_ptr<ModelAPI_AttributeSelection> aSel =
188         boost::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*aRefsIter);
189       if (updateObject(aSel->context())) {
190         aMustbeUpdated = true;
191         // aSel->update(); // this must be done on execution since it may be long operation
192       }
193     }
194     // lists of selection attributes: must be called "update" methods if needed
195     aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::type());
196     for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
197       boost::shared_ptr<ModelAPI_AttributeSelectionList> aSel =
198         boost::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aRefsIter);
199       for(int a = aSel->size() - 1; a >= 0; a--) {
200         if (updateObject(aSel->value(a)->context())) {
201           aMustbeUpdated = true;
202         }
203       }
204     }
205
206     // execute feature if it must be updated
207     if (aMustbeUpdated) {
208
209       if (boost::dynamic_pointer_cast<Model_Document>(theFeature->document())->executeFeatures() ||
210           !theFeature->isPersistentResult()) {
211         ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
212         if (aFactory->validate(theFeature)) {
213           if (isAutomatic || (myJustCreatedOrUpdated.find(theFeature) != myJustCreatedOrUpdated.end()) ||
214             !theFeature->isPersistentResult() /* execute quick, not persistent results */) 
215           {
216             // before execution update the selection attributes if any
217             aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelection::type());
218             for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
219               boost::shared_ptr<ModelAPI_AttributeSelection> aSel =
220                 boost::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*aRefsIter);
221               aSel->update(); // this must be done on execution since it may be long operation
222             }
223             aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::type());
224             for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
225               boost::shared_ptr<ModelAPI_AttributeSelectionList> aSel =
226                 boost::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aRefsIter);
227               for(int a = aSel->size() - 1; a >= 0; a--) {
228                 aSel->value(a)->update();
229               }
230             }
231             // execute in try-catch to avoid internal problems of the feature
232             try {
233               theFeature->execute();
234             } catch(...) {
235               Events_Error::send(
236                 "Feature " + theFeature->getKind() + " has failed during the execution");
237               theFeature->eraseResults();
238             }
239             theFeature->data()->mustBeUpdated(false);
240             const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
241             std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
242             for (; aRIter != aResults.cend(); aRIter++) {
243               boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
244               aRes->data()->mustBeUpdated(false);
245             }
246           } else {
247             theFeature->data()->mustBeUpdated(true);
248             const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
249             std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
250             for (; aRIter != aResults.cend(); aRIter++) {
251               boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
252               aRes->data()->mustBeUpdated(true);
253             }
254             aMustbeUpdated = false;
255           }
256         } else {
257           theFeature->eraseResults();
258         }
259       }
260       // redisplay all results
261       static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
262       const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
263       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
264       for (; aRIter != aResults.cend(); aRIter++) {
265         boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
266         myUpdated[aRes] = true;
267         ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
268       }
269       // to redisplay "presentable" feature (for ex. distance constraint)
270       ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
271     } else {  // returns also true is results were updated: for sketch that refers to sub-features but results of sub-features were changed
272       const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
273       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
274       for (; aRIter != aResults.cend(); aRIter++) {
275         if (myInitial.find(*aRIter) != myInitial.end()) {
276           aMustbeUpdated = true;
277           break;
278         }
279       }
280     }
281   }
282   myUpdated[theFeature] = aMustbeUpdated;
283   return aMustbeUpdated;
284 }
285
286 bool Model_Update::updateObject(boost::shared_ptr<ModelAPI_Object> theObject)
287 {
288   if (myUpdated.find(theObject) != myUpdated.end())
289     return myUpdated[theObject];  // already processed
290   return myInitial.find(theObject) != myInitial.end();
291
292   /* remove algorithm for update of all features by dependencies tree
293   if (!theObject)
294     return false;
295   FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
296   if (aFeature) {  // for feature just call update Feature
297     return updateFeature(aFeature);
298   }
299   // check general object, possible just a result
300   if (myUpdated.find(theObject) != myUpdated.end())
301     return myUpdated[theObject];  // already processed
302   // check the feature of this object must be executed
303   ResultPtr aResult = boost::dynamic_pointer_cast<ModelAPI_Result>(theObject);
304   if (aResult) {
305     FeaturePtr aResFeature = aResult->document()->feature(aResult);
306     if (aResFeature) {
307       return updateFeature(aResFeature);
308     }
309   }
310   if (myInitial.find(theObject) != myInitial.end())
311     return true;
312   return false;  // nothing is known
313   */
314 }