Salome HOME
Update SketchPlugin_Projection feature (issue #1459)
[modules/shaper.git] / src / ModuleBase / ModuleBase_ModelWidget.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        ModuleBase_ModelWidget.cpp
4 // Created:     25 Apr 2014
5 // Author:      Natalia ERMOLAEVA
6
7 #include "ModuleBase_ModelWidget.h"
8 #include "ModuleBase_ViewerPrs.h"
9 #include "ModuleBase_Tools.h"
10 #include "ModuleBase_WidgetValidator.h"
11
12 #include <ModelAPI_Data.h>
13 #include <ModelAPI_Attribute.h>
14 #include <ModelAPI_Events.h>
15 #include <ModelAPI_Session.h>
16 #include <ModelAPI_Validator.h>
17
18 #include <Config_Keywords.h>
19 #include <Config_WidgetAPI.h>
20
21 #include <Events_Loop.h>
22
23 #include <QEvent>
24 #include <QLabel>
25 #include <QFocusEvent>
26
27 //#define DEBUG_VALUE_STATE
28
29 ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,
30                                                const Config_WidgetAPI* theData)
31     : QWidget(theParent),
32       myIsEditing(false),
33       myState(Stored),
34       myIsValueStateBlocked(false),
35       myFlushUpdateBlocked(false),
36       myWidgetValidator(0)
37 {
38   myIsInternal = theData->getBooleanAttribute(ATTR_INTERNAL, false);
39
40   myDefaultValue = theData->getProperty(ATTR_DEFAULT);
41   myUseReset = theData->getBooleanAttribute(ATTR_USE_RESET, true);
42   myIsComputedDefault = theData->getProperty(ATTR_DEFAULT) == DOUBLE_WDG_DEFAULT_COMPUTED;
43   myAttributeID = theData ? theData->widgetId() : "";
44   myIsObligatory = theData->getBooleanAttribute(ATTR_OBLIGATORY, true);
45
46   connect(this, SIGNAL(valuesChanged()), this, SLOT(onWidgetValuesChanged()));
47   connect(this, SIGNAL(valuesModified()), this, SLOT(onWidgetValuesModified()));
48 }
49
50 bool ModuleBase_ModelWidget::reset()
51 {
52   bool aResult = resetCustom();
53   if (aResult)
54     setValueState(Reset);
55
56   return aResult;
57 }
58
59 bool ModuleBase_ModelWidget::isInitialized(ObjectPtr theObject) const
60 {
61   return theObject->data()->attribute(attributeID())->isInitialized();
62 }
63
64 QString ModuleBase_ModelWidget::getValueStateError() const
65 {
66   QString anError = "";
67
68   ModuleBase_ModelWidget::ValueState aState = getValueState();
69   if (aState != ModuleBase_ModelWidget::Stored) {
70     AttributePtr anAttr = feature()->attribute(attributeID());
71     if (anAttr.get()) {
72       QString anAttributeName = anAttr->id().c_str();
73       switch (aState) {
74         case ModuleBase_ModelWidget::ModifiedInViewer:
75           anError = "Attribute \"" + anAttributeName +
76                     "\" is locked by modification value in the viewer.";
77           break;
78         case ModuleBase_ModelWidget::Reset:
79           anError = "Attribute \"" + anAttributeName + "\" is not initialized.";
80           break;
81         case ModuleBase_ModelWidget::ModifiedInPP: // Apply should be enabled in this mode
82         default:
83           break;
84       }
85     }
86   }
87   return anError;
88 }
89
90 QString ModuleBase_ModelWidget::getError(const bool theValueStateChecked) const
91 {
92   QString anError;
93
94   if (!feature().get())
95     return anError;
96
97   std::string anAttributeID = attributeID();
98   AttributePtr anAttribute = feature()->attribute(anAttributeID);
99   if (!anAttribute.get())
100     return anError;
101
102   std::string aValidatorID;
103   std::string anErrorMsg;
104
105   static ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
106   if (!aValidators->validate(anAttribute, aValidatorID, anErrorMsg)) {
107     if (anErrorMsg.empty())
108       anErrorMsg = "unknown error.";
109     anErrorMsg = anAttributeID + " - " + aValidatorID + ": " + anErrorMsg;
110   }
111
112   anError = QString::fromStdString(anErrorMsg);
113   if (anError.isEmpty() && theValueStateChecked)
114     anError = getValueStateError();
115
116   return anError;
117 }
118
119 void ModuleBase_ModelWidget::enableFocusProcessing()
120 {
121   QList<QWidget*> aMyControls = getControls();
122   foreach(QWidget*  eachControl, aMyControls) {
123       eachControl->setFocusPolicy(Qt::StrongFocus);
124       eachControl->installEventFilter(this);
125   }
126 }
127
128 void ModuleBase_ModelWidget::setHighlighted(bool isHighlighted)
129 {
130   QList<QWidget*> aWidgetList = getControls();
131   foreach(QWidget* aWidget, aWidgetList) {
132     QLabel* aLabel = qobject_cast<QLabel*>(aWidget);
133     // We won't set the effect to QLabels - it looks ugly
134     if(aLabel) continue;
135     // If effect is the installed on a different widget, setGraphicsEffect() will
136     // remove the effect from the widget and install it on this widget.
137     // That's why we create a new effect for each widget
138     ModuleBase_Tools::setShadowEffect(aWidget, isHighlighted);
139   }
140 }
141
142 void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool theToStoreValue,
143                                         const bool isUpdateFlushed)
144 {
145   /// it is possible to give this flag as parameter in storeValue/storeCustomValue
146   /// after debug, it may be corrected
147   myFlushUpdateBlocked = !isUpdateFlushed;
148   myFeature = theFeature;
149   if (theToStoreValue)
150     storeValue();
151   myFlushUpdateBlocked = false;
152 }
153
154 bool ModuleBase_ModelWidget::focusTo()
155 {
156   QList<QWidget*> aControls = getControls();
157   QList<QWidget*>::const_iterator anIt = aControls.begin(), aLast = aControls.end();
158   bool isFocusAccepted = false;
159   for (; anIt != aLast && !isFocusAccepted; anIt++) {
160     QWidget* aWidget = *anIt;
161     if (aWidget && aWidget->focusPolicy() != Qt::NoFocus) {
162       ModuleBase_Tools::setFocus(aWidget, "ModuleBase_ModelWidget::focusTo()");
163       isFocusAccepted = true;
164     }
165   }
166   return isFocusAccepted;
167 }
168
169 void ModuleBase_ModelWidget::activate()
170 {
171   // the control value is stored to the mode by the focus in on the widget
172   // we need the value is initialized in order to enable the apply button in the property panel.
173   // It should happens in the creation mode only because all fields are filled in the edition mode
174   if (!isEditingMode()) {
175     AttributePtr anAttribute = myFeature->data()->attribute(myAttributeID);
176     if (anAttribute.get() != NULL && !anAttribute->isInitialized())
177       initializeValueByActivate();
178   }
179
180   if (myWidgetValidator)
181     myWidgetValidator->activateFilters(true);
182
183   activateCustom();
184 }
185
186 void ModuleBase_ModelWidget::deactivate()
187 {
188   myIsValueStateBlocked = false;
189   if (myState == ModifiedInPP || myState == ModifiedInViewer)
190     storeValue();
191   myState = Stored;
192
193   if (myWidgetValidator)
194     myWidgetValidator->activateFilters(false);
195 }
196
197 void ModuleBase_ModelWidget::initializeValueByActivate()
198 {
199   if (isComputedDefault()) {
200     if (myFeature->compute(myAttributeID)) {
201       restoreValue();
202     }
203   }
204   else {
205     storeValue();
206   }
207 }
208
209 QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)
210 {
211   QWidget* aControl = 0;
212
213   QList<QWidget*> aControls = getControls();
214   int aSize = aControls.size();
215
216   if (isFirst) {
217     for (int i = 0; i < aSize && !aControl; i++)  {
218       if (aControls[i]->focusPolicy() != Qt::NoFocus)
219         aControl = aControls[i];
220     }
221   }
222   else {
223     for (int i = aSize - 1; i >= 0 && !aControl; i--)  {
224       if (aControls[i]->focusPolicy() != Qt::NoFocus)
225         aControl = aControls[i];
226     }
227   }
228   return aControl;
229 }
230
231 void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)
232 {
233   myDefaultValue = theValue;
234 }
235
236 bool ModuleBase_ModelWidget::storeValue()
237 {
238   setValueState(Stored);
239
240   emit beforeValuesChanged();
241   bool isDone = storeValueCustom();
242   emit afterValuesChanged();
243
244   return isDone;
245 }
246 #ifdef DEBUG_VALUE_STATE
247 std::string getDebugInfo(const ModuleBase_ModelWidget::ValueState& theState)
248 {
249   std::string anInfo;
250   switch (theState) {
251     case ModuleBase_ModelWidget::Stored:           anInfo = "Stored          "; break;
252     case ModuleBase_ModelWidget::ModifiedInPP:     anInfo = "ModifiedInPP    "; break;
253     case ModuleBase_ModelWidget::ModifiedInViewer: anInfo = "ModifiedInViewer"; break;
254     case ModuleBase_ModelWidget::Reset:            anInfo = "Reset           "; break;
255     default: break;
256   }
257   return anInfo;
258 }
259
260 #endif
261 ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState
262                                          (const ModuleBase_ModelWidget::ValueState& theState)
263 {
264   ValueState aState = myState;
265
266   if (myState != theState && !myIsValueStateBlocked) {
267 #ifdef DEBUG_VALUE_STATE
268     qDebug(QString("setValueState: previous state = %1,\t new state = %2")
269            .arg(getDebugInfo(myState).c_str())
270            .arg(getDebugInfo(theState).c_str()).toStdString().c_str());
271 #endif
272     myState = theState;
273     emit valueStateChanged(aState);
274   }
275   return aState;
276 }
277
278 bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
279 {
280   bool isBlocked = myIsValueStateBlocked;
281   myIsValueStateBlocked = theBlocked;
282   return isBlocked;
283 }
284
285 bool ModuleBase_ModelWidget::restoreValue()
286 {
287   emit beforeValuesRestored();
288   bool isDone = restoreValueCustom();
289   emit afterValuesRestored();
290
291   return isDone;
292 }
293
294 void ModuleBase_ModelWidget::updateObject(ObjectPtr theObject)
295 {
296   if (!myFlushUpdateBlocked) {
297     ModuleBase_Tools::flushUpdated(theObject);
298     emit objectUpdated();
299   }
300 }
301
302 void ModuleBase_ModelWidget::moveObject(ObjectPtr theObj)
303 {
304   //blockUpdateViewer(true);
305
306   static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
307   ModelAPI_EventCreator::get()->sendUpdated(theObj, anEvent);
308   Events_Loop::loop()->flush(anEvent);
309
310   //blockUpdateViewer(false);
311 }
312
313 bool ModuleBase_ModelWidget::processEnter()
314 {
315   return false;
316 }
317
318 bool ModuleBase_ModelWidget::processDelete()
319 {
320   // we consider that model objects eats delete key in order to
321   // do nothing by for example symbol delete in line edit or spin box
322   return true;
323 }
324
325 bool ModuleBase_ModelWidget::eventFilter(QObject* theObject, QEvent *theEvent)
326 {
327   QWidget* aWidget = qobject_cast<QWidget*>(theObject);
328   if (theEvent->type() == QEvent::FocusIn) {
329     #ifdef _DEBUG
330     // The following two lines are for debugging purpose only
331     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
332     bool isWinFocus = aFocusEvent->reason() == Qt::ActiveWindowFocusReason;
333     #endif
334     if (getControls().contains(aWidget)) {
335       emit focusInWidget(this);
336     }
337   }
338   else if (theEvent->type() == QEvent::FocusOut) {
339     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
340
341     Qt::FocusReason aReason = aFocusEvent->reason();
342     bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
343                         aReason == Qt::TabFocusReason ||
344                         aReason == Qt::BacktabFocusReason ||
345                         aReason == Qt::OtherFocusReason; // to process widget->setFocus()
346     if (aMouseOrKey && getControls().contains(aWidget)) {
347       if (getValueState() == ModifiedInPP) {
348         storeValue();
349       }
350     }
351   }
352   // pass the event on to the parent class
353
354   return QObject::eventFilter(theObject, theEvent);
355 }
356
357 //**************************************************************
358 void ModuleBase_ModelWidget::onWidgetValuesChanged()
359 {
360   storeValue();
361 }
362
363 //**************************************************************
364 void ModuleBase_ModelWidget::onWidgetValuesModified()
365 {
366   setValueState(ModifiedInPP);
367 }