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