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_Result.h>
15 #include <ModelAPI_Validator.h>
16 #include <Events_Loop.h>
17 #include <Events_LongOp.h>
18 #include <Events_Error.h>
19 #include <Config_PropManager.h>
23 Model_Update MY_INSTANCE; /// the only one instance initialized on load of the library
25 Model_Update::Model_Update() : isCreated(false)
27 static const Events_ID kChangedEvent = Events_Loop::loop()->eventByName("PreferenceChanged");
28 Events_Loop::loop()->registerListener(this, kChangedEvent);
29 static const Events_ID kRebuildEvent = Events_Loop::loop()->eventByName("Rebuild");
30 Events_Loop::loop()->registerListener(this, kRebuildEvent);
31 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
32 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
33 Config_PropManager::registerProp("Model update", "automatic_rebuild", "Rebuild automatically",
34 Config_Prop::Bool, "false");
35 isAutomatic = Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true";
38 void Model_Update::processEvent(const boost::shared_ptr<Events_Message>& theMessage)
40 static const Events_ID kChangedEvent = Events_Loop::loop()->eventByName("PreferenceChanged");
41 static const Events_ID kRebuildEvent = Events_Loop::loop()->eventByName("Rebuild");
42 bool isAutomaticChanged = false;
43 if (theMessage->eventID() == kChangedEvent) { // automatic and manual rebuild flag is changed
45 Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true";
46 } else if (theMessage->eventID() == kRebuildEvent) { // the rebuild command
47 if (isAutomatic == false) {
48 isAutomaticChanged = true;
54 return; // nothing to do: it is executed now
55 // execute just created features anyway
56 isCreated = theMessage->eventID() == Events_Loop::eventByName(EVENT_OBJECT_CREATED);
58 //Events_LongOp::start(this);
60 list<boost::shared_ptr<ModelAPI_Document> > aDocs;
61 boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
62 boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
63 if (aMsg) myInitial = aMsg->objects();
66 // on change flag all documents must be updated
68 aDocs = ModelAPI_Session::get()->allOpenedDocuments();
71 // collect all documents involved into the update
72 set<boost::shared_ptr<ModelAPI_Object> >::iterator aFIter = myInitial.begin();
73 for (; aFIter != myInitial.end(); aFIter++) {
74 aDocs.push_back((*aFIter)->document());
76 // iterate all features of features-documents to update them (including hidden)
77 list<boost::shared_ptr<ModelAPI_Document> >::iterator aDIter = aDocs.begin();
78 for (; aDIter != aDocs.end(); aDIter++) {
79 int aNbFeatures = (*aDIter)->size(ModelAPI_Feature::group(), true);
80 for (int aFIndex = 0; aFIndex < aNbFeatures; aFIndex++) {
81 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(
82 (*aDIter)->object(ModelAPI_Feature::group(), aFIndex, true));
84 updateFeature(aFeature);
89 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
90 Events_Loop::loop()->flush(EVENT_DISP);
91 //Events_LongOp::end(this);
92 if (isAutomaticChanged) isAutomatic = false;
97 bool Model_Update::updateFeature(FeaturePtr theFeature)
99 // check it is already processed
100 if (myUpdated.find(theFeature) != myUpdated.end())
101 return myUpdated[theFeature];
102 // check all features this feature depended on (recursive call of updateFeature)
103 bool aMustbeUpdated = myInitial.find(theFeature) != myInitial.end();
104 if (theFeature) { // only real feature contains references to other objects
105 if (theFeature->data()->mustBeUpdated()) aMustbeUpdated = true;
107 list<boost::shared_ptr<ModelAPI_Attribute> > aRefs = theFeature->data()->attributes(
108 ModelAPI_AttributeReference::type());
109 list<boost::shared_ptr<ModelAPI_Attribute> >::iterator aRefsIter = aRefs.begin();
110 for (; aRefsIter != aRefs.end(); aRefsIter++) {
111 boost::shared_ptr<ModelAPI_Object> aSub = boost::dynamic_pointer_cast<
112 ModelAPI_AttributeReference>(*aRefsIter)->value();
113 if (updateObject(aSub)) {
114 aMustbeUpdated = true;
117 // reference to attribute or object
118 list<boost::shared_ptr<ModelAPI_Attribute> > aRefAttrs = theFeature->data()->attributes(
119 ModelAPI_AttributeRefAttr::type());
120 for (aRefsIter = aRefAttrs.begin(); aRefsIter != aRefAttrs.end(); aRefsIter++) {
121 boost::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
122 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefsIter);
124 if (aRef->isObject()) {
125 boost::shared_ptr<ModelAPI_Object> aSub = aRef->object();
126 if (updateObject(aSub)) {
127 aMustbeUpdated = true;
129 } else if (aRef->attr()) { // reference to the attribute
130 boost::shared_ptr<ModelAPI_Object> aSub = aRef->attr()->owner();
131 if (updateObject(aSub)) {
132 aMustbeUpdated = true;
136 // lists of references
137 aRefs = theFeature->data()->attributes(ModelAPI_AttributeRefList::type());
138 for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
139 list<ObjectPtr> aListRef = boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*aRefsIter)
141 list<ObjectPtr>::iterator aListIter = aListRef.begin();
142 for (; aListIter != aListRef.end(); aListIter++) {
143 boost::shared_ptr<ModelAPI_Object> aSub = *aListIter;
144 if (updateObject(aSub)) {
145 aMustbeUpdated = true;
149 // execute feature if it must be updated
150 if (aMustbeUpdated) {
152 if (boost::dynamic_pointer_cast<Model_Document>(theFeature->document())->executeFeatures() ||
153 !theFeature->isPersistentResult()) {
154 ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
155 if (aFactory->validate(theFeature)) {
156 if (isAutomatic || (isCreated && myInitial.find(theFeature) != myInitial.end()) ||
157 !theFeature->isPersistentResult() /* execute quick, not persistent results */) {
159 theFeature->execute();
160 theFeature->data()->mustBeUpdated(false);
163 "Feature " + theFeature->getKind() + " has failed during the execution");
164 theFeature->eraseResults();
167 theFeature->data()->mustBeUpdated(true);
168 aMustbeUpdated = false;
171 theFeature->eraseResults();
174 // redisplay all results
175 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
176 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
177 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
178 for (; aRIter != aResults.cend(); aRIter++) {
179 boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
180 myUpdated[aRes] = true;
181 ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
183 // to redisplay "presentable" feature (for ex. distance constraint)
184 ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
185 } else { // returns also true is results were updated: for sketch that refers to sub-features but results of sub-features were changed
186 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
187 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
188 for (; aRIter != aResults.cend(); aRIter++) {
189 if (myInitial.find(*aRIter) != myInitial.end()) {
190 aMustbeUpdated = true;
196 myUpdated[theFeature] = aMustbeUpdated;
197 return aMustbeUpdated;
200 bool Model_Update::updateObject(boost::shared_ptr<ModelAPI_Object> theObject)
204 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
205 if (aFeature) { // for feature just call update Feature
206 return updateFeature(aFeature);
208 // check general object, possible just a result
209 if (myUpdated.find(theObject) != myUpdated.end())
210 return myUpdated[theObject]; // already processed
211 // check the feature of this object must be executed
212 ResultPtr aResult = boost::dynamic_pointer_cast<ModelAPI_Result>(theObject);
214 FeaturePtr aResFeature = aResult->document()->feature(aResult);
216 return updateFeature(aResFeature);
219 if (myInitial.find(theObject) != myInitial.end())
221 return false; // nothing is known