]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_Update.cpp
Salome HOME
Make automatic/manual rebuild property and connect the "Rebuild" button
[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 <Events_Loop.h>
17 #include <Events_LongOp.h>
18 #include <Events_Error.h>
19 #include <Config_PropManager.h>
20
21 using namespace std;
22
23 Model_Update MY_INSTANCE;  /// the only one instance initialized on load of the library
24
25 Model_Update::Model_Update() : isCreated(false)
26 {
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";
36 }
37
38 void Model_Update::processEvent(const boost::shared_ptr<Events_Message>& theMessage)
39 {
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
44     isAutomatic = 
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;
49       isAutomatic = true;
50     }
51   }
52
53   if (isExecuted)
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);
57
58   //Events_LongOp::start(this);
59   isExecuted = true;
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();
64   else {
65     myInitial.clear();
66     // on change flag all documents must be updated
67     if (isAutomatic) {
68       aDocs = ModelAPI_Session::get()->allOpenedDocuments();
69     }
70   }
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());
75   }
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));
83       if (aFeature)
84         updateFeature(aFeature);
85     }
86   }
87   myUpdated.clear();
88   // flush
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;
93   isCreated = false;
94   isExecuted = false;
95 }
96
97 bool Model_Update::updateFeature(FeaturePtr theFeature)
98 {
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;
106     // references
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;
115       }
116     }
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);
123       if (!aRef) continue;
124       if (aRef->isObject()) {
125         boost::shared_ptr<ModelAPI_Object> aSub = aRef->object();
126         if (updateObject(aSub)) {
127           aMustbeUpdated = true;
128         }
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;
133         }
134       }
135     }
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)
140           ->list();
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;
146         }
147       }
148     }
149     // execute feature if it must be updated
150     if (aMustbeUpdated) {
151
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 */) {
158             try {
159               theFeature->execute();
160               theFeature->data()->mustBeUpdated(false);
161             } catch(...) {
162               Events_Error::send(
163                 "Feature " + theFeature->getKind() + " has failed during the execution");
164               theFeature->eraseResults();
165             }
166           } else {
167             theFeature->data()->mustBeUpdated(true);
168             aMustbeUpdated = false;
169           }
170         } else {
171           theFeature->eraseResults();
172         }
173       }
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);
182       }
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;
191           break;
192         }
193       }
194     }
195   }
196   myUpdated[theFeature] = aMustbeUpdated;
197   return aMustbeUpdated;
198 }
199
200 bool Model_Update::updateObject(boost::shared_ptr<ModelAPI_Object> theObject)
201 {
202   if (!theObject)
203     return false;
204   FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
205   if (aFeature) {  // for feature just call update Feature
206     return updateFeature(aFeature);
207   }
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);
213   if (aResult) {
214     FeaturePtr aResFeature = aResult->document()->feature(aResult);
215     if (aResFeature) {
216       return updateFeature(aResFeature);
217     }
218   }
219   if (myInitial.find(theObject) != myInitial.end())
220     return true;
221   return false;  // nothing is known
222 }