]> SALOME platform Git repositories - modules/shaper.git/blob - src/ModuleBase/ModuleBase_ModelWidget.cpp
Salome HOME
Multiple fixes (issue #1757 , issue #1799 , issue #1842 , etc):
[modules/shaper.git] / src / ModuleBase / ModuleBase_ModelWidget.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D\r
2 \r
3 // File:        ModuleBase_ModelWidget.cpp\r
4 // Created:     25 Apr 2014\r
5 // Author:      Natalia ERMOLAEVA\r
6 \r
7 #include "ModuleBase_ModelWidget.h"\r
8 #include "ModuleBase_ViewerPrs.h"\r
9 #include "ModuleBase_Tools.h"\r
10 #include "ModuleBase_WidgetValidator.h"\r
11 \r
12 #include <Events_InfoMessage.h>\r
13 \r
14 #include <ModelAPI_Data.h>\r
15 #include <ModelAPI_Attribute.h>\r
16 #include <ModelAPI_Events.h>\r
17 #include <ModelAPI_Session.h>\r
18 #include <ModelAPI_Validator.h>\r
19 \r
20 #include <Config_Keywords.h>\r
21 #include <Config_WidgetAPI.h>\r
22 #include <Config_Translator.h>\r
23 #include <Config_PropManager.h>\r
24 \r
25 #include <Events_Loop.h>\r
26 \r
27 #include <QEvent>\r
28 #include <QLabel>\r
29 #include <QFocusEvent>\r
30 #include <QTextCodec>\r
31 \r
32 //#define DEBUG_VALUE_STATE\r
33 \r
34 //#define DEBUG_WIDGET_INSTANCE\r
35 //#define DEBUG_ENABLE_SKETCH_INPUT_FIELDS\r
36 \r
37 ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,\r
38                                                const Config_WidgetAPI* theData)\r
39     : QWidget(theParent),\r
40       myIsEditing(false),\r
41       myState(Stored),\r
42       myIsValueStateBlocked(false),\r
43       myFlushUpdateBlocked(false),\r
44       myWidgetValidator(0)\r
45 {\r
46 #ifdef DEBUG_WIDGET_INSTANCE\r
47   qDebug("ModuleBase_ModelWidget::ModuleBase_ModelWidget");\r
48 #endif\r
49 \r
50   myIsInternal = theData->getBooleanAttribute(ATTR_INTERNAL, false);\r
51 \r
52   myDefaultValue = theData->getProperty(ATTR_DEFAULT);\r
53   myUseReset = theData->getBooleanAttribute(ATTR_USE_RESET, true);\r
54   myIsComputedDefault = theData->getProperty(ATTR_DEFAULT) == DOUBLE_WDG_DEFAULT_COMPUTED;\r
55   myAttributeID = theData ? theData->widgetId() : "";\r
56   myIsObligatory = theData->getBooleanAttribute(ATTR_OBLIGATORY, true);\r
57 \r
58   myIsValueEnabled = On; // not defined or "true"\r
59   std::string anEnableValue = theData->getProperty(DOUBLE_WDG_ENABLE_VALUE);\r
60   if (anEnableValue == "false")\r
61     myIsValueEnabled = Off;\r
62   if (anEnableValue == DOUBLE_WDG_ENABLE_VALUE_BY_PREFERENCES)\r
63     myIsValueEnabled = DefinedInPreferences;\r
64 \r
65   connect(this, SIGNAL(valuesChanged()), this, SLOT(onWidgetValuesChanged()));\r
66   connect(this, SIGNAL(valuesModified()), this, SLOT(onWidgetValuesModified()));\r
67 }\r
68 \r
69 ModuleBase_ModelWidget::~ModuleBase_ModelWidget()\r
70 {\r
71 #ifdef DEBUG_WIDGET_INSTANCE\r
72   qDebug("ModuleBase_ModelWidget::~ModuleBase_ModelWidget");\r
73 #endif\r
74 }\r
75 \r
76 bool ModuleBase_ModelWidget::reset()\r
77 {\r
78   bool aResult = resetCustom();\r
79   if (aResult)\r
80     setValueState(Reset);\r
81 \r
82   return aResult;\r
83 }\r
84 \r
85 bool ModuleBase_ModelWidget::isInitialized(ObjectPtr theObject) const\r
86 {\r
87   return theObject->data()->attribute(attributeID())->isInitialized();\r
88 }\r
89 \r
90 bool ModuleBase_ModelWidget::isValueEnabled() const\r
91 {\r
92   bool anEnabled = true;\r
93   if (myIsValueEnabled == DefinedInPreferences) {\r
94 #ifdef DEBUG_ENABLE_SKETCH_INPUT_FIELDS\r
95     bool aCanDisable = false;\r
96 #else\r
97     bool aCanDisable = true;//Config_PropManager::boolean(SKETCH_TAB_NAME, "disable_input_fields", "true");\r
98 #endif\r
99     if (aCanDisable)\r
100       anEnabled = false;\r
101   }\r
102   else if (myIsValueEnabled == Off)\r
103     anEnabled = false;\r
104   return anEnabled;\r
105 }\r
106 \r
107 void ModuleBase_ModelWidget::processValueState()\r
108 {\r
109   if (myState == ModifiedInPP || myState == ModifiedInViewer)\r
110     storeValue();\r
111 }\r
112 \r
113 QString ModuleBase_ModelWidget::getValueStateError() const\r
114 {\r
115   QString anError = "";\r
116 \r
117   ModuleBase_ModelWidget::ValueState aState = getValueState();\r
118   if (aState != ModuleBase_ModelWidget::Stored) {\r
119     AttributePtr anAttr = feature()->attribute(attributeID());\r
120     if (anAttr.get()) {\r
121       QString anAttributeName = anAttr->id().c_str();\r
122       switch (aState) {\r
123         case ModuleBase_ModelWidget::ModifiedInViewer:\r
124           anError = "Attribute \"" + anAttributeName +\r
125                     "\" is locked by modification value in the viewer.";\r
126           break;\r
127         case ModuleBase_ModelWidget::Reset:\r
128           anError = "Attribute \"" + anAttributeName + "\" is not initialized.";\r
129           break;\r
130         case ModuleBase_ModelWidget::ModifiedInPP: // Apply should be enabled in this mode\r
131         default:\r
132           break;\r
133       }\r
134     }\r
135   }\r
136   return anError;\r
137 }\r
138 \r
139 QString ModuleBase_ModelWidget::getError(const bool theValueStateChecked) const\r
140 {\r
141   QString anError;\r
142 \r
143   if (!feature().get())\r
144     return anError;\r
145 \r
146   std::string anAttributeID = attributeID();\r
147   AttributePtr anAttribute = feature()->attribute(anAttributeID);\r
148   if (!anAttribute.get())\r
149     return anError;\r
150 \r
151   std::string aValidatorID;\r
152   Events_InfoMessage anErrorMsg;\r
153 \r
154   static ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();\r
155   if (!aValidators->validate(anAttribute, aValidatorID, anErrorMsg)) {\r
156     if (anErrorMsg.empty())\r
157       anErrorMsg = "unknown error.";\r
158     anErrorMsg = anAttributeID + " - " + aValidatorID + ": " + anErrorMsg.messageString();\r
159   }\r
160 \r
161   if (!anErrorMsg.empty()) {\r
162     std::string aStr = Config_Translator::translate(anErrorMsg);\r
163     std::string aCodec = Config_Translator::codec(anErrorMsg.context());\r
164     anError = QTextCodec::codecForName(aCodec.c_str())->toUnicode(aStr.c_str());\r
165   }\r
166 \r
167   if (anError.isEmpty() && theValueStateChecked)\r
168     anError = getValueStateError();\r
169 \r
170   anError = translateString(anError);\r
171   return anError;\r
172 }\r
173 \r
174 \r
175 QString ModuleBase_ModelWidget::translateString(const QString& theMsg) const\r
176 {\r
177   if (!theMsg.isEmpty()) {\r
178     std::string aContext = feature()->getKind();\r
179     std::string aStr = Config_Translator::translate(aContext, theMsg.toStdString().c_str());\r
180     std::string aCodec = Config_Translator::codec(aContext);\r
181     return QTextCodec::codecForName(aCodec.c_str())->toUnicode(aStr.c_str());\r
182   }\r
183   return theMsg;\r
184 }\r
185 \r
186 \r
187 void ModuleBase_ModelWidget::enableFocusProcessing()\r
188 {\r
189   QList<QWidget*> aMyControls = getControls();\r
190   foreach(QWidget*  eachControl, aMyControls) {\r
191       eachControl->setFocusPolicy(Qt::StrongFocus);\r
192       eachControl->installEventFilter(this);\r
193   }\r
194 }\r
195 \r
196 void ModuleBase_ModelWidget::setHighlighted(bool isHighlighted)\r
197 {\r
198   QList<QWidget*> aWidgetList = getControls();\r
199   foreach(QWidget* aWidget, aWidgetList) {\r
200     QLabel* aLabel = qobject_cast<QLabel*>(aWidget);\r
201     // We won't set the effect to QLabels - it looks ugly\r
202     if(aLabel) continue;\r
203     // If effect is the installed on a different widget, setGraphicsEffect() will\r
204     // remove the effect from the widget and install it on this widget.\r
205     // That's why we create a new effect for each widget\r
206     ModuleBase_Tools::setShadowEffect(aWidget, isHighlighted);\r
207   }\r
208 }\r
209 \r
210 void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool theToStoreValue,\r
211                                         const bool isUpdateFlushed)\r
212 {\r
213   /// it is possible to give this flag as parameter in storeValue/storeCustomValue\r
214   /// after debug, it may be corrected\r
215   myFlushUpdateBlocked = !isUpdateFlushed;\r
216   myFeature = theFeature;\r
217   if (theToStoreValue) {\r
218     /// it is possible that the attribute is filled before the operation is started,\r
219     /// e.g. by reentrant operation case some attributes are filled by values of\r
220     /// feature of previous operation, we should not lost them here\r
221     if (!theFeature->data()->attribute(attributeID())->isInitialized())\r
222       storeValue();\r
223   }\r
224   myFlushUpdateBlocked = false;\r
225 }\r
226 \r
227 bool ModuleBase_ModelWidget::focusTo()\r
228 {\r
229 #ifdef DEBUG_WIDGET_INSTANCE\r
230   qDebug("ModuleBase_ModelWidget::focusTo");\r
231 #endif\r
232   QList<QWidget*> aControls = getControls();\r
233   QList<QWidget*>::const_iterator anIt = aControls.begin(), aLast = aControls.end();\r
234   bool isFocusAccepted = false;\r
235   for (; anIt != aLast && !isFocusAccepted; anIt++) {\r
236     QWidget* aWidget = *anIt;\r
237     if (aWidget && aWidget->focusPolicy() != Qt::NoFocus) {\r
238       ModuleBase_Tools::setFocus(aWidget, "ModuleBase_ModelWidget::focusTo()");\r
239       isFocusAccepted = true;\r
240     }\r
241   }\r
242   return isFocusAccepted;\r
243 }\r
244 \r
245 void ModuleBase_ModelWidget::activate()\r
246 {\r
247 #ifdef DEBUG_WIDGET_INSTANCE\r
248   qDebug("ModuleBase_ModelWidget::activate");\r
249 #endif\r
250   // the control value is stored to the mode by the focus in on the widget\r
251   // we need the value is initialized in order to enable the apply button in the property panel.\r
252   // It should happens in the creation mode only because all fields are filled in the edition mode\r
253   if (!isEditingMode()) {\r
254     AttributePtr anAttribute = myFeature->data()->attribute(myAttributeID);\r
255     if (anAttribute.get() != NULL && !anAttribute->isInitialized())\r
256       initializeValueByActivate();\r
257   }\r
258 \r
259   if (myWidgetValidator)\r
260     myWidgetValidator->activateFilters(true);\r
261 \r
262   activateCustom();\r
263 }\r
264 \r
265 void ModuleBase_ModelWidget::deactivate()\r
266 {\r
267 #ifdef DEBUG_WIDGET_INSTANCE\r
268   qDebug("ModuleBase_ModelWidget::deactivate");\r
269 #endif\r
270   myIsValueStateBlocked = false;\r
271   myState = Stored;\r
272   if (myWidgetValidator)\r
273     myWidgetValidator->activateFilters(false);\r
274 }\r
275 \r
276 void ModuleBase_ModelWidget::initializeValueByActivate()\r
277 {\r
278   if (isComputedDefault()) {\r
279     if (myFeature->compute(myAttributeID)) {\r
280       restoreValue();\r
281     }\r
282   }\r
283   else {\r
284     storeValue();\r
285   }\r
286 }\r
287 \r
288 QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)\r
289 {\r
290   QWidget* aControl = 0;\r
291 \r
292   QList<QWidget*> aControls = getControls();\r
293   int aSize = aControls.size();\r
294 \r
295   if (isFirst) {\r
296     for (int i = 0; i < aSize && !aControl; i++)  {\r
297       if (aControls[i]->focusPolicy() != Qt::NoFocus)\r
298         aControl = aControls[i];\r
299     }\r
300   }\r
301   else {\r
302     for (int i = aSize - 1; i >= 0 && !aControl; i--)  {\r
303       if (aControls[i]->focusPolicy() != Qt::NoFocus)\r
304         aControl = aControls[i];\r
305     }\r
306   }\r
307   return aControl;\r
308 }\r
309 \r
310 void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)\r
311 {\r
312   myDefaultValue = theValue;\r
313 }\r
314 \r
315 bool ModuleBase_ModelWidget::storeValue()\r
316 {\r
317   setValueState(Stored);\r
318 \r
319   emit beforeValuesChanged();\r
320   bool isDone = storeValueCustom();\r
321   emit afterValuesChanged();\r
322 \r
323   return isDone;\r
324 }\r
325 #ifdef DEBUG_VALUE_STATE\r
326 std::string getDebugInfo(const ModuleBase_ModelWidget::ValueState& theState)\r
327 {\r
328   std::string anInfo;\r
329   switch (theState) {\r
330     case ModuleBase_ModelWidget::Stored:           anInfo = "Stored          "; break;\r
331     case ModuleBase_ModelWidget::ModifiedInPP:     anInfo = "ModifiedInPP    "; break;\r
332     case ModuleBase_ModelWidget::ModifiedInViewer: anInfo = "ModifiedInViewer"; break;\r
333     case ModuleBase_ModelWidget::Reset:            anInfo = "Reset           "; break;\r
334     default: break;\r
335   }\r
336   return anInfo;\r
337 }\r
338 \r
339 #endif\r
340 ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState\r
341                                          (const ModuleBase_ModelWidget::ValueState& theState)\r
342 {\r
343   ValueState aState = myState;\r
344 \r
345   if (myState != theState && !myIsValueStateBlocked) {\r
346 #ifdef DEBUG_VALUE_STATE\r
347     qDebug(QString("setValueState: previous state = %1,\t new state = %2")\r
348            .arg(getDebugInfo(myState).c_str())\r
349            .arg(getDebugInfo(theState).c_str()).toStdString().c_str());\r
350 #endif\r
351     myState = theState;\r
352     emit valueStateChanged(aState);\r
353   }\r
354   return aState;\r
355 }\r
356 \r
357 bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)\r
358 {\r
359   bool isBlocked = myIsValueStateBlocked;\r
360   myIsValueStateBlocked = theBlocked;\r
361   return isBlocked;\r
362 }\r
363 \r
364 bool ModuleBase_ModelWidget::restoreValue()\r
365 {\r
366   emit beforeValuesRestored();\r
367   bool isDone = restoreValueCustom();\r
368   emit afterValuesRestored();\r
369 \r
370   return isDone;\r
371 }\r
372 \r
373 void ModuleBase_ModelWidget::updateObject(ObjectPtr theObject)\r
374 {\r
375   if (!myFlushUpdateBlocked) {\r
376 #ifdef DEBUG_WIDGET_INSTANCE\r
377     qDebug("ModuleBase_ModelWidget::updateObject");\r
378 #endif\r
379     ModuleBase_Tools::flushUpdated(theObject);\r
380     emit objectUpdated();\r
381   }\r
382 }\r
383 \r
384 void ModuleBase_ModelWidget::moveObject(ObjectPtr theObj)\r
385 {\r
386   //blockUpdateViewer(true);\r
387 #ifdef DEBUG_WIDGET_INSTANCE\r
388   qDebug("ModuleBase_ModelWidget::moveObject");\r
389 #endif\r
390 \r
391   static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);\r
392   ModelAPI_EventCreator::get()->sendUpdated(theObj, anEvent);\r
393   Events_Loop::loop()->flush(anEvent);\r
394 \r
395   //blockUpdateViewer(false);\r
396 }\r
397 \r
398 bool ModuleBase_ModelWidget::processEnter()\r
399 {\r
400   return false;\r
401 }\r
402 \r
403 bool ModuleBase_ModelWidget::processDelete()\r
404 {\r
405   // we consider that model objects eats delete key in order to\r
406   // do nothing by for example symbol delete in line edit or spin box\r
407   return true;\r
408 }\r
409 \r
410 bool ModuleBase_ModelWidget::eventFilter(QObject* theObject, QEvent *theEvent)\r
411 {\r
412   QWidget* aWidget = qobject_cast<QWidget*>(theObject);\r
413   if (theEvent->type() == QEvent::FocusIn) {\r
414     #ifdef _DEBUG\r
415     // The following two lines are for debugging purpose only\r
416     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);\r
417     bool isWinFocus = aFocusEvent->reason() == Qt::ActiveWindowFocusReason;\r
418     #endif\r
419     if (getControls().contains(aWidget)) {\r
420       emit focusInWidget(this);\r
421     }\r
422   }\r
423   else if (theEvent->type() == QEvent::FocusOut) {\r
424     QFocusEvent* aFocusEvent = dynamic_cast<QFocusEvent*>(theEvent);\r
425 \r
426     Qt::FocusReason aReason = aFocusEvent->reason();\r
427     bool aMouseOrKey = aReason == Qt::MouseFocusReason ||\r
428                         aReason == Qt::TabFocusReason ||\r
429                         aReason == Qt::BacktabFocusReason ||\r
430                         aReason == Qt::OtherFocusReason; // to process widget->setFocus()\r
431     if (aMouseOrKey && getControls().contains(aWidget)) {\r
432       if (getValueState() == ModifiedInPP) {\r
433         storeValue();\r
434       }\r
435     }\r
436   }\r
437   // pass the event on to the parent class\r
438 \r
439   return QObject::eventFilter(theObject, theEvent);\r
440 }\r
441 \r
442 //**************************************************************\r
443 void ModuleBase_ModelWidget::onWidgetValuesChanged()\r
444 {\r
445   storeValue();\r
446 }\r
447 \r
448 //**************************************************************\r
449 void ModuleBase_ModelWidget::onWidgetValuesModified()\r
450 {\r
451   setValueState(ModifiedInPP);\r
452 }\r