1 // File: Model_Update.cxx
2 // Created: 25 Jun 2014
3 // Author: Mikhail PONIKAROV
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>
25 Model_Update MY_UPDATER_INSTANCE; /// the only one instance initialized on load of the library
27 Model_Update::Model_Update()
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);
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";
48 void Model_Update::processEvent(const boost::shared_ptr<Events_Message>& theMessage)
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
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;
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();
79 return; // nothing to do: it is executed now
81 //Events_LongOp::start(this);
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();
89 // on change flag all documents must be updated
91 aDocs = ModelAPI_Session::get()->allOpenedDocuments();
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());
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));
107 updateFeature(aFeature);
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;
119 bool Model_Update::updateFeature(FeaturePtr theFeature)
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;
129 // composite feature must be executed after sub-features execution
130 CompositeFeaturePtr aComposite =
131 boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
133 int aSubsNum = aComposite->numberOfSubs();
134 for(int a = 0; a < aSubsNum; a++) {
135 if (updateFeature(aComposite->subFeature(a)))
136 aMustbeUpdated = true;
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;
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);
158 if (aRef->isObject()) {
159 boost::shared_ptr<ModelAPI_Object> aSub = aRef->object();
160 if (updateObject(aSub)) {
161 aMustbeUpdated = true;
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;
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)
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;
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;
195 // execute feature if it must be updated
196 if (aMustbeUpdated) {
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 */) {
205 theFeature->execute();
208 "Feature " + theFeature->getKind() + " has failed during the execution");
209 theFeature->eraseResults();
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);
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);
226 aMustbeUpdated = false;
229 theFeature->eraseResults();
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);
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;
254 myUpdated[theFeature] = aMustbeUpdated;
255 return aMustbeUpdated;
258 bool Model_Update::updateObject(boost::shared_ptr<ModelAPI_Object> theObject)
260 if (myUpdated.find(theObject) != myUpdated.end())
261 return myUpdated[theObject]; // already processed
262 return myInitial.find(theObject) != myInitial.end();
264 /* remove algorithm for update of all features by dependencies tree
267 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
268 if (aFeature) { // for feature just call update Feature
269 return updateFeature(aFeature);
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);
277 FeaturePtr aResFeature = aResult->document()->feature(aResult);
279 return updateFeature(aResFeature);
282 if (myInitial.find(theObject) != myInitial.end())
284 return false; // nothing is known