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