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