Salome HOME
SketchShapePlugin: checked group box/multi editor controls, which highlight the paren...
[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_Tools.h"
9
10 #include <ModelAPI_Data.h>
11 #include <ModelAPI_Attribute.h>
12 #include <ModelAPI_Events.h>
13 #include <ModelAPI_Session.h>
14
15 #include <Config_Keywords.h>
16 #include <Config_WidgetAPI.h>
17
18 #include <Events_Loop.h>
19
20 #include <QEvent>
21 #include <QLabel>
22 #include <QFocusEvent>
23
24 ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,
25                                                const Config_WidgetAPI* theData,
26                                                const std::string& theParentId)
27     : QWidget(theParent),
28       myParentId(theParentId),
29       myIsEditing(false),
30       myState(Stored),
31       myIsValueStateBlocked(false)
32 {
33   myDefaultValue = theData->getProperty(ATTR_DEFAULT);
34   myUseReset = theData->getBooleanAttribute(ATTR_USE_RESET, true);
35   myIsComputedDefault = theData->getProperty(ATTR_DEFAULT) == DOUBLE_WDG_DEFAULT_COMPUTED;
36   myAttributeID = theData ? theData->widgetId() : "";
37   myIsObligatory = theData->getBooleanAttribute(ATTR_OBLIGATORY, true);
38
39   connect(this, SIGNAL(valuesChanged()), this, SLOT(onWidgetValuesChanged()));
40   connect(this, SIGNAL(valuesModified()), this, SLOT(onWidgetValuesModified()));
41 }
42
43 bool ModuleBase_ModelWidget::reset()
44 {
45   bool aResult = resetCustom();
46   if (aResult)
47     setValueState(Reset);
48
49   return aResult;
50 }
51
52 bool ModuleBase_ModelWidget::isInitialized(ObjectPtr theObject) const
53 {
54   return theObject->data()->attribute(attributeID())->isInitialized();
55 }
56
57 QString ModuleBase_ModelWidget::getValueStateError() const
58 {
59   QString anError = "";
60
61   ModuleBase_ModelWidget::ValueState aState = getValueState();
62   if (aState != ModuleBase_ModelWidget::Stored) {
63     AttributePtr anAttr = feature()->attribute(attributeID());
64     if (anAttr.get()) {
65       QString anAttributeName = anAttr->id().c_str();
66       switch (aState) {
67         case ModuleBase_ModelWidget::ModifiedInPP:
68           anError = "Attribute \"" + anAttributeName +
69                     "\" modification is not applyed. Please click \"Enter\" or \"Tab\".";
70           break;
71         case ModuleBase_ModelWidget::ModifiedInViewer:
72           anError = "Attribute \"" + anAttributeName +
73                     "\" is locked by modification value in the viewer.";
74           break;
75         case ModuleBase_ModelWidget::Reset:
76           anError = "Attribute \"" + anAttributeName + "\" is not initialized.";
77           break;
78       }
79     }
80   }
81   return anError;
82 }
83
84 void ModuleBase_ModelWidget::enableFocusProcessing()
85 {
86   QList<QWidget*> aMyControls = getControls();
87   foreach(QWidget*  eachControl, aMyControls) {
88     if (myIsObligatory) {
89       eachControl->setFocusPolicy(Qt::StrongFocus);
90       eachControl->installEventFilter(this);
91     }
92     else {
93       eachControl->setFocusPolicy(Qt::NoFocus);
94     }
95   }
96 }
97
98 void ModuleBase_ModelWidget::setHighlighted(bool isHighlighted)
99 {
100   QList<QWidget*> aWidgetList = getControls();
101   foreach(QWidget* aWidget, aWidgetList) {
102     QLabel* aLabel = qobject_cast<QLabel*>(aWidget);
103     // We won't set the effect to QLabels - it looks ugly
104     if(aLabel) continue;
105     // If effect is the installed on a different widget, setGraphicsEffect() will
106     // remove the effect from the widget and install it on this widget.
107     // That's why we create a new effect for each widget
108     ModuleBase_Tools::setShadowEffect(aWidget, isHighlighted);
109   }
110 }
111
112 void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool theToStoreValue)
113 {
114   myFeature = theFeature;
115   if (theToStoreValue)
116     storeValue();
117 }
118
119 bool ModuleBase_ModelWidget::focusTo()
120 {
121   QList<QWidget*> aControls = getControls();
122   QList<QWidget*>::const_iterator anIt = aControls.begin(), aLast = aControls.end();
123   bool isFocusAccepted = false;
124   for (; anIt != aLast && !isFocusAccepted; anIt++) {
125     QWidget* aWidget = *anIt;
126     if (aWidget && aWidget->focusPolicy() != Qt::NoFocus) {
127       ModuleBase_Tools::setFocus(aWidget, "ModuleBase_ModelWidget::focusTo()");
128       isFocusAccepted = true;
129     }
130   }
131   return isFocusAccepted;
132 }
133
134 void ModuleBase_ModelWidget::activate()
135 {
136   // the control value is stored to the mode by the focus in on the widget
137   // we need the value is initialized in order to enable the apply button in the property panel.
138   // It should happens in the creation mode only because all fields are filled in the edition mode
139   if (!isEditingMode()) {
140     AttributePtr anAttribute = myFeature->data()->attribute(myAttributeID);
141     if (anAttribute.get() != NULL && !anAttribute->isInitialized())
142       initializeValueByActivate();
143   }
144   activateCustom();
145 }
146
147 void ModuleBase_ModelWidget::deactivate()
148 {
149   myIsValueStateBlocked = false;
150   if (myState == ModifiedInPP)
151     storeValue();
152   myState = Stored;
153 }
154
155 void ModuleBase_ModelWidget::initializeValueByActivate()
156 {
157   if (isComputedDefault()) {
158     if (myFeature->compute(myAttributeID)) {
159       restoreValue();
160     }
161   }
162   else {
163     storeValue();
164   }
165 }
166
167 QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)
168 {
169   QWidget* aControl = 0;
170
171   QList<QWidget*> aControls = getControls();
172   int aSize = aControls.size();
173
174   if (isFirst) {
175     for (int i = 0; i < aSize && !aControl; i++)  {
176       if (aControls[i]->focusPolicy() != Qt::NoFocus)
177         aControl = aControls[i];
178     }
179   }
180   else {
181     for (int i = aSize - 1; i >= 0 && !aControl; i--)  {
182       if (aControls[i]->focusPolicy() != Qt::NoFocus)
183         aControl = aControls[i];
184     }
185   }
186   return aControl;
187 }
188
189 void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)
190 {
191   myDefaultValue = theValue;
192 }
193
194 bool ModuleBase_ModelWidget::storeValue()
195 {
196   setValueState(Stored);
197
198   emit beforeValuesChanged();
199   bool isDone = storeValueCustom();
200   emit afterValuesChanged();
201
202   return isDone;
203 }
204
205 ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState(const ModuleBase_ModelWidget::ValueState& theState)
206 {
207   ValueState aState = myState;
208   if (myState != theState && !myIsValueStateBlocked) {
209     myState = theState;
210     emit valueStateChanged(aState);
211   }
212   return aState;
213 }
214
215 bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
216 {
217   bool isBlocked = myIsValueStateBlocked;
218   myIsValueStateBlocked = theBlocked;
219   return isBlocked;
220 }
221
222 bool ModuleBase_ModelWidget::restoreValue()
223 {
224   emit beforeValuesRestored();
225   bool isDone = restoreValueCustom();
226   emit afterValuesRestored();
227
228   return isDone;
229 }
230
231 void ModuleBase_ModelWidget::updateObject(ObjectPtr theObj)
232 {
233   blockUpdateViewer(true);
234
235   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
236
237   blockUpdateViewer(false);
238 }
239
240 void ModuleBase_ModelWidget::moveObject(ObjectPtr theObj)
241 {
242   //blockUpdateViewer(true);
243
244   static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
245   ModelAPI_EventCreator::get()->sendUpdated(theObj, anEvent);
246   Events_Loop::loop()->flush(anEvent);
247
248   //blockUpdateViewer(false);
249 }
250
251 bool ModuleBase_ModelWidget::processEnter()
252 {
253   return false;
254 }
255
256 bool ModuleBase_ModelWidget::eventFilter(QObject* theObject, QEvent *theEvent)
257 {
258   QWidget* aWidget = qobject_cast<QWidget*>(theObject);
259   if (theEvent->type() == QEvent::FocusIn) {
260     #ifdef _DEBUG
261     // The following two lines are for debugging purpose only
262     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
263     bool isWinFocus = aFocusEvent->reason() == Qt::ActiveWindowFocusReason;
264     #endif
265     if (getControls().contains(aWidget)) {
266       emit focusInWidget(this);
267     }
268   }
269   else if (theEvent->type() == QEvent::FocusOut) {
270     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
271
272     Qt::FocusReason aReason = aFocusEvent->reason();
273     bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
274                         aReason == Qt::TabFocusReason ||
275                         aReason == Qt::BacktabFocusReason ||
276                         aReason == Qt::OtherFocusReason; // to process widget->setFocus()
277     if (aMouseOrKey && getControls().contains(aWidget) && getValueState() == ModifiedInPP)
278       storeValue();
279   }
280   // pass the event on to the parent class
281
282   return QObject::eventFilter(theObject, theEvent);
283 }
284
285 //**************************************************************
286 void ModuleBase_ModelWidget::onWidgetValuesChanged()
287 {
288   storeValue();
289 }
290
291 //**************************************************************
292 void ModuleBase_ModelWidget::onWidgetValuesModified()
293 {
294   setValueState(ModifiedInPP);
295 }
296
297 //**************************************************************
298 void ModuleBase_ModelWidget::blockUpdateViewer(const bool theValue)
299 {
300   // the viewer update should be blocked in order to avoid the temporary feature content
301   // when the solver processes the feature, the redisplay message can be flushed
302   // what caused the display in the viewer preliminary states of object
303   // e.g. fillet feature, angle value change
304   std::shared_ptr<Events_Message> aMsg;
305   if (theValue) {
306     aMsg = std::shared_ptr<Events_Message>(
307         new Events_Message(Events_Loop::eventByName(EVENT_UPDATE_VIEWER_BLOCKED)));
308   }
309   else {
310     // the viewer update should be unblocked
311     aMsg = std::shared_ptr<Events_Message>(
312         new Events_Message(Events_Loop::eventByName(EVENT_UPDATE_VIEWER_UNBLOCKED)));
313   }
314   Events_Loop::loop()->send(aMsg);
315 }