Salome HOME
07f9ce6a0b0168caaa829574b094341eb81069b4
[modules/shaper.git] / src / ModelAPI / ModelAPI_Feature.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "ModelAPI_Feature.h"
21 #include <ModelAPI_Events.h>
22 #include <ModelAPI_Result.h>
23 #include <ModelAPI_Data.h>
24 #include <ModelAPI_Document.h>
25 #include <ModelAPI_Session.h>
26 #include <Events_Loop.h>
27 #include <Config_Translator.h>
28
29 void ModelAPI_Feature::setError(const std::string& theError,
30                                 bool isSend,
31                                 bool isTranslate)
32 {
33   std::string anError = isTranslate ? Config_Translator::translate(getKind(), theError)
34                                     : theError;
35   data()->setError(anError, isSend);
36 }
37
38 const std::list<std::shared_ptr<ModelAPI_Result> >& ModelAPI_Feature::results()
39 {
40   return myResults;
41 }
42
43 std::shared_ptr<ModelAPI_Result> ModelAPI_Feature::firstResult() const
44 {
45   return myResults.empty() ? std::shared_ptr<ModelAPI_Result>() : *(myResults.begin());
46 }
47
48 std::shared_ptr<ModelAPI_Result> ModelAPI_Feature::lastResult()
49 {
50   return myResults.empty() ? std::shared_ptr<ModelAPI_Result>() : *(myResults.rbegin());
51 }
52
53 void ModelAPI_Feature::setResult(const std::shared_ptr<ModelAPI_Result>& theResult)
54 {
55   static Events_ID EVENT_UPD = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
56   static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
57
58   if (firstResult() == theResult) {
59     // nothing to change
60   } else if (!myResults.empty()) {  // all except first become disabled
61     std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
62     *aResIter = theResult;
63     aECreator->sendUpdated(theResult, EVENT_UPD);
64     for(aResIter++; aResIter != myResults.end(); aResIter++) {
65       (*aResIter)->setDisabled((*aResIter), true);
66     }
67   } else {
68     myResults.push_back(theResult);
69   }
70   // in any case result becomes enabled
71   if (!isDisabled()) // disabled feature may be executed when it is added as not enabled (#2078)
72     theResult->setDisabled(theResult, false);
73 }
74
75 void ModelAPI_Feature::setResult(const std::shared_ptr<ModelAPI_Result>& theResult,
76                                  const int theIndex)
77 {
78   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
79   for (int anIndex = 0; anIndex < theIndex; anIndex++) {
80     aResIter++;
81   }
82   if (aResIter == myResults.end()) {  // append
83     myResults.push_back(theResult);
84   } else {  // update
85     *aResIter = theResult;
86   }
87   theResult->setDisabled(theResult, false);
88 }
89
90 void ModelAPI_Feature::eraseResultFromList(const std::shared_ptr<ModelAPI_Result>& theResult)
91 {
92   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
93   for(; aResIter != myResults.end(); aResIter++) {
94     ResultPtr aRes = *aResIter;
95     if (aRes == theResult) {
96       std::string aGroup = aRes->groupName();
97       aRes->setDisabled(aRes, true); // for complex results to disable all subs
98       aRes->data()->erase();
99       myResults.erase(aResIter);
100
101       static Events_Loop* aLoop = Events_Loop::loop();
102       static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
103       static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
104       aECreator->sendDeleted(document(), aGroup);
105       aECreator->sendUpdated(aRes, EVENT_DISP);
106       break;
107     }
108   }
109 }
110
111 void ModelAPI_Feature::removeResults(
112   const int theSinceIndex, const bool theForever, const bool theFlush)
113 {
114   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
115   for(int anIndex = 0; anIndex < theSinceIndex && aResIter != myResults.end(); anIndex++)
116     aResIter++;
117
118   std::string aGroup;
119   std::list<std::shared_ptr<ModelAPI_Result> >::iterator aNextIter = aResIter;
120   while( aNextIter != myResults.end()) {
121     aGroup = (*aNextIter)->groupName();
122     // remove previously erased results: to enable later if needed only actual (of history change)
123     (*aNextIter)->setDisabled(*aNextIter, true); // just disable results
124     if (theForever) {
125       aNextIter = myResults.erase(aNextIter);
126     } else {
127       aNextIter++;
128     }
129   }
130   if (!aGroup.empty() && theFlush) {
131     // flush visualization changes
132     static Events_Loop* aLoop = Events_Loop::loop();
133     static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
134     aLoop->flush(aRedispEvent);
135     static Events_ID aDelEvent = aLoop->eventByName(EVENT_OBJECT_DELETED);
136     aLoop->flush(aDelEvent);
137   }
138 }
139
140 void ModelAPI_Feature::eraseResults(const bool theForever)
141 {
142   removeResults(0, theForever, true);
143 }
144
145 const std::string& ModelAPI_Feature::documentToAdd()
146 {
147   // empty to use the current document
148   static const std::string anEmpty;
149   return anEmpty;
150 }
151
152 void ModelAPI_Feature::erase()
153 {
154   // if this is the current feature, make the upper feature as current before removing
155   if (document().get() && document()->currentFeature(false).get() == this) {
156     document()->setCurrentFeatureUp();
157   }
158
159   while (!myResults.empty()) {  // remove one by one with messages
160     std::shared_ptr<ModelAPI_Result> aRes = *(myResults.begin());
161     aRes->setDisabled(aRes, true); // to avoid activation of the Part result
162     if (!myResults.empty()) {// disabling result may erase the list (on undo of Part, issue 665)
163       myResults.erase(myResults.begin());
164       aRes->erase();
165     }
166   }
167   ModelAPI_Object::erase();
168 }
169
170 ModelAPI_Feature::~ModelAPI_Feature()
171 {
172   if (data() && data()->isValid())
173     erase();
174 }
175
176 FeaturePtr ModelAPI_Feature::feature(ObjectPtr theObject)
177 {
178   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
179   if (!aFeature) {
180     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
181     if (aResult) {
182       DocumentPtr aDoc = aResult->document();
183       return aDoc->feature(aResult);
184     }
185   }
186   return aFeature;
187 }
188
189 bool ModelAPI_Feature::isMacro() const
190 {
191   return false;
192 }
193
194 bool ModelAPI_Feature::setDisabled(const bool theFlag)
195 {
196   if (myIsDisabled != theFlag) {
197     myIsDisabled = theFlag;
198     if (myIsDisabled) {
199       removeResults(0, false, false); // flush will be in setCurrentFeature
200     } else {
201       // enable all disabled previously results
202       std::list<std::shared_ptr<ModelAPI_Result> >::iterator aResIter = myResults.begin();
203       for(; aResIter != myResults.end(); aResIter++) {
204         (*aResIter)->setDisabled(*aResIter, false);
205       }
206       // update selection for the case something was updated higher in the history
207       // while this feature was disabled, but avoid flushing it immediately and
208       // wait while all the previous features update myIsDisabled flag
209       // (flush will be called by the document)
210       static Events_Loop* aLoop = Events_Loop::loop();
211       static Events_ID kUpdatedSel = aLoop->eventByName(EVENT_UPDATE_SELECTION);
212       static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
213       aECreator->sendUpdated(data()->owner(), kUpdatedSel, true);
214     }
215     return true;
216   }
217   return false;
218 }
219
220 bool ModelAPI_Feature::isDisabled()
221 {
222   return myIsDisabled;
223 }
224
225 // LCOV_EXCL_START
226 bool ModelAPI_Feature::setStable(const bool theFlag)
227 {
228   if (myIsStable != theFlag) {
229     myIsStable = theFlag;
230     // send an event about the stability change (editing is started/finished)
231     static Events_Loop* aLoop = Events_Loop::loop();
232     static Events_ID EVENT_STAB = aLoop->eventByName(EVENT_STABILITY_CHANGED);
233     std::shared_ptr<Events_Message> aMessage(new Events_Message(EVENT_STAB, this));
234     aLoop->send(aMessage, false);
235     return true;
236   }
237   return false;
238 }
239 // LCOV_EXCL_STOP
240
241 bool ModelAPI_Feature::isStable()
242 {
243   return myIsStable;
244 }
245
246 bool ModelAPI_Feature::customAction(const std::string& /*theActionId*/)
247 {
248   return false;
249 }
250
251 bool ModelAPI_Feature::isPreviewNeeded() const
252 {
253   return true;
254 }
255
256 void ModelAPI_Feature::init()
257 {
258   myIsDisabled = false;
259   myIsStable = true;
260 }