Salome HOME
62751487a2cce8f33ec12f2212855995fb9784eb
[modules/shaper.git] / src / ModuleBase / ModuleBase_ModelWidget.cpp
1 // Copyright (C) 2014-2023  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   myWidgetValidator(0),
56   myState(Stored),
57   myIsEditing(false),
58   myIsValueStateBlocked(false),
59   myFlushUpdateBlocked(false)
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 anAttributeID = attributeID();
195   AttributePtr anAttribute = feature()->attribute(anAttributeID);
196   if (!anAttribute.get())
197     return anError;
198
199   std::string aValidatorID;
200   Events_InfoMessage anErrorMsg;
201
202   static ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
203   if (!aValidators->validate(anAttribute, aValidatorID, anErrorMsg)) {
204     if (anErrorMsg.empty())
205       anErrorMsg = "Unknown error.";
206
207     if (anErrorMsg.context().empty()) {
208       anErrorMsg.setContext(context() + ":" + aValidatorID);
209     }
210   }
211
212   if (anErrorMsg.empty() && theValueStateChecked) {
213     anErrorMsg = getValueStateError();
214   }
215
216   if (!anErrorMsg.empty()) {
217     anError = ModuleBase_Tools::translate(anErrorMsg);
218   }
219
220   return anError;
221 }
222
223 //**************************************************************
224 void ModuleBase_ModelWidget::enableFocusProcessing()
225 {
226   QList<QWidget*> aMyControls = getControls();
227   foreach(QWidget*  eachControl, aMyControls) {
228       eachControl->setFocusPolicy(Qt::StrongFocus);
229       eachControl->installEventFilter(this);
230   }
231 }
232
233 //**************************************************************
234 void ModuleBase_ModelWidget::setHighlighted(bool isHighlighted)
235 {
236   QList<QWidget*> aWidgetList = getControls();
237   foreach(QWidget* aWidget, aWidgetList) {
238     QLabel* aLabel = qobject_cast<QLabel*>(aWidget);
239     // We won't set the effect to QLabels - it looks ugly
240     if(aLabel) continue;
241     // If effect is the installed on a different widget, setGraphicsEffect() will
242     // remove the effect from the widget and install it on this widget.
243     // That's why we create a new effect for each widget
244     ModuleBase_Tools::setShadowEffect(aWidget, isHighlighted);
245   }
246 }
247
248 //**************************************************************
249 void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool theToStoreValue,
250                                         const bool isUpdateFlushed)
251 {
252   /// it is possible to give this flag as parameter in storeValue/storeCustomValue
253   /// after debug, it may be corrected
254   myFlushUpdateBlocked = !isUpdateFlushed;
255   myFeature = theFeature;
256   if (theToStoreValue) {
257     /// it is possible that the attribute is filled before the operation is started,
258     /// e.g. by reentrant operation case some attributes are filled by values of
259     /// feature of previous operation, we should not lost them here
260     if (!theFeature->data()->attribute(attributeID())->isInitialized())
261       storeValue();
262   }
263   myFlushUpdateBlocked = false;
264 }
265
266 //**************************************************************
267 bool ModuleBase_ModelWidget::focusTo()
268 {
269 #ifdef DEBUG_WIDGET_INSTANCE
270   qDebug("ModuleBase_ModelWidget::focusTo");
271 #endif
272   QList<QWidget*> aControls = getControls();
273   QList<QWidget*>::const_iterator anIt = aControls.begin(), aLast = aControls.end();
274   bool isFocusAccepted = false;
275   for (; anIt != aLast && !isFocusAccepted; anIt++) {
276     QWidget* aWidget = *anIt;
277     if (aWidget && aWidget->focusPolicy() != Qt::NoFocus) {
278       ModuleBase_Tools::setFocus(aWidget, "ModuleBase_ModelWidget::focusTo()");
279       isFocusAccepted = true;
280     }
281   }
282   return isFocusAccepted;
283 }
284
285 //**************************************************************
286 void ModuleBase_ModelWidget::activate()
287 {
288 #ifdef DEBUG_WIDGET_INSTANCE
289   qDebug("ModuleBase_ModelWidget::activate");
290 #endif
291   // the control value is stored to the mode by the focus in on the widget
292   // we need the value is initialized in order to enable the apply button in the property panel.
293   // It should happens in the creation mode only because all fields are filled in the edition mode
294   if (!isEditingMode()) {
295     AttributePtr anAttribute = myFeature->data()->attribute(myAttributeID);
296     if (anAttribute.get() != NULL && !anAttribute->isInitialized())
297       initializeValueByActivate();
298   }
299   activateCustom();
300 }
301
302 //**************************************************************
303 void ModuleBase_ModelWidget::deactivate()
304 {
305 #ifdef DEBUG_WIDGET_INSTANCE
306   qDebug("ModuleBase_ModelWidget::deactivate");
307 #endif
308   myIsValueStateBlocked = false;
309   myState = Stored;
310   if (myWidgetValidator)
311     myWidgetValidator->clearValidatedCash();
312 }
313
314 //**************************************************************
315 void ModuleBase_ModelWidget::initializeValueByActivate()
316 {
317   if (isComputedDefault()) {
318     if (myFeature->compute(myAttributeID)) {
319       restoreValue();
320     }
321   }
322   else {
323     storeValue();
324   }
325 }
326
327 //**************************************************************
328 QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)
329 {
330   QWidget* aControl = 0;
331
332   QList<QWidget*> aControls = getControls();
333   int aSize = aControls.size();
334
335   if (isFirst) {
336     for (int i = 0; i < aSize && !aControl; i++)  {
337       if (aControls[i]->focusPolicy() != Qt::NoFocus)
338         aControl = aControls[i];
339     }
340   }
341   else {
342     for (int i = aSize - 1; i >= 0 && !aControl; i--)  {
343       if (aControls[i]->focusPolicy() != Qt::NoFocus)
344         aControl = aControls[i];
345     }
346   }
347   return aControl;
348 }
349
350 //**************************************************************
351 void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)
352 {
353   myDefaultValue = theValue;
354 }
355
356 //**************************************************************
357 bool ModuleBase_ModelWidget::storeValue()
358 {
359   setValueState(Stored);
360
361   emit beforeValuesChanged();
362   bool isDone = false;
363   // value is stored only in creation mode and in edition if there is not
364   // XML flag prohibited modification in edit mode(macro feature circle/arc)
365   if (!isEditingMode() || isModifiedInEdit().empty())
366     isDone = storeValueCustom();
367   else {
368     /// store value in an alternative attribute if possible(attribute has the same type)
369     std::string aWidgetAttribute = attributeID();
370     myAttributeID = isModifiedInEdit();
371     storeValueCustom();
372     myAttributeID = aWidgetAttribute;
373     // operation will be restarted but if isDone == true, PagedContainer will try to set focus
374     // to the current widget, but will be already deleted
375     isDone = false;
376   }
377
378   emit afterValuesChanged();
379
380   return isDone;
381 }
382 #ifdef DEBUG_VALUE_STATE
383
384 //**************************************************************
385 std::string getDebugInfo(const ModuleBase_ModelWidget::ValueState& theState)
386 {
387   std::string anInfo;
388   switch (theState) {
389     case ModuleBase_ModelWidget::Stored:           anInfo = "Stored          "; break;
390     case ModuleBase_ModelWidget::ModifiedInPP:     anInfo = "ModifiedInPP    "; break;
391     case ModuleBase_ModelWidget::ModifiedInViewer: anInfo = "ModifiedInViewer"; break;
392     case ModuleBase_ModelWidget::Reset:            anInfo = "Reset           "; break;
393     default: break;
394   }
395   return anInfo;
396 }
397 #endif
398
399 //**************************************************************
400 ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState
401                                          (const ModuleBase_ModelWidget::ValueState& theState)
402 {
403   ValueState aState = myState;
404
405   if (myState != theState && !myIsValueStateBlocked) {
406 #ifdef DEBUG_VALUE_STATE
407     qDebug(QString("setValueState: previous state = %1,\t new state = %2")
408            .arg(getDebugInfo(myState).c_str())
409            .arg(getDebugInfo(theState).c_str()).toStdString().c_str());
410 #endif
411     myState = theState;
412     emit valueStateChanged(aState);
413   }
414   return aState;
415 }
416
417 //**************************************************************
418 bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
419 {
420   bool isBlocked = myIsValueStateBlocked;
421   myIsValueStateBlocked = theBlocked;
422   return isBlocked;
423 }
424
425 //**************************************************************
426 bool ModuleBase_ModelWidget::restoreValue()
427 {
428   if (!isEnabled()) {
429     // This code works in inspection panel
430     ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
431     if (!aValidators->isCase(myFeature, attributeID()))
432       return false; // if it is not an active case for the widget
433   }
434   emit beforeValuesRestored();
435   bool isDone = restoreValueCustom();
436   emit afterValuesRestored();
437
438   return isDone;
439 }
440
441 //**************************************************************
442 void ModuleBase_ModelWidget::updateObject(ObjectPtr theObject)
443 {
444   if (!myFlushUpdateBlocked) {
445 #ifdef DEBUG_WIDGET_INSTANCE
446     qDebug("ModuleBase_ModelWidget::updateObject");
447 #endif
448     if (myFeature.get() && myUpdateVisualAttributes) {
449       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
450       ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
451     }
452     ModuleBase_Tools::flushUpdated(theObject);
453     emit objectUpdated();
454   }
455 }
456
457 //**************************************************************
458 bool ModuleBase_ModelWidget::canProcessAction(ModuleBase_ActionType theActionType,
459                                               bool& isActionEnabled)
460 {
461   isActionEnabled = false;
462   switch (theActionType) {
463     case ActionEnter: return false;
464     case ActionEscape: return false;
465     case ActionDelete: return true;
466     case ActionSelection: return true;
467     case ActionUndo:
468     case ActionRedo:
469     default:
470       return false;
471   }
472 }
473
474 //**************************************************************
475 bool ModuleBase_ModelWidget::processAction(ModuleBase_ActionType theActionType,
476                                            const ActionParamPtr& theParam)
477 {
478   switch (theActionType) {
479     case ActionEnter:
480       return processEnter();
481     case ActionEscape:
482       return processEscape();
483     case ActionDelete:
484       return processDelete();
485     case ActionSelection:
486       processSelection();
487     case ActionUndo:
488     case ActionRedo:
489     default:
490       return false;
491   }
492 }
493
494 //**************************************************************
495 bool ModuleBase_ModelWidget::processEnter()
496 {
497   return false;
498 }
499
500 //**************************************************************
501 bool ModuleBase_ModelWidget::processEscape()
502 {
503   return false;
504 }
505
506 //**************************************************************
507 bool ModuleBase_ModelWidget::processDelete()
508 {
509   // we consider that model objects eats delete key in order to
510   // do nothing by for example symbol delete in line edit or spin box
511   return true;
512 }
513
514 //**************************************************************
515 bool ModuleBase_ModelWidget::processSelection()
516 {
517   return false;
518 }
519
520 //**************************************************************
521 bool ModuleBase_ModelWidget::eventFilter(QObject* theObject, QEvent *theEvent)
522 {
523   QWidget* aWidget = qobject_cast<QWidget*>(theObject);
524   if (theEvent->type() == QEvent::FocusIn) {
525     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
526     Qt::FocusReason aReason = aFocusEvent->reason();
527     bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
528                         /*aReason == Qt::TabFocusReason ||
529                         //aReason == Qt::BacktabFocusReason ||*/
530                         aReason == Qt::OtherFocusReason; // to process widget->setFocus()
531     if (aMouseOrKey && getControls().contains(aWidget)) {
532     //if (getControls().contains(aWidget)) {
533       emitFocusInWidget();
534     }
535   }
536   else if (theEvent->type() == QEvent::FocusOut) {
537     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
538
539     Qt::FocusReason aReason = aFocusEvent->reason();
540     bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
541                         aReason == Qt::TabFocusReason ||
542                         aReason == Qt::BacktabFocusReason ||
543                         aReason == Qt::OtherFocusReason; // to process widget->setFocus()
544     if (aMouseOrKey && getControls().contains(aWidget)) {
545       if (getValueState() == ModifiedInPP) {
546         storeValue();
547       }
548     }
549   }
550   // pass the event on to the parent class
551
552   return QObject::eventFilter(theObject, theEvent);
553 }
554
555 //**************************************************************
556 void ModuleBase_ModelWidget::onWidgetValuesChanged()
557 {
558   storeValue();
559 }
560
561 //**************************************************************
562 void ModuleBase_ModelWidget::onWidgetValuesModified()
563 {
564   setValueState(ModifiedInPP);
565 }
566
567 //**************************************************************
568 QString ModuleBase_ModelWidget::translate(const std::string& theStr) const
569 {
570   return ModuleBase_Tools::translate(context(), theStr);
571 }
572
573 //**************************************************************
574 ModuleBase_ModelWidget* ModuleBase_ModelWidget::findModelWidget(ModuleBase_IPropertyPanel* theProp,
575                                                                 QWidget* theWidget)
576 {
577   ModuleBase_ModelWidget* aModelWidget = 0;
578   if (!theWidget)
579     return aModelWidget;
580
581   QObject* aParent = theWidget->parent();
582   while (aParent) {
583     aModelWidget = qobject_cast<ModuleBase_ModelWidget*>(aParent);
584     if (aModelWidget)
585       break;
586     aParent = aParent->parent();
587   }
588   return aModelWidget;
589 }