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