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