Salome HOME
Issue #1005: To improve user-friendship of error-messages for features and attributes
[modules/shaper.git] / src / ModelAPI / ModelAPI_Feature.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        ModelAPI_Feature.cpp
4 // Created:     17 Jul 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include "ModelAPI_Feature.h"
8 #include <ModelAPI_Events.h>
9 #include <ModelAPI_Result.h>
10 #include <ModelAPI_Data.h>
11 #include <ModelAPI_Document.h>
12 #include <ModelAPI_Session.h>
13 #include <Events_Loop.h>
14 #include <Config_Translator.h>
15
16 void ModelAPI_Feature::setError(const std::string& theError,
17                                 bool isSend,
18                                 bool isTranslate)
19 {
20   std::string anError = isTranslate ? Config_Translator::translate(getKind(), theError)
21                                     : theError;
22   data()->setError(anError, isSend);
23 }
24
25 const std::list<std::shared_ptr<ModelAPI_Result> >& ModelAPI_Feature::results()
26 {
27   return myResults;
28 }
29
30 std::shared_ptr<ModelAPI_Result> ModelAPI_Feature::firstResult() const
31 {
32   return myResults.empty() ? std::shared_ptr<ModelAPI_Result>() : *(myResults.begin());
33 }
34
35 std::shared_ptr<ModelAPI_Result> ModelAPI_Feature::lastResult()
36 {
37   return myResults.empty() ? std::shared_ptr<ModelAPI_Result>() : *(myResults.rbegin());
38 }
39
40 void ModelAPI_Feature::setResult(const std::shared_ptr<ModelAPI_Result>& theResult)
41 {
42   static Events_ID EVENT_UPD = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
43   static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
44
45   if (firstResult() == theResult) {
46     // nothing to change
47   } else if (!myResults.empty()) {  // all except first become disabled
48     std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
49     *aResIter = theResult;
50     aECreator->sendUpdated(theResult, EVENT_UPD);
51     for(aResIter++; aResIter != myResults.end(); aResIter++) {
52       (*aResIter)->setDisabled((*aResIter), true);
53     }
54   } else {
55     myResults.push_back(theResult);
56   }
57   // in any case result becomes enabled
58   theResult->setDisabled(theResult, false);
59 }
60
61 void ModelAPI_Feature::setResult(const std::shared_ptr<ModelAPI_Result>& theResult,
62                                  const int theIndex)
63 {
64   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
65   for (int anIndex = 0; anIndex < theIndex; anIndex++) {
66     aResIter++;
67   }
68   if (aResIter == myResults.end()) {  // append
69     myResults.push_back(theResult);
70   } else {  // update
71     *aResIter = theResult;
72   }
73   theResult->setDisabled(theResult, false);
74 }
75
76 void ModelAPI_Feature::removeResult(const std::shared_ptr<ModelAPI_Result>& theResult)
77 {
78   theResult->setDisabled(theResult, true);
79   // flush visualisation changes
80   static Events_Loop* aLoop = Events_Loop::loop();
81   static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
82   aLoop->flush(aRedispEvent);
83 }
84
85 void ModelAPI_Feature::eraseResultFromList(const std::shared_ptr<ModelAPI_Result>& theResult)
86 {
87   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
88   for(; aResIter != myResults.end(); aResIter++) {
89     ResultPtr aRes = *aResIter;
90     if (aRes == theResult) {
91       std::string aGroup = aRes->groupName();
92       aRes->setDisabled(aRes, true); // for complex results to disable all subs
93       aRes->data()->erase();
94       myResults.erase(aResIter);
95
96       static Events_Loop* aLoop = Events_Loop::loop();
97       static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
98       static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
99       aECreator->sendDeleted(document(), aGroup);
100       aECreator->sendUpdated(aRes, EVENT_DISP);
101       break;
102     }
103   }
104 }
105
106 void ModelAPI_Feature::removeResults(const int theSinceIndex, const bool theFlush)
107 {
108   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
109   for(int anIndex = 0; anIndex < theSinceIndex && aResIter != myResults.end(); anIndex++)
110     aResIter++;
111
112   std::string aGroup;
113   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aNextIter = aResIter;
114   while( aNextIter != myResults.end()) {
115     aGroup = (*aNextIter)->groupName();
116     // remove previously erased results: to enable later if needed only actual (of history change)
117     //if (theSinceIndex == 0 && (*aNextIter)->isDisabled()) {
118     //  aNextIter = myResults.erase(aNextIter);
119     //} else {
120       (*aNextIter)->setDisabled(*aNextIter, true); // just disable results
121       aNextIter++;
122     //}
123   }
124   if (!aGroup.empty() && theFlush) {
125     // flush visualisation changes
126     static Events_Loop* aLoop = Events_Loop::loop();
127     static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
128     aLoop->flush(aRedispEvent);
129     static Events_ID aDelEvent = aLoop->eventByName(EVENT_OBJECT_DELETED);
130     aLoop->flush(aDelEvent);
131   }
132 }
133
134 void ModelAPI_Feature::eraseResults()
135 {
136   removeResults(0);
137 }
138
139 const std::string& ModelAPI_Feature::documentToAdd()
140 {
141   // empty to use the current document
142   static const std::string anEmpty;
143   return anEmpty;
144 }
145
146 void ModelAPI_Feature::erase()
147 {
148   // if this is the current feature, make the upper feature as current before removing
149   if (document().get() && document()->currentFeature(false).get() == this) {
150     document()->setCurrentFeatureUp();
151   }
152
153   static Events_Loop* aLoop = Events_Loop::loop();
154   static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
155   static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
156
157   while (!myResults.empty()) {  // remove one by one with messages
158     std::shared_ptr<ModelAPI_Result> aRes = *(myResults.begin());
159     aRes->setDisabled(aRes, true); // to avoid activation of the Part result
160     if (!myResults.empty()) // disabling result may erase the list (on undo of Part, issue 665)
161       myResults.erase(myResults.begin());
162   }
163   ModelAPI_Object::erase();
164 }
165
166 ModelAPI_Feature::~ModelAPI_Feature()
167 {
168   erase();
169 }
170
171 FeaturePtr ModelAPI_Feature::feature(ObjectPtr theObject)
172 {
173   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
174   if (!aFeature) {
175     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
176     if (aResult) {
177       DocumentPtr aDoc = aResult->document();
178       return aDoc->feature(aResult);
179     }
180   }
181   return aFeature;
182 }
183
184 bool ModelAPI_Feature::isMacro() const
185 {
186   return false;
187 }
188
189 bool ModelAPI_Feature::setDisabled(const bool theFlag)
190 {
191   if (myIsDisabled != theFlag) {
192     myIsDisabled = theFlag;
193     if (myIsDisabled) {
194       removeResults(0, false); // flush will be in setCurrentFeature
195     } else {
196       // enable all disabled previously results
197       std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
198       for(; aResIter != myResults.end(); aResIter++) {
199         (*aResIter)->setDisabled(*aResIter, false);
200       }
201       // update selection for the case something was updated higher in the history
202       // while this feature was disabled
203       static Events_Loop* aLoop = Events_Loop::loop();
204       static Events_ID kUpdatedSel = aLoop->eventByName(EVENT_UPDATE_SELECTION);
205       static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
206       aECreator->sendUpdated(data()->owner(), kUpdatedSel, false);
207     }
208     return true;
209   }
210   return false;
211 }
212
213 bool ModelAPI_Feature::isDisabled()
214 {
215   return myIsDisabled;
216 }
217
218 bool ModelAPI_Feature::setStable(const bool theFlag)
219 {
220   if (myIsStable != theFlag) {
221     myIsStable = theFlag;
222     // send an event about the stability change (editing is started/finished)
223     static Events_Loop* aLoop = Events_Loop::loop();
224     static Events_ID EVENT_STAB = aLoop->eventByName(EVENT_STABILITY_CHANGED);
225     std::shared_ptr<Events_Message> aMessage(new Events_Message(EVENT_STAB, this));
226     aLoop->send(aMessage, false);
227     return true;
228   }
229   return false;
230 }
231
232 bool ModelAPI_Feature::isStable()
233 {
234   return myIsStable;
235 }
236
237 bool ModelAPI_Feature::customAction(const std::string& theActionId)
238 {
239   return false;
240 }
241
242 bool ModelAPI_Feature::isPreviewNeeded() const
243 {
244   return true;
245 }
246
247 void ModelAPI_Feature::init()
248 {
249   myIsDisabled = false;
250   myIsStable = true;
251 }