1 // Copyright (C) 2014-2019 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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"
26 #include <Events_InfoMessage.h>
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>
34 #include <Config_Keywords.h>
35 #include <Config_WidgetAPI.h>
36 #include <Config_Translator.h>
37 #include <Config_PropManager.h>
39 #include <Events_Loop.h>
43 #include <QFocusEvent>
46 //#define DEBUG_VALUE_STATE
48 //#define DEBUG_WIDGET_INSTANCE
49 //#define DEBUG_ENABLE_SKETCH_INPUT_FIELDS
51 //**************************************************************
52 ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,
53 const Config_WidgetAPI* theData)
57 myIsValueStateBlocked(false),
58 myFlushUpdateBlocked(false),
61 #ifdef DEBUG_WIDGET_INSTANCE
62 qDebug("ModuleBase_ModelWidget::ModuleBase_ModelWidget");
65 myFeatureId = theData->featureId();
67 myIsInternal = theData->getBooleanAttribute(ATTR_INTERNAL, false);
68 myUseExternalParts = theData->getBooleanAttribute("allow_parts_content", false);
70 myIsModifiedInEdit = theData->getProperty(ATTR_MODIFIED_IN_EDIT);
72 myUpdateVisualAttributes = theData->getBooleanAttribute(ATTR_VISUAL_CHANGED, false);
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);
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;
87 connect(this, SIGNAL(valuesChanged()), this, SLOT(onWidgetValuesChanged()));
88 connect(this, SIGNAL(valuesModified()), this, SLOT(onWidgetValuesModified()));
91 //**************************************************************
92 ModuleBase_ModelWidget::~ModuleBase_ModelWidget()
94 #ifdef DEBUG_WIDGET_INSTANCE
95 qDebug("ModuleBase_ModelWidget::~ModuleBase_ModelWidget");
99 //**************************************************************
100 bool ModuleBase_ModelWidget::reset()
102 bool aResult = resetCustom();
104 setValueState(Reset);
109 //**************************************************************
110 bool ModuleBase_ModelWidget::isInitialized(ObjectPtr theObject) const
112 return theObject->data()->attribute(attributeID())->isInitialized();
115 //**************************************************************
116 void ModuleBase_ModelWidget::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
118 theModuleSelectionModes = -1;
119 if (myWidgetValidator)
120 myWidgetValidator->selectionModes(theModuleSelectionModes, theModes);
123 //**************************************************************
124 void ModuleBase_ModelWidget::selectionFilters(QIntList& theModuleSelectionFilters,
125 SelectMgr_ListOfFilter& theSelectionFilters)
127 if (myWidgetValidator)
128 myWidgetValidator->selectionFilters(theModuleSelectionFilters, theSelectionFilters);
131 //**************************************************************
132 bool ModuleBase_ModelWidget::isValueEnabled() const
134 bool anEnabled = true;
135 if (myIsValueEnabled == DefinedInPreferences) {
136 #ifdef DEBUG_ENABLE_SKETCH_INPUT_FIELDS
137 bool aCanDisable = false;
139 //Config_PropManager::boolean(SKETCH_TAB_NAME, "disable_input_fields", "true");
140 bool aCanDisable = true;
145 else if (myIsValueEnabled == Off)
150 //**************************************************************
151 void ModuleBase_ModelWidget::processValueState()
153 if (myState == ModifiedInPP || myState == ModifiedInViewer)
157 //**************************************************************
158 Events_InfoMessage ModuleBase_ModelWidget::getValueStateError() const
160 Events_InfoMessage aMessage;
161 aMessage.setContext(context());
163 ModuleBase_ModelWidget::ValueState aState = getValueState();
164 if (aState != ModuleBase_ModelWidget::Stored) {
165 AttributePtr anAttr = feature()->attribute(attributeID());
167 const std::string& anAttributeName = anAttr->id();
169 case ModuleBase_ModelWidget::ModifiedInViewer:
170 aMessage = "Attribute \"%1\" is locked by modification value in the viewer.";
171 aMessage.addParameter(anAttributeName);
173 case ModuleBase_ModelWidget::Reset:
174 aMessage = "Attribute \"%1\" is not initialized.";
175 aMessage.addParameter(anAttributeName);
177 case ModuleBase_ModelWidget::ModifiedInPP: // Apply should be enabled in this mode
186 //**************************************************************
187 QString ModuleBase_ModelWidget::getError(const bool theValueStateChecked) const
191 if (!feature().get())
194 std::string aFeatureID = feature()->getKind();
195 std::string anAttributeID = attributeID();
196 AttributePtr anAttribute = feature()->attribute(anAttributeID);
197 if (!anAttribute.get())
200 std::string aValidatorID;
201 Events_InfoMessage anErrorMsg;
203 static ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
204 if (!aValidators->validate(anAttribute, aValidatorID, anErrorMsg)) {
205 if (anErrorMsg.empty())
206 anErrorMsg = "Unknown error.";
208 if (anErrorMsg.context().empty()) {
209 anErrorMsg.setContext(aFeatureID + ":" + anAttributeID + ":" + aValidatorID);
213 if (anErrorMsg.empty() && theValueStateChecked) {
214 anErrorMsg = getValueStateError();
217 if (!anErrorMsg.empty()) {
218 anError = ModuleBase_Tools::translate(anErrorMsg);
224 //**************************************************************
225 void ModuleBase_ModelWidget::enableFocusProcessing()
227 QList<QWidget*> aMyControls = getControls();
228 foreach(QWidget* eachControl, aMyControls) {
229 eachControl->setFocusPolicy(Qt::StrongFocus);
230 eachControl->installEventFilter(this);
234 //**************************************************************
235 void ModuleBase_ModelWidget::setHighlighted(bool isHighlighted)
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
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);
249 //**************************************************************
250 void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool theToStoreValue,
251 const bool isUpdateFlushed)
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())
264 myFlushUpdateBlocked = false;
267 //**************************************************************
268 bool ModuleBase_ModelWidget::focusTo()
270 #ifdef DEBUG_WIDGET_INSTANCE
271 qDebug("ModuleBase_ModelWidget::focusTo");
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;
283 return isFocusAccepted;
286 //**************************************************************
287 void ModuleBase_ModelWidget::activate()
289 #ifdef DEBUG_WIDGET_INSTANCE
290 qDebug("ModuleBase_ModelWidget::activate");
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();
303 //**************************************************************
304 void ModuleBase_ModelWidget::deactivate()
306 #ifdef DEBUG_WIDGET_INSTANCE
307 qDebug("ModuleBase_ModelWidget::deactivate");
309 myIsValueStateBlocked = false;
311 if (myWidgetValidator)
312 myWidgetValidator->clearValidatedCash();
315 //**************************************************************
316 void ModuleBase_ModelWidget::initializeValueByActivate()
318 if (isComputedDefault()) {
319 if (myFeature->compute(myAttributeID)) {
328 //**************************************************************
329 QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)
331 QWidget* aControl = 0;
333 QList<QWidget*> aControls = getControls();
334 int aSize = aControls.size();
337 for (int i = 0; i < aSize && !aControl; i++) {
338 if (aControls[i]->focusPolicy() != Qt::NoFocus)
339 aControl = aControls[i];
343 for (int i = aSize - 1; i >= 0 && !aControl; i--) {
344 if (aControls[i]->focusPolicy() != Qt::NoFocus)
345 aControl = aControls[i];
351 //**************************************************************
352 void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)
354 myDefaultValue = theValue;
357 //**************************************************************
358 bool ModuleBase_ModelWidget::storeValue()
360 setValueState(Stored);
362 emit beforeValuesChanged();
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();
369 /// store value in an alternative attribute if possible(attribute has the same type)
370 std::string aWidgetAttribute = attributeID();
371 myAttributeID = isModifiedInEdit();
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
379 emit afterValuesChanged();
383 #ifdef DEBUG_VALUE_STATE
385 //**************************************************************
386 std::string getDebugInfo(const ModuleBase_ModelWidget::ValueState& 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;
400 //**************************************************************
401 ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState
402 (const ModuleBase_ModelWidget::ValueState& theState)
404 ValueState aState = myState;
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());
413 emit valueStateChanged(aState);
418 //**************************************************************
419 bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
421 bool isBlocked = myIsValueStateBlocked;
422 myIsValueStateBlocked = theBlocked;
426 //**************************************************************
427 bool ModuleBase_ModelWidget::restoreValue()
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
435 emit beforeValuesRestored();
436 bool isDone = restoreValueCustom();
437 emit afterValuesRestored();
442 //**************************************************************
443 void ModuleBase_ModelWidget::updateObject(ObjectPtr theObject)
445 if (!myFlushUpdateBlocked) {
446 #ifdef DEBUG_WIDGET_INSTANCE
447 qDebug("ModuleBase_ModelWidget::updateObject");
449 if (myFeature.get() && myUpdateVisualAttributes) {
450 static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
451 ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
453 ModuleBase_Tools::flushUpdated(theObject);
454 emit objectUpdated();
458 //**************************************************************
459 bool ModuleBase_ModelWidget::canProcessAction(ModuleBase_ActionType theActionType,
460 bool& isActionEnabled)
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;
475 //**************************************************************
476 bool ModuleBase_ModelWidget::processAction(ModuleBase_ActionType theActionType,
477 const ActionParamPtr& theParam)
479 switch (theActionType) {
481 return processEnter();
483 return processEscape();
485 return processDelete();
486 case ActionSelection:
495 //**************************************************************
496 bool ModuleBase_ModelWidget::processEnter()
501 //**************************************************************
502 bool ModuleBase_ModelWidget::processEscape()
507 //**************************************************************
508 bool ModuleBase_ModelWidget::processDelete()
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
515 //**************************************************************
516 bool ModuleBase_ModelWidget::processSelection()
521 //**************************************************************
522 bool ModuleBase_ModelWidget::eventFilter(QObject* theObject, QEvent *theEvent)
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)) {
537 else if (theEvent->type() == QEvent::FocusOut) {
538 QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
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) {
551 // pass the event on to the parent class
553 return QObject::eventFilter(theObject, theEvent);
556 //**************************************************************
557 void ModuleBase_ModelWidget::onWidgetValuesChanged()
562 //**************************************************************
563 void ModuleBase_ModelWidget::onWidgetValuesModified()
565 setValueState(ModifiedInPP);
568 //**************************************************************
569 QString ModuleBase_ModelWidget::translate(const std::string& theStr) const
571 return ModuleBase_Tools::translate(context(), theStr);
574 //**************************************************************
575 ModuleBase_ModelWidget* ModuleBase_ModelWidget::findModelWidget(ModuleBase_IPropertyPanel* theProp,
578 ModuleBase_ModelWidget* aModelWidget = 0;
582 QObject* aParent = theWidget->parent();
584 aModelWidget = qobject_cast<ModuleBase_ModelWidget*>(aParent);
587 aParent = aParent->parent();