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