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