From a12201ecb4883c5042b364cc68523c7235b035b8 Mon Sep 17 00:00:00 2001 From: spo Date: Thu, 24 Dec 2015 12:18:46 +0300 Subject: [PATCH] Issue #1158: To use parameters in integer attributes -- GUI --- src/ModuleBase/CMakeLists.txt | 2 + src/ModuleBase/ModuleBase_ParamIntSpinBox.cpp | 208 ++++++++++++++++++ src/ModuleBase/ModuleBase_ParamIntSpinBox.h | 87 ++++++++ src/ModuleBase/ModuleBase_Tools.cpp | 22 ++ src/ModuleBase/ModuleBase_Tools.h | 11 + .../ModuleBase_WidgetDoubleValue.cpp | 2 +- src/ModuleBase/ModuleBase_WidgetIntValue.cpp | 45 ++-- src/ModuleBase/ModuleBase_WidgetIntValue.h | 7 +- 8 files changed, 366 insertions(+), 18 deletions(-) create mode 100644 src/ModuleBase/ModuleBase_ParamIntSpinBox.cpp create mode 100644 src/ModuleBase/ModuleBase_ParamIntSpinBox.h diff --git a/src/ModuleBase/CMakeLists.txt b/src/ModuleBase/CMakeLists.txt index 48c904e16..bc1ab4e90 100644 --- a/src/ModuleBase/CMakeLists.txt +++ b/src/ModuleBase/CMakeLists.txt @@ -30,6 +30,7 @@ SET(PROJECT_HEADERS ModuleBase_PageGroupBox.h ModuleBase_PageWidget.h ModuleBase_PagedContainer.h + ModuleBase_ParamIntSpinBox.h ModuleBase_ParamSpinBox.h ModuleBase_Preferences.h ModuleBase_ResultPrs.h @@ -85,6 +86,7 @@ SET(PROJECT_SOURCES ModuleBase_PageGroupBox.cpp ModuleBase_PageWidget.cpp ModuleBase_PagedContainer.cpp + ModuleBase_ParamIntSpinBox.cpp ModuleBase_ParamSpinBox.cpp ModuleBase_Preferences.cpp ModuleBase_ResultPrs.cpp diff --git a/src/ModuleBase/ModuleBase_ParamIntSpinBox.cpp b/src/ModuleBase/ModuleBase_ParamIntSpinBox.cpp new file mode 100644 index 000000000..b3f286dc2 --- /dev/null +++ b/src/ModuleBase/ModuleBase_ParamIntSpinBox.cpp @@ -0,0 +1,208 @@ +#include "ModuleBase_ParamIntSpinBox.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +ModuleBase_ParamIntSpinBox::ModuleBase_ParamIntSpinBox(QWidget* theParent) + : ModuleBase_IntSpinBox(theParent), + myAcceptVariables(true) +{ + connectSignalsAndSlots(); +} + +/*! + \brief Destructor. + */ +ModuleBase_ParamIntSpinBox::~ModuleBase_ParamIntSpinBox() +{ +} + +/*! + \brief Perform \a steps increment/decrement steps. + + Re-implemented to handle cases when Notebook variable + name is specified by the user as the widget text. + Otherwise, simply calls the base implementation. + + \param steps number of increment/decrement steps + */ +void ModuleBase_ParamIntSpinBox::stepBy(int steps) +{ + if ((!myTextValue.isEmpty()) && hasVariable()) + return; + + ModuleBase_IntSpinBox::stepBy(steps); +} + +/*! + \brief Connect signals and slots. + */ +void ModuleBase_ParamIntSpinBox::connectSignalsAndSlots() +{ + connect(this, SIGNAL(valueChanged(const QString&)), + this, SLOT(onTextChanged(const QString&))); +} + +void ModuleBase_ParamIntSpinBox::onTextChanged(const QString& text) +{ + myTextValue = text; +} + +int ModuleBase_ParamIntSpinBox::valueFromText(const QString& theText) const +{ + if (!hasVariable(theText)) + return ModuleBase_IntSpinBox::valueFromText(theText); + + // small hack: return hash of the string to initiate valuesChanged signal + return qHash(theText); +} + +QString ModuleBase_ParamIntSpinBox::textFromValue(int theValue) const +{ + if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)){ + return myTextValue; + } + return ModuleBase_IntSpinBox::textFromValue(theValue); +} + +/*! + \brief This function is used to determine whether input is valid. + \param str currently entered value + \param pos cursor position in the string + \return validating operation result + */ +QValidator::State ModuleBase_ParamIntSpinBox::validate(QString& str, int& pos) const +{ + // Trying to interpret the current input text as a numeric value + if (!hasVariable(str)) + return ModuleBase_IntSpinBox::validate(str, pos); + + QValidator::State res = QValidator::Invalid; + if (isAcceptVariables()) { + res = QValidator::Acceptable; + } + return res; +} + +/*! + \brief This function is used to set a current value for this spinbox. + \param value current value + + The new value is ignored if the spinbox has a variable. + */ +void ModuleBase_ParamIntSpinBox::setValue(int value) +{ + if (hasVariable()) + return; + + myTextValue = ModuleBase_IntSpinBox::textFromValue(value); + ModuleBase_IntSpinBox::setValue(value); +} + +/*! + \brief This function is used to set a text for this spinbox. + \param value current value + */ +void ModuleBase_ParamIntSpinBox::setText(const QString& value) +{ + myTextValue = value; + lineEdit()->setText(value); +} + +/*! + \brief Enables or disables variable names in the spin box. + By default, variable names are enabled. + \param flag If true, variable names are enabled. + */ +void ModuleBase_ParamIntSpinBox::setAcceptVariables(const bool flag) +{ + myAcceptVariables = flag; +} + +/*! + \brief Returns true if the spin box accepts variable names. + */ +bool ModuleBase_ParamIntSpinBox::isAcceptVariables() const +{ + return myAcceptVariables; +} + +bool ModuleBase_ParamIntSpinBox::hasVariable() const +{ + if (myTextValue.isEmpty()) + return false; + return hasVariable(myTextValue); +} + +bool ModuleBase_ParamIntSpinBox::hasVariable(const QString& theText) const +{ + bool ok = false; + QLocale::c().toInt(theText, &ok); + return !ok; +} + +/*! + \brief This function is used to determine whether input is valid. + \return validating operation result + */ +ModuleBase_ParamIntSpinBox::State ModuleBase_ParamIntSpinBox::isValid( + const QString& theText, double& theValue) const +{ + if (hasVariable() && !findVariable(theText, theValue)) { + bool ok = false; + theValue = locale().toInt(theText, &ok); + if (!ok) { + return NoVariable; + } + } + if (!checkRange(theValue)) { + return Invalid; + } + + return Acceptable; +} + +/*! + \brief This function is used to check that string value lies within predefined range. + \return check status + */ +bool ModuleBase_ParamIntSpinBox::checkRange(const double theValue) const +{ + return theValue >= minimum() && theValue <= maximum(); +} + +/*! + \brief This function is used to determine whether input is a variable name and to get its value. + \return status of search operation + */ +bool ModuleBase_ParamIntSpinBox::findVariable(const QString& theName, + double& outValue) const +{ + ResultParameterPtr aParam; + return ModelAPI_Tools::findVariable(theName.toStdString(), outValue, aParam); +} + +/*! + \brief This function is called when the spinbox receives show event. + */ +void ModuleBase_ParamIntSpinBox::showEvent(QShowEvent* theEvent) +{ + ModuleBase_IntSpinBox::showEvent(theEvent); + if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)) { + setText(myTextValue); + } +} diff --git a/src/ModuleBase/ModuleBase_ParamIntSpinBox.h b/src/ModuleBase/ModuleBase_ParamIntSpinBox.h new file mode 100644 index 000000000..d72895301 --- /dev/null +++ b/src/ModuleBase/ModuleBase_ParamIntSpinBox.h @@ -0,0 +1,87 @@ + +#ifndef ModuleBase_ParamIntSpinBox_H +#define ModuleBase_ParamIntSpinBox_H + +#include "ModuleBase.h" + +#include + +#include + +/** +* \ingroup GUI +* An extension of a double spin box which let to use parameters and expressions for value definition +*/ +class MODULEBASE_EXPORT ModuleBase_ParamIntSpinBox : public ModuleBase_IntSpinBox +{ + Q_OBJECT + + enum State { Invalid = 0, NoVariable, Incompatible, Acceptable }; + +public: + /*! + \brief Constructor. + + Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value, + a step value of 1.0 and a precision of 2 decimal places. + The value is initially set to 0.00. + + \param theParent a parent object + \param thePrecision a precision of values display + */ + explicit ModuleBase_ParamIntSpinBox(QWidget* theParent = 0); + virtual ~ModuleBase_ParamIntSpinBox(); + + virtual void stepBy(int); + + virtual int valueFromText(const QString&) const; + virtual QString textFromValue(int value) const; + + virtual QValidator::State validate(QString&, int&) const; + + virtual void setValue(int); + + virtual void setText(const QString&); + + /// Set a flag about accepted variable + void setAcceptVariables(const bool); + + /// Returns accepted variables flag + bool isAcceptVariables() const; + + /// Returns True if the input value contains variable + bool hasVariable() const; + + protected: + /// Returns True if the given text contains variable + /// \param theText a text string + bool hasVariable(const QString& theText) const; + + /// Returns state of the control + State isValid(const QString&, double&) const; + + /// Returns True if the given value is within min and max of the control + bool checkRange(const double) const; + + /// Finds a variable by its name. Returns true in success + /// \param theName a name of variable + /// \param outValue an output value of the variable + bool findVariable(const QString& theName, double& outValue) const; + + protected: + virtual void showEvent(QShowEvent*); + + protected slots: + /// A slot called on text change + void onTextChanged(const QString&); + + private: + void connectSignalsAndSlots(); + + private: + QString myTextValue; + + bool myAcceptVariables; +}; + +#endif diff --git a/src/ModuleBase/ModuleBase_Tools.cpp b/src/ModuleBase/ModuleBase_Tools.cpp index 66f2979fa..6cbbe1c80 100755 --- a/src/ModuleBase/ModuleBase_Tools.cpp +++ b/src/ModuleBase/ModuleBase_Tools.cpp @@ -5,6 +5,8 @@ // Author: Vitaly Smetannikov #include "ModuleBase_Tools.h" + +#include #include #include @@ -190,6 +192,26 @@ void setSpinValue(ModuleBase_ParamSpinBox* theSpin, double theValue) theSpin->blockSignals(isBlocked); } +void setSpinText(ModuleBase_ParamIntSpinBox* theSpin, const QString& theText) +{ + // In order to avoid extra text setting because it will + // reset cursor position in control + if (theSpin->text() == theText) + return; + bool isBlocked = theSpin->blockSignals(true); + theSpin->setText(theText); + theSpin->blockSignals(isBlocked); +} + +void setSpinValue(ModuleBase_ParamIntSpinBox* theSpin, int theValue) +{ + if (theSpin->value() == theValue) + return; + bool isBlocked = theSpin->blockSignals(true); + theSpin->setValue(theValue); + theSpin->blockSignals(isBlocked); +} + QString objectInfo(const ObjectPtr& theObj, const bool isUseAttributesInfo) { QString aFeatureStr = "feature"; diff --git a/src/ModuleBase/ModuleBase_Tools.h b/src/ModuleBase/ModuleBase_Tools.h index c8d3c6afa..31556d8d8 100755 --- a/src/ModuleBase/ModuleBase_Tools.h +++ b/src/ModuleBase/ModuleBase_Tools.h @@ -24,6 +24,7 @@ class QWidget; class QLayout; class QDoubleSpinBox; +class ModuleBase_ParamIntSpinBox; class ModuleBase_ParamSpinBox; namespace ModuleBase_Tools { @@ -102,6 +103,16 @@ MODULEBASE_EXPORT void setSpinValue(ModuleBase_ParamSpinBox* theSpin, double the /// \param theText a new value MODULEBASE_EXPORT void setSpinText(ModuleBase_ParamSpinBox* theSpin, const QString& theText); +/// Sets programmatically the value to the spin box without emitting any signals(e.g. valueChanged) +/// \param theSpin a ModuleBase_ParamIntSpinBox object +/// \param theValue a new value +MODULEBASE_EXPORT void setSpinValue(ModuleBase_ParamIntSpinBox* theSpin, int theValue); + +/// Sets programmatically the value to the spin box without emitting any signals(e.g. valueChanged) +/// \param theSpin a SpinBox that accepts text +/// \param theText a new value +MODULEBASE_EXPORT void setSpinText(ModuleBase_ParamIntSpinBox* theSpin, const QString& theText); + /// Converts the object to the feature or a result and generate information string /// \param theObj an object /// \param isUseAttributesInfo a flag whether the attribute values information is used diff --git a/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp b/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp index 141abdd39..fbe80ec18 100644 --- a/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp +++ b/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp @@ -105,7 +105,7 @@ bool ModuleBase_WidgetDoubleValue::resetCustom() bool isOk; double aDefValue = QString::fromStdString(getDefaultValue()).toDouble(&isOk); // reset the value just if there is a default value definition in the XML definition - // if the double value can not be found by the default value, do nothing + // if the value can not be found by the default value, do nothing if (isOk) { ModuleBase_Tools::setSpinValue(mySpinBox, aDefValue); storeValue(); diff --git a/src/ModuleBase/ModuleBase_WidgetIntValue.cpp b/src/ModuleBase/ModuleBase_WidgetIntValue.cpp index 308aef0ff..6056ca2e0 100644 --- a/src/ModuleBase/ModuleBase_WidgetIntValue.cpp +++ b/src/ModuleBase/ModuleBase_WidgetIntValue.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -48,7 +48,7 @@ ModuleBase_WidgetIntValue::ModuleBase_WidgetIntValue(QWidget* theParent, if (!aLabelIcon.isEmpty()) myLabel->setPixmap(QPixmap(aLabelIcon)); - mySpinBox = new ModuleBase_IntSpinBox(this); + mySpinBox = new ModuleBase_ParamIntSpinBox(this); QString anObjName = QString::fromStdString(attributeID()); mySpinBox->setObjectName(anObjName); @@ -95,18 +95,16 @@ ModuleBase_WidgetIntValue::~ModuleBase_WidgetIntValue() bool ModuleBase_WidgetIntValue::resetCustom() { bool aDone = false; - if (!isUseReset() || isComputedDefault()) { + if (!isUseReset() || isComputedDefault() || mySpinBox->hasVariable()) { aDone = false; } else { bool isOk; int aDefValue = QString::fromStdString(getDefaultValue()).toInt(&isOk); // reset the value just if there is a default value definition in the XML definition - // if the double value can not be found by the default value, do nothing + // if the value can not be found by the default value, do nothing if (isOk) { - bool isBlocked = mySpinBox->blockSignals(true); - mySpinBox->setValue(isOk ? aDefValue : 0); - mySpinBox->blockSignals(isBlocked); - storeValueCustom(); + ModuleBase_Tools::setSpinValue(mySpinBox, aDefValue); + storeValue(); aDone = true; } } @@ -116,9 +114,18 @@ bool ModuleBase_WidgetIntValue::resetCustom() bool ModuleBase_WidgetIntValue::storeValueCustom() const { DataPtr aData = myFeature->data(); - AttributeIntegerPtr aIntVal = aData->integer(attributeID()); - int aVal = mySpinBox->value(); - aIntVal->setValue(mySpinBox->value()); + AttributeIntegerPtr anAttribute = aData->integer(attributeID()); + if (mySpinBox->hasVariable()) { + // Here is a text of a real value or an expression. + std::string aText = mySpinBox->text().toStdString(); + anAttribute->setText(aText); + } else { + // it is important to set the empty text value to the attribute before set the value + // because setValue tries to calculate the attribute value according to the + // attribute current text + anAttribute->setText(""); + anAttribute->setValue(mySpinBox->value()); + } updateObject(myFeature); return true; } @@ -126,13 +133,21 @@ bool ModuleBase_WidgetIntValue::storeValueCustom() const bool ModuleBase_WidgetIntValue::restoreValueCustom() { DataPtr aData = myFeature->data(); - AttributeIntegerPtr aRef = aData->integer(attributeID()); - bool isBlocked = mySpinBox->blockSignals(true); - mySpinBox->setValue(aRef->value()); - mySpinBox->blockSignals(isBlocked); + AttributeIntegerPtr anAttribute = aData->integer(attributeID()); + std::string aTextRepr = anAttribute->text(); + if (!aTextRepr.empty()) { + ModuleBase_Tools::setSpinText(mySpinBox, QString::fromStdString(aTextRepr)); + } else { + ModuleBase_Tools::setSpinValue(mySpinBox, anAttribute->value()); + } return true; } +void ModuleBase_WidgetIntValue::selectContent() +{ + mySpinBox->selectAll(); +} + QList ModuleBase_WidgetIntValue::getControls() const { QList aList; diff --git a/src/ModuleBase/ModuleBase_WidgetIntValue.h b/src/ModuleBase/ModuleBase_WidgetIntValue.h index 3eaf0e52b..1268a5592 100644 --- a/src/ModuleBase/ModuleBase_WidgetIntValue.h +++ b/src/ModuleBase/ModuleBase_WidgetIntValue.h @@ -10,7 +10,7 @@ #include "ModuleBase.h" #include "ModuleBase_ModelWidget.h" -class ModuleBase_IntSpinBox; +class ModuleBase_ParamIntSpinBox; class Config_WidgetAPI; class QWidget; class QLabel; @@ -37,6 +37,9 @@ Q_OBJECT virtual ~ModuleBase_WidgetIntValue(); + /// Select the internal content if it can be selected. It is empty in the default realization + virtual void selectContent(); + /// Returns list of widget controls /// \return a control list virtual QList getControls() const; @@ -62,7 +65,7 @@ protected: QLabel* myLabel; /// Input value control - ModuleBase_IntSpinBox* mySpinBox; + ModuleBase_ParamIntSpinBox* mySpinBox; }; #endif -- 2.39.2