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