1 // Copyright (C) 2014-2017 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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
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"
27 #include <Events_InfoMessage.h>
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>
35 #include <Config_Keywords.h>
36 #include <Config_WidgetAPI.h>
37 #include <Config_Translator.h>
38 #include <Config_PropManager.h>
40 #include <Events_Loop.h>
44 #include <QFocusEvent>
47 //#define DEBUG_VALUE_STATE
49 //#define DEBUG_WIDGET_INSTANCE
50 //#define DEBUG_ENABLE_SKETCH_INPUT_FIELDS
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);
69 myIsModifiedInEdit = theData->getProperty(ATTR_MODIFIED_IN_EDIT);
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);
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;
84 connect(this, SIGNAL(valuesChanged()), this, SLOT(onWidgetValuesChanged()));
85 connect(this, SIGNAL(valuesModified()), this, SLOT(onWidgetValuesModified()));
88 ModuleBase_ModelWidget::~ModuleBase_ModelWidget()
90 #ifdef DEBUG_WIDGET_INSTANCE
91 qDebug("ModuleBase_ModelWidget::~ModuleBase_ModelWidget");
95 bool ModuleBase_ModelWidget::reset()
97 bool aResult = resetCustom();
104 bool ModuleBase_ModelWidget::isInitialized(ObjectPtr theObject) const
106 return theObject->data()->attribute(attributeID())->isInitialized();
109 bool ModuleBase_ModelWidget::isValueEnabled() const
111 bool anEnabled = true;
112 if (myIsValueEnabled == DefinedInPreferences) {
113 #ifdef DEBUG_ENABLE_SKETCH_INPUT_FIELDS
114 bool aCanDisable = false;
116 //Config_PropManager::boolean(SKETCH_TAB_NAME, "disable_input_fields", "true");
117 bool aCanDisable = true;
122 else if (myIsValueEnabled == Off)
127 void ModuleBase_ModelWidget::processValueState()
129 if (myState == ModifiedInPP || myState == ModifiedInViewer)
133 Events_InfoMessage ModuleBase_ModelWidget::getValueStateError() const
135 Events_InfoMessage aMessage;
137 ModuleBase_ModelWidget::ValueState aState = getValueState();
138 if (aState != ModuleBase_ModelWidget::Stored) {
139 AttributePtr anAttr = feature()->attribute(attributeID());
141 const std::string& anAttributeName = anAttr->id();
143 case ModuleBase_ModelWidget::ModifiedInViewer:
144 aMessage = "Attribute \"%1\" is locked by modification value in the viewer.";
145 aMessage.addParameter(anAttributeName);
147 case ModuleBase_ModelWidget::Reset:
148 aMessage = "Attribute \"%1\" is not initialized.";
149 aMessage.addParameter(anAttributeName);
151 case ModuleBase_ModelWidget::ModifiedInPP: // Apply should be enabled in this mode
160 QString ModuleBase_ModelWidget::getError(const bool theValueStateChecked) const
164 if (!feature().get())
167 std::string aFeatureID = feature()->getKind();
168 std::string anAttributeID = attributeID();
169 AttributePtr anAttribute = feature()->attribute(anAttributeID);
170 if (!anAttribute.get())
173 std::string aValidatorID;
174 Events_InfoMessage anErrorMsg;
176 static ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
177 if (!aValidators->validate(anAttribute, aValidatorID, anErrorMsg)) {
178 if (anErrorMsg.empty())
179 anErrorMsg = "Unknown error.";
181 if (anErrorMsg.context().empty()) {
182 anErrorMsg.setContext(aFeatureID + ":" + anAttributeID + ":" + aValidatorID);
186 if (anErrorMsg.empty() && theValueStateChecked) {
187 anErrorMsg = getValueStateError();
190 if (!anErrorMsg.empty()) {
191 anError = ModuleBase_Tools::translate(anErrorMsg);
197 void ModuleBase_ModelWidget::enableFocusProcessing()
199 QList<QWidget*> aMyControls = getControls();
200 foreach(QWidget* eachControl, aMyControls) {
201 eachControl->setFocusPolicy(Qt::StrongFocus);
202 eachControl->installEventFilter(this);
206 void ModuleBase_ModelWidget::setHighlighted(bool isHighlighted)
208 QList<QWidget*> aWidgetList = getControls();
209 foreach(QWidget* aWidget, aWidgetList) {
210 QLabel* aLabel = qobject_cast<QLabel*>(aWidget);
211 // We won't set the effect to QLabels - it looks ugly
213 // If effect is the installed on a different widget, setGraphicsEffect() will
214 // remove the effect from the widget and install it on this widget.
215 // That's why we create a new effect for each widget
216 ModuleBase_Tools::setShadowEffect(aWidget, isHighlighted);
220 void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool theToStoreValue,
221 const bool isUpdateFlushed)
223 /// it is possible to give this flag as parameter in storeValue/storeCustomValue
224 /// after debug, it may be corrected
225 myFlushUpdateBlocked = !isUpdateFlushed;
226 myFeature = theFeature;
227 if (theToStoreValue) {
228 /// it is possible that the attribute is filled before the operation is started,
229 /// e.g. by reentrant operation case some attributes are filled by values of
230 /// feature of previous operation, we should not lost them here
231 if (!theFeature->data()->attribute(attributeID())->isInitialized())
234 myFlushUpdateBlocked = false;
237 bool ModuleBase_ModelWidget::focusTo()
239 #ifdef DEBUG_WIDGET_INSTANCE
240 qDebug("ModuleBase_ModelWidget::focusTo");
242 QList<QWidget*> aControls = getControls();
243 QList<QWidget*>::const_iterator anIt = aControls.begin(), aLast = aControls.end();
244 bool isFocusAccepted = false;
245 for (; anIt != aLast && !isFocusAccepted; anIt++) {
246 QWidget* aWidget = *anIt;
247 if (aWidget && aWidget->focusPolicy() != Qt::NoFocus) {
248 ModuleBase_Tools::setFocus(aWidget, "ModuleBase_ModelWidget::focusTo()");
249 isFocusAccepted = true;
252 return isFocusAccepted;
255 void ModuleBase_ModelWidget::activate()
257 #ifdef DEBUG_WIDGET_INSTANCE
258 qDebug("ModuleBase_ModelWidget::activate");
260 // the control value is stored to the mode by the focus in on the widget
261 // we need the value is initialized in order to enable the apply button in the property panel.
262 // It should happens in the creation mode only because all fields are filled in the edition mode
263 if (!isEditingMode()) {
264 AttributePtr anAttribute = myFeature->data()->attribute(myAttributeID);
265 if (anAttribute.get() != NULL && !anAttribute->isInitialized())
266 initializeValueByActivate();
269 if (myWidgetValidator)
270 myWidgetValidator->activateFilters(true);
275 void ModuleBase_ModelWidget::deactivate()
277 #ifdef DEBUG_WIDGET_INSTANCE
278 qDebug("ModuleBase_ModelWidget::deactivate");
280 myIsValueStateBlocked = false;
282 if (myWidgetValidator)
283 myWidgetValidator->activateFilters(false);
286 void ModuleBase_ModelWidget::initializeValueByActivate()
288 if (isComputedDefault()) {
289 if (myFeature->compute(myAttributeID)) {
298 QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)
300 QWidget* aControl = 0;
302 QList<QWidget*> aControls = getControls();
303 int aSize = aControls.size();
306 for (int i = 0; i < aSize && !aControl; i++) {
307 if (aControls[i]->focusPolicy() != Qt::NoFocus)
308 aControl = aControls[i];
312 for (int i = aSize - 1; i >= 0 && !aControl; i--) {
313 if (aControls[i]->focusPolicy() != Qt::NoFocus)
314 aControl = aControls[i];
320 void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)
322 myDefaultValue = theValue;
325 bool ModuleBase_ModelWidget::storeValue()
327 setValueState(Stored);
329 emit beforeValuesChanged();
331 // value is stored only in creation mode and in edition if there is not
332 // XML flag prohibited modification in edit mode(macro feature circle/arc)
333 if (!isEditingMode() || isModifiedInEdit().empty())
334 isDone = storeValueCustom();
336 /// store value in an alternative attribute if possible(attribute has the same type)
337 std::string aWidgetAttribute = attributeID();
338 myAttributeID = isModifiedInEdit();
340 myAttributeID = aWidgetAttribute;
341 // operation will be restarted but if isDone == true, PagedContainer will try to set focus
342 // to the current widget, but will be already deleted
346 emit afterValuesChanged();
350 #ifdef DEBUG_VALUE_STATE
351 std::string getDebugInfo(const ModuleBase_ModelWidget::ValueState& theState)
355 case ModuleBase_ModelWidget::Stored: anInfo = "Stored "; break;
356 case ModuleBase_ModelWidget::ModifiedInPP: anInfo = "ModifiedInPP "; break;
357 case ModuleBase_ModelWidget::ModifiedInViewer: anInfo = "ModifiedInViewer"; break;
358 case ModuleBase_ModelWidget::Reset: anInfo = "Reset "; break;
365 ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState
366 (const ModuleBase_ModelWidget::ValueState& theState)
368 ValueState aState = myState;
370 if (myState != theState && !myIsValueStateBlocked) {
371 #ifdef DEBUG_VALUE_STATE
372 qDebug(QString("setValueState: previous state = %1,\t new state = %2")
373 .arg(getDebugInfo(myState).c_str())
374 .arg(getDebugInfo(theState).c_str()).toStdString().c_str());
377 emit valueStateChanged(aState);
382 bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
384 bool isBlocked = myIsValueStateBlocked;
385 myIsValueStateBlocked = theBlocked;
389 bool ModuleBase_ModelWidget::restoreValue()
391 emit beforeValuesRestored();
392 bool isDone = restoreValueCustom();
393 emit afterValuesRestored();
398 void ModuleBase_ModelWidget::updateObject(ObjectPtr theObject)
400 if (!myFlushUpdateBlocked) {
401 #ifdef DEBUG_WIDGET_INSTANCE
402 qDebug("ModuleBase_ModelWidget::updateObject");
404 ModuleBase_Tools::flushUpdated(theObject);
405 emit objectUpdated();
409 bool ModuleBase_ModelWidget::canProcessAction(ModuleBase_ActionType theActionType,
410 bool& isActionEnabled)
412 isActionEnabled = false;
413 switch (theActionType) {
414 case ActionEnter: return false;
415 case ActionEscape: return false;
416 case ActionDelete: return true;
424 bool ModuleBase_ModelWidget::processAction(ModuleBase_ActionType theActionType)
426 switch (theActionType) {
428 return processEnter();
430 return processEscape();
432 return processDelete();
440 bool ModuleBase_ModelWidget::processEnter()
445 bool ModuleBase_ModelWidget::processEscape()
450 bool ModuleBase_ModelWidget::processDelete()
452 // we consider that model objects eats delete key in order to
453 // do nothing by for example symbol delete in line edit or spin box
457 bool ModuleBase_ModelWidget::eventFilter(QObject* theObject, QEvent *theEvent)
459 QWidget* aWidget = qobject_cast<QWidget*>(theObject);
460 if (theEvent->type() == QEvent::FocusIn) {
461 QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
462 Qt::FocusReason aReason = aFocusEvent->reason();
463 bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
464 /*aReason == Qt::TabFocusReason ||
465 //aReason == Qt::BacktabFocusReason ||*/
466 aReason == Qt::OtherFocusReason; // to process widget->setFocus()
467 if (aMouseOrKey && getControls().contains(aWidget)) {
468 //if (getControls().contains(aWidget)) {
472 else if (theEvent->type() == QEvent::FocusOut) {
473 QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);
475 Qt::FocusReason aReason = aFocusEvent->reason();
476 bool aMouseOrKey = aReason == Qt::MouseFocusReason ||
477 aReason == Qt::TabFocusReason ||
478 aReason == Qt::BacktabFocusReason ||
479 aReason == Qt::OtherFocusReason; // to process widget->setFocus()
480 if (aMouseOrKey && getControls().contains(aWidget)) {
481 if (getValueState() == ModifiedInPP) {
486 // pass the event on to the parent class
488 return QObject::eventFilter(theObject, theEvent);
491 //**************************************************************
492 void ModuleBase_ModelWidget::onWidgetValuesChanged()
497 //**************************************************************
498 void ModuleBase_ModelWidget::onWidgetValuesModified()
500 setValueState(ModifiedInPP);
503 //**************************************************************
504 QString ModuleBase_ModelWidget::translate(const std::string& theStr) const
506 return ModuleBase_Tools::translate(context(), theStr);
509 //**************************************************************
510 ModuleBase_ModelWidget* ModuleBase_ModelWidget::findModelWidget(ModuleBase_IPropertyPanel* theProp,
513 ModuleBase_ModelWidget* aModelWidget = 0;
517 QObject* aParent = theWidget->parent();
519 aModelWidget = qobject_cast<ModuleBase_ModelWidget*>(aParent);
522 aParent = aParent->parent();