Salome HOME
01eeccac4fd3e4de52231525e369edb932662dd7
[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_IPropertyPanel.h"
9 #include "ModuleBase_ViewerPrs.h"
10 #include "ModuleBase_Tools.h"
11 #include "ModuleBase_WidgetValidator.h"
12
13 #include <Events_InfoMessage.h>
14
15 #include <ModelAPI_Data.h>
16 #include <ModelAPI_Attribute.h>
17 #include <ModelAPI_Events.h>
18 #include <ModelAPI_Session.h>
19 #include <ModelAPI_Validator.h>
20
21 #include <Config_Keywords.h>
22 #include <Config_WidgetAPI.h>
23 #include <Config_Translator.h>
24 #include <Config_PropManager.h>
25
26 #include <Events_Loop.h>
27
28 #include <QEvent>
29 #include <QLabel>
30 #include <QFocusEvent>
31 #include <QTextCodec>
32
33 //#define DEBUG_VALUE_STATE
34
35 //#define DEBUG_WIDGET_INSTANCE
36 //#define DEBUG_ENABLE_SKETCH_INPUT_FIELDS
37
38 ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,
39                                                const Config_WidgetAPI* theData)
40     : QWidget(theParent),
41       myIsEditing(false),
42       myState(Stored),
43       myIsValueStateBlocked(false),
44       myFlushUpdateBlocked(false),
45       myWidgetValidator(0)
46 {
47 #ifdef DEBUG_WIDGET_INSTANCE
48   qDebug("ModuleBase_ModelWidget::ModuleBase_ModelWidget");
49 #endif
50
51   myFeatureId = theData->featureId();
52
53   myIsInternal = theData->getBooleanAttribute(ATTR_INTERNAL, false);
54
55   myIsModifiedInEdit = theData->getProperty(ATTR_MODIFIED_IN_EDIT);
56
57   myDefaultValue = theData->getProperty(ATTR_DEFAULT);
58   myUseReset = theData->getBooleanAttribute(ATTR_USE_RESET, true);
59   myIsComputedDefault = theData->getProperty(ATTR_DEFAULT) == DOUBLE_WDG_DEFAULT_COMPUTED;
60   myAttributeID = theData ? theData->widgetId() : "";
61   myIsObligatory = theData->getBooleanAttribute(ATTR_OBLIGATORY, true);
62
63   myIsValueEnabled = On; // not defined or "true"
64   std::string anEnableValue = theData->getProperty(DOUBLE_WDG_ENABLE_VALUE);
65   if (anEnableValue == "false")
66     myIsValueEnabled = Off;
67   if (anEnableValue == DOUBLE_WDG_ENABLE_VALUE_BY_PREFERENCES)
68     myIsValueEnabled = DefinedInPreferences;
69
70   connect(this, SIGNAL(valuesChanged()), this, SLOT(onWidgetValuesChanged()));
71   connect(this, SIGNAL(valuesModified()), this, SLOT(onWidgetValuesModified()));
72 }
73
74 ModuleBase_ModelWidget::~ModuleBase_ModelWidget()
75 {
76 #ifdef DEBUG_WIDGET_INSTANCE
77   qDebug("ModuleBase_ModelWidget::~ModuleBase_ModelWidget");
78 #endif
79 }
80
81 bool ModuleBase_ModelWidget::reset()
82 {
83   bool aResult = resetCustom();
84   if (aResult)
85     setValueState(Reset);
86
87   return aResult;
88 }
89
90 bool ModuleBase_ModelWidget::isInitialized(ObjectPtr theObject) const
91 {
92   return theObject->data()->attribute(attributeID())->isInitialized();
93 }
94
95 bool ModuleBase_ModelWidget::isValueEnabled() const
96 {
97   bool anEnabled = true;
98   if (myIsValueEnabled == DefinedInPreferences) {
99 #ifdef DEBUG_ENABLE_SKETCH_INPUT_FIELDS
100     bool aCanDisable = false;
101 #else
102     //Config_PropManager::boolean(SKETCH_TAB_NAME, "disable_input_fields", "true");
103     bool aCanDisable = true;
104 #endif
105     if (aCanDisable)
106       anEnabled = false;
107   }
108   else if (myIsValueEnabled == Off)
109     anEnabled = false;
110   return anEnabled;
111 }
112
113 void ModuleBase_ModelWidget::processValueState()
114 {
115   if (myState == ModifiedInPP || myState == ModifiedInViewer)
116     storeValue();
117 }
118
119 Events_InfoMessage ModuleBase_ModelWidget::getValueStateError() const
120 {
121   Events_InfoMessage aMessage;
122
123   ModuleBase_ModelWidget::ValueState aState = getValueState();
124   if (aState != ModuleBase_ModelWidget::Stored) {
125     AttributePtr anAttr = feature()->attribute(attributeID());
126     if (anAttr.get()) {
127       const std::string& anAttributeName = anAttr->id();
128       switch (aState) {
129         case ModuleBase_ModelWidget::ModifiedInViewer:
130           aMessage = "Attribute \"%1\" is locked by modification value in the viewer.";
131           aMessage.addParameter(anAttributeName);
132           break;
133         case ModuleBase_ModelWidget::Reset:
134           aMessage = "Attribute \"%1\" is not initialized.";
135           aMessage.addParameter(anAttributeName);
136           break;
137         case ModuleBase_ModelWidget::ModifiedInPP: // Apply should be enabled in this mode
138         default:
139           break;
140       }
141     }
142   }
143   return aMessage;
144 }
145
146 QString ModuleBase_ModelWidget::getError(const bool theValueStateChecked) const
147 {
148   QString anError;
149
150   if (!feature().get())
151     return anError;
152
153   std::string aFeatureID = feature()->getKind();
154   std::string anAttributeID = attributeID();
155   AttributePtr anAttribute = feature()->attribute(anAttributeID);
156   if (!anAttribute.get())
157     return anError;
158
159   std::string aValidatorID;
160   Events_InfoMessage anErrorMsg;
161
162   static ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
163   if (!aValidators->validate(anAttribute, aValidatorID, anErrorMsg)) {
164     if (anErrorMsg.empty())
165       anErrorMsg = "Unknown error.";
166
167     if (anErrorMsg.context().empty()) {
168       anErrorMsg.setContext(aFeatureID + ":" + anAttributeID + ":" + aValidatorID);
169     }
170   }
171
172   if (anErrorMsg.empty() && theValueStateChecked) {
173     anErrorMsg = getValueStateError();
174   }
175
176   if (!anErrorMsg.empty()) {
177     anError = ModuleBase_Tools::translate(anErrorMsg);
178   }
179
180   return anError;
181 }
182
183 void ModuleBase_ModelWidget::enableFocusProcessing()
184 {
185   QList<QWidget*> aMyControls = getControls();
186   foreach(QWidget*  eachControl, aMyControls) {
187       eachControl->setFocusPolicy(Qt::StrongFocus);
188       eachControl->installEventFilter(this);
189   }
190 }
191
192 void ModuleBase_ModelWidget::setHighlighted(bool isHighlighted)
193 {
194   QList<QWidget*> aWidgetList = getControls();
195   foreach(QWidget* aWidget, aWidgetList) {
196     QLabel* aLabel = qobject_cast<QLabel*>(aWidget);
197     // We won't set the effect to QLabels - it looks ugly
198     if(aLabel) continue;
199     // If effect is the installed on a different widget, setGraphicsEffect() will
200     // remove the effect from the widget and install it on this widget.
201     // That's why we create a new effect for each widget
202     ModuleBase_Tools::setShadowEffect(aWidget, isHighlighted);
203   }
204 }
205
206 void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool theToStoreValue,
207                                         const bool isUpdateFlushed)
208 {
209   /// it is possible to give this flag as parameter in storeValue/storeCustomValue
210   /// after debug, it may be corrected
211   myFlushUpdateBlocked = !isUpdateFlushed;
212   myFeature = theFeature;
213   if (theToStoreValue) {
214     /// it is possible that the attribute is filled before the operation is started,
215     /// e.g. by reentrant operation case some attributes are filled by values of
216     /// feature of previous operation, we should not lost them here
217     if (!theFeature->data()->attribute(attributeID())->isInitialized())
218       storeValue();
219   }
220   myFlushUpdateBlocked = false;
221 }
222
223 bool ModuleBase_ModelWidget::focusTo()
224 {
225 #ifdef DEBUG_WIDGET_INSTANCE
226   qDebug("ModuleBase_ModelWidget::focusTo");
227 #endif
228   QList<QWidget*> aControls = getControls();
229   QList<QWidget*>::const_iterator anIt = aControls.begin(), aLast = aControls.end();
230   bool isFocusAccepted = false;
231   for (; anIt != aLast && !isFocusAccepted; anIt++) {
232     QWidget* aWidget = *anIt;
233     if (aWidget && aWidget->focusPolicy() != Qt::NoFocus) {
234       ModuleBase_Tools::setFocus(aWidget, "ModuleBase_ModelWidget::focusTo()");
235       isFocusAccepted = true;
236     }
237   }
238   return isFocusAccepted;
239 }
240
241 void ModuleBase_ModelWidget::activate()
242 {
243 #ifdef DEBUG_WIDGET_INSTANCE
244   qDebug("ModuleBase_ModelWidget::activate");
245 #endif
246   // the control value is stored to the mode by the focus in on the widget
247   // we need the value is initialized in order to enable the apply button in the property panel.
248   // It should happens in the creation mode only because all fields are filled in the edition mode
249   if (!isEditingMode()) {
250     AttributePtr anAttribute = myFeature->data()->attribute(myAttributeID);
251     if (anAttribute.get() != NULL && !anAttribute->isInitialized())
252       initializeValueByActivate();
253   }
254
255   if (myWidgetValidator)
256     myWidgetValidator->activateFilters(true);
257
258   activateCustom();
259 }
260
261 void ModuleBase_ModelWidget::deactivate()
262 {
263 #ifdef DEBUG_WIDGET_INSTANCE
264   qDebug("ModuleBase_ModelWidget::deactivate");
265 #endif
266   myIsValueStateBlocked = false;
267   myState = Stored;
268   if (myWidgetValidator)
269     myWidgetValidator->activateFilters(false);
270 }
271
272 void ModuleBase_ModelWidget::initializeValueByActivate()
273 {
274   if (isComputedDefault()) {
275     if (myFeature->compute(myAttributeID)) {
276       restoreValue();
277     }
278   }
279   else {
280     storeValue();
281   }
282 }
283
284 QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)
285 {
286   QWidget* aControl = 0;
287
288   QList<QWidget*> aControls = getControls();
289   int aSize = aControls.size();
290
291   if (isFirst) {
292     for (int i = 0; i < aSize && !aControl; i++)  {
293       if (aControls[i]->focusPolicy() != Qt::NoFocus)
294         aControl = aControls[i];
295     }
296   }
297   else {
298     for (int i = aSize - 1; i >= 0 && !aControl; i--)  {
299       if (aControls[i]->focusPolicy() != Qt::NoFocus)
300         aControl = aControls[i];
301     }
302   }
303   return aControl;
304 }
305
306 void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)
307 {
308   myDefaultValue = theValue;
309 }
310
311 bool ModuleBase_ModelWidget::storeValue()
312 {
313   setValueState(Stored);
314
315   emit beforeValuesChanged();
316   bool isDone = false;
317   // value is stored only in creation mode and in edition if there is not
318   // XML flag prohibited modification in edit mode(macro feature circle/arc)
319   if (!isEditingMode() || isModifiedInEdit().empty())
320     isDone = storeValueCustom();
321   else {
322     /// store value in an alternative attribute if possible(attribute has the same type)
323     std::string aWidgetAttribute = attributeID();
324     myAttributeID = isModifiedInEdit();
325     storeValueCustom();
326     myAttributeID = aWidgetAttribute;
327     // operation will be restarted but if isDone == true, PagedContainer will try to set focus
328     // to the current widget, but will be already deleted
329     isDone = false;
330   }
331
332   emit afterValuesChanged();
333
334   return isDone;
335 }
336 #ifdef DEBUG_VALUE_STATE
337 std::string getDebugInfo(const ModuleBase_ModelWidget::ValueState& theState)
338 {
339   std::string anInfo;
340   switch (theState) {
341     case ModuleBase_ModelWidget::Stored:           anInfo = "Stored          "; break;
342     case ModuleBase_ModelWidget::ModifiedInPP:     anInfo = "ModifiedInPP    "; break;
343     case ModuleBase_ModelWidget::ModifiedInViewer: anInfo = "ModifiedInViewer"; break;
344     case ModuleBase_ModelWidget::Reset:            anInfo = "Reset           "; break;
345     default: break;
346   }
347   return anInfo;
348 }
349
350 #endif
351 ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState
352                                          (const ModuleBase_ModelWidget::ValueState& theState)
353 {
354   ValueState aState = myState;
355
356   if (myState != theState && !myIsValueStateBlocked) {
357 #ifdef DEBUG_VALUE_STATE
358     qDebug(QString("setValueState: previous state = %1,\t new state = %2")
359            .arg(getDebugInfo(myState).c_str())
360            .arg(getDebugInfo(theState).c_str()).toStdString().c_str());
361 #endif
362     myState = theState;
363     emit valueStateChanged(aState);
364   }
365   return aState;
366 }
367
368 bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
369 {
370   bool isBlocked = myIsValueStateBlocked;
371   myIsValueStateBlocked = theBlocked;
372   return isBlocked;
373 }
374
375 bool ModuleBase_ModelWidget::restoreValue()
376 {
377   emit beforeValuesRestored();
378   bool isDone = restoreValueCustom();
379   emit afterValuesRestored();
380
381   return isDone;
382 }
383
384 void ModuleBase_ModelWidget::updateObject(ObjectPtr theObject)
385 {
386   if (!myFlushUpdateBlocked) {
387 #ifdef DEBUG_WIDGET_INSTANCE
388     qDebug("ModuleBase_ModelWidget::updateObject");
389 #endif
390     ModuleBase_Tools::flushUpdated(theObject);
391     emit objectUpdated();
392   }
393 }
394
395 void ModuleBase_ModelWidget::moveObject(ObjectPtr theObj)
396 {
397   //blockUpdateViewer(true);
398 #ifdef DEBUG_WIDGET_INSTANCE
399   qDebug("ModuleBase_ModelWidget::moveObject");
400 #endif
401
402   static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
403   ModelAPI_EventCreator::get()->sendUpdated(theObj, anEvent);
404   Events_Loop::loop()->flush(anEvent);
405
406   //blockUpdateViewer(false);
407 }
408
409 bool ModuleBase_ModelWidget::processEnter()
410 {
411   return false;
412 }
413
414 bool ModuleBase_ModelWidget::processDelete()
415 {
416   // we consider that model objects eats delete key in order to
417   // do nothing by for example symbol delete in line edit or spin box
418   return true;
419 }
420
421 bool ModuleBase_ModelWidget::eventFilter(QObject* theObject, QEvent *theEvent)
422 {
423   QWidget* aWidget = qobject_cast<QWidget*>(theObject);
424   if (theEvent->type() == QEvent::FocusIn) {
425     #ifdef _DEBUG
426     // The following two lines are for debugging purpose only
427     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
428     bool isWinFocus = aFocusEvent->reason() == Qt::ActiveWindowFocusReason;
429     #endif
430     Qt::FocusReason aReason = aFocusEvent->reason();
431     bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
432                         /*aReason == Qt::TabFocusReason ||
433                         //aReason == Qt::BacktabFocusReason ||*/
434                         aReason == Qt::OtherFocusReason; // to process widget->setFocus()
435     if (aMouseOrKey && getControls().contains(aWidget)) {
436     //if (getControls().contains(aWidget)) {
437       emitFocusInWidget();
438     }
439   }
440   else if (theEvent->type() == QEvent::FocusOut) {
441     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
442
443     Qt::FocusReason aReason = aFocusEvent->reason();
444     bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
445                         aReason == Qt::TabFocusReason ||
446                         aReason == Qt::BacktabFocusReason ||
447                         aReason == Qt::OtherFocusReason; // to process widget->setFocus()
448     if (aMouseOrKey && getControls().contains(aWidget)) {
449       if (getValueState() == ModifiedInPP) {
450         storeValue();
451       }
452     }
453   }
454   // pass the event on to the parent class
455
456   return QObject::eventFilter(theObject, theEvent);
457 }
458
459 //**************************************************************
460 void ModuleBase_ModelWidget::onWidgetValuesChanged()
461 {
462   storeValue();
463 }
464
465 //**************************************************************
466 void ModuleBase_ModelWidget::onWidgetValuesModified()
467 {
468   setValueState(ModifiedInPP);
469 }
470
471 //**************************************************************
472 QString ModuleBase_ModelWidget::translate(const std::string& theStr) const
473 {
474   return ModuleBase_Tools::translate(context(), theStr);
475 }
476
477 //**************************************************************
478 ModuleBase_ModelWidget* ModuleBase_ModelWidget::findModelWidget(ModuleBase_IPropertyPanel* theProp,
479                                                                 QWidget* theWidget)
480 {
481   ModuleBase_ModelWidget* aModelWidget;
482   QObject* aParent = theWidget->parent();
483   while (aParent) {
484     aModelWidget = qobject_cast<ModuleBase_ModelWidget*>(aParent);
485     if (aModelWidget)
486       break;
487     aParent = aParent->parent();
488   }
489   return aModelWidget;
490 }