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