Salome HOME
a5747140567767a2cdbed087cfd3238b516b8e0e
[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_Result.h>
14 #include <Events_Loop.h>
15 #include <Events_LongOp.h>
16
17 using namespace std;
18
19 Model_Update MY_INSTANCE;  /// the only one instance initialized on load of the library
20
21 Model_Update::Model_Update()
22 {
23   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
24   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
25 }
26
27 void Model_Update::processEvent(const Events_Message* theMessage)
28 {
29   if (isExecuted)
30     return;  // nothing to do: it is executed now
31   //Events_LongOp::start(this);
32   isExecuted = true;
33   const ModelAPI_ObjectUpdatedMessage* aMsg =
34       dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
35   myInitial = aMsg->objects();
36   // collect all documents involved into the update
37   set<boost::shared_ptr<ModelAPI_Document> > aDocs;
38   set<boost::shared_ptr<ModelAPI_Object> >::iterator aFIter = myInitial.begin();
39   for (; aFIter != myInitial.end(); aFIter++) {
40     aDocs.insert((*aFIter)->document());
41   }
42   // iterate all features of features-documents to update them (including hidden)
43   set<boost::shared_ptr<ModelAPI_Document> >::iterator aDIter = aDocs.begin();
44   for (; aDIter != aDocs.end(); aDIter++) {
45     int aNbFeatures = (*aDIter)->size(ModelAPI_Feature::group(), true);
46     for (int aFIndex = 0; aFIndex < aNbFeatures; aFIndex++) {
47       FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(
48           (*aDIter)->object(ModelAPI_Feature::group(), aFIndex, true));
49       if (aFeature)
50         updateFeature(aFeature);
51     }
52   }
53   myUpdated.clear();
54   // flush
55   static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
56   Events_Loop::loop()->flush(EVENT_DISP);
57   //Events_LongOp::end(this);
58   isExecuted = false;
59 }
60
61 bool Model_Update::updateFeature(FeaturePtr theFeature)
62 {
63   // check it is already processed
64   if (myUpdated.find(theFeature) != myUpdated.end())
65     return myUpdated[theFeature];
66   // check all features this feature depended on (recursive call of updateFeature)
67   bool aMustbeUpdated = myInitial.find(theFeature) != myInitial.end();
68   if (theFeature) {  // only real feature contains references to other objects
69     // references
70     list<boost::shared_ptr<ModelAPI_Attribute> > aRefs = theFeature->data()->attributes(
71         ModelAPI_AttributeReference::type());
72     list<boost::shared_ptr<ModelAPI_Attribute> >::iterator aRefsIter = aRefs.begin();
73     for (; aRefsIter != aRefs.end(); aRefsIter++) {
74       boost::shared_ptr<ModelAPI_Object> aSub = boost::dynamic_pointer_cast<
75           ModelAPI_AttributeReference>(*aRefsIter)->value();
76       if (updateObject(aSub)) {
77         aMustbeUpdated = true;
78       }
79     }
80     // lists of references
81     aRefs = theFeature->data()->attributes(ModelAPI_AttributeRefList::type());
82     for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
83       list<ObjectPtr> aListRef = boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*aRefsIter)
84           ->list();
85       list<ObjectPtr>::iterator aListIter = aListRef.begin();
86       for (; aListIter != aListRef.end(); aListIter++) {
87         boost::shared_ptr<ModelAPI_Object> aSub = *aListIter;
88         if (updateObject(aSub)) {
89           aMustbeUpdated = true;
90         }
91       }
92     }
93     // execute feature if it must be updated
94     if (aMustbeUpdated) {
95
96       if (boost::dynamic_pointer_cast<Model_Document>(theFeature->document())->executeFeatures() ||
97           !theFeature->isPersistentResult())
98         theFeature->execute();
99       // redisplay all results
100       static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
101       const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
102       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
103       for (; aRIter != aResults.cend(); aRIter++) {
104         boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
105         myUpdated[aRes] = true;
106         ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
107       }
108       // to redisplay "presentable" feature (for ex. distance constraint)
109       ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
110     } else {  // returns also true is results were updated: for sketch that refers to sub-features but results of sub-features were changed
111       const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
112       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
113       for (; aRIter != aResults.cend(); aRIter++) {
114         if (myInitial.find(*aRIter) != myInitial.end()) {
115           aMustbeUpdated = true;
116           break;
117         }
118       }
119     }
120   }
121   myUpdated[theFeature] = aMustbeUpdated;
122   return aMustbeUpdated;
123 }
124
125 bool Model_Update::updateObject(boost::shared_ptr<ModelAPI_Object> theObject)
126 {
127   if (!theObject)
128     return false;
129   FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
130   if (aFeature) {  // for feature just call update Feature
131     return updateFeature(aFeature);
132   }
133   // check general object, possible just a result
134   if (myUpdated.find(theObject) != myUpdated.end())
135     return myUpdated[theObject];  // already processed
136   // check the feature of this object must be executed
137   ResultPtr aResult = boost::dynamic_pointer_cast<ModelAPI_Result>(theObject);
138   if (aResult) {
139     FeaturePtr aResFeature = aResult->document()->feature(aResult);
140     if (aResFeature) {
141       return updateFeature(aResFeature);
142     }
143   }
144   if (myInitial.find(theObject) != myInitial.end())
145     return true;
146   return false;  // nothing is known
147 }