From 47d4db552a34070d5da4491c1727a336a6b83a54 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 8 Aug 2020 20:04:45 +0200 Subject: [PATCH] plugin: [skip ci] make QuantitySpinBox inside plugin functioning --- src/Tools/plugins/widget/customwidgets.cpp | 759 +++++++++++++++++++-- src/Tools/plugins/widget/customwidgets.h | 236 ++++++- 2 files changed, 923 insertions(+), 72 deletions(-) diff --git a/src/Tools/plugins/widget/customwidgets.cpp b/src/Tools/plugins/widget/customwidgets.cpp index 8952dc46d2..eee94475ac 100644 --- a/src/Tools/plugins/widget/customwidgets.cpp +++ b/src/Tools/plugins/widget/customwidgets.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "customwidgets.h" @@ -523,79 +525,587 @@ void InputField::setHistorySize(int i) // -------------------------------------------------------------------- -QuantitySpinBox::QuantitySpinBox (QWidget * parent) - : QAbstractSpinBox(parent), - Value(0), - Maximum(INT_MAX), - Minimum(-INT_MAX), - StepSize(1.0) +namespace Base { + +Unit::Unit() { + +} + +Unit::Unit(const QString& u) + : unit(u) +{ + +} + +bool Unit::isEmpty() const +{ + return unit.isEmpty(); +} + +bool Unit::operator ==(const Unit& that) +{ + return this->unit == that.unit; +} + +bool Unit::operator !=(const Unit& that) +{ + return this->unit != that.unit; +} + +const QString& Unit::getString() const +{ + return unit; +} + +int QuantityFormat::defaultDenominator = 8; // for 1/8" + + +QuantityFormat::QuantityFormat() + : option(OmitGroupSeparator | RejectGroupSeparator) + , format(Fixed) + , precision(4) + , denominator(defaultDenominator) +{ +} + +Quantity::Quantity() + : value(0) + , unit() +{ + +} + +Quantity::Quantity(double v, const Unit& u) + : value(v) + , unit(u) +{ + +} + +Quantity Quantity::parse(const QString& str) +{ + bool ok; + QString txt = str; + QString unit; + while (!txt.isEmpty() && txt[txt.length()-1].isLetter()) { + unit.prepend(txt[txt.length()-1]); + txt.chop(1); + } + + double v = QLocale::system().toDouble(txt, &ok); + //if (!ok) + // throw QString("Cannot convert to double"); + return Quantity(v, Unit(unit)); +} + +void Quantity::setValue(double v) +{ + value = v; +} + +double Quantity::getValue() const +{ + return value; +} + +void Quantity::setUnit(const Unit& u) +{ + unit = u; +} + +Unit Quantity::getUnit() const +{ + return unit; +} + +QString Quantity::getUserString() const +{ + QLocale Lc; + const QuantityFormat& format = getFormat(); + if (format.option != QuantityFormat::None) { + uint opt = static_cast(format.option); + Lc.setNumberOptions(static_cast(opt)); + } + + QString Ln = Lc.toString(value, format.toFormat(), format.precision); + return QString::fromUtf8("%1 %2").arg(Ln, unit.getString()); +} + +QString Quantity::getUserString(double& factor, QString& unitString) const +{ + factor = 1; + unitString = unit.getString(); + + QLocale Lc; + const QuantityFormat& format = getFormat(); + if (format.option != QuantityFormat::None) { + uint opt = static_cast(format.option); + Lc.setNumberOptions(static_cast(opt)); + } + + QString Ln = Lc.toString(value, format.toFormat(), format.precision); + return QString::fromUtf8("%1 %2").arg(Ln, unit.getString()); +} + +} + +namespace Gui { + +class QuantitySpinBoxPrivate +{ +public: + QuantitySpinBoxPrivate() : + validInput(true), + pendingEmit(false), + unitValue(0), + maximum(INT_MAX), + minimum(-INT_MAX), + singleStep(1.0) + { + } + ~QuantitySpinBoxPrivate() + { + } + + QString stripped(const QString &t, int *pos) const + { + QString text = t; + const int s = text.size(); + text = text.trimmed(); + if (pos) + (*pos) -= (s - text.size()); + return text; + } + + bool validate(QString& input, Base::Quantity& result) const + { + bool success = false; + QString tmp = input; + int pos = 0; + QValidator::State state; + Base::Quantity res = validateAndInterpret(tmp, pos, state); + res.setFormat(quantity.getFormat()); + if (state == QValidator::Acceptable) { + success = true; + result = res; + input = tmp; + } + else if (state == QValidator::Intermediate) { + tmp = tmp.trimmed(); + tmp += QLatin1Char(' '); + tmp += unitStr; + Base::Quantity res2 = validateAndInterpret(tmp, pos, state); + res2.setFormat(quantity.getFormat()); + if (state == QValidator::Acceptable) { + success = true; + result = res2; + input = tmp; + } + } + + return success; + } + Base::Quantity validateAndInterpret(QString& input, int& pos, QValidator::State& state) const + { + Base::Quantity res; + const double max = this->maximum; + const double min = this->minimum; + + QString copy = input; + + int len = copy.size(); + + const bool plus = max >= 0; + const bool minus = min <= 0; + + switch (len) { + case 0: + state = max != min ? QValidator::Intermediate : QValidator::Invalid; + goto end; + case 1: + if (copy.at(0) == locale.decimalPoint()) { + state = QValidator::Intermediate; + copy.prepend(QLatin1Char('0')); + pos++; + len++; + goto end; + } + else if (copy.at(0) == QLatin1Char('+')) { + // the quantity parser doesn't allow numbers of the form '+1.0' + state = QValidator::Invalid; + goto end; + } + else if (copy.at(0) == QLatin1Char('-')) { + if (minus) + state = QValidator::Intermediate; + else + state = QValidator::Invalid; + goto end; + } + break; + case 2: + if (copy.at(1) == locale.decimalPoint() + && (plus && copy.at(0) == QLatin1Char('+'))) { + state = QValidator::Intermediate; + goto end; + } + if (copy.at(1) == locale.decimalPoint() + && (minus && copy.at(0) == QLatin1Char('-'))) { + state = QValidator::Intermediate; + copy.insert(1, QLatin1Char('0')); + pos++; + len++; + goto end; + } + break; + default: break; + } + + { + if (copy.at(0) == locale.groupSeparator()) { + state = QValidator::Invalid; + goto end; + } + else if (len > 1) { + bool decOccurred = false; + for (int i = 0; i= min && value <= max) { + if (copy.endsWith(locale.decimalPoint())) { + // input shouldn't end with a decimal point + state = QValidator::Intermediate; + } + else if (res.getUnit().isEmpty() && !this->unit.isEmpty()) { + // if not dimensionless the input should have a dimension + state = QValidator::Intermediate; + } + else if (res.getUnit() != this->unit) { + state = QValidator::Invalid; + } + else { + state = QValidator::Acceptable; + } + } + else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min) + state = QValidator::Invalid; + } + else { + if ((value >= 0 && value > max) || (value < 0 && value < min)) { + state = QValidator::Invalid; + } + else { + state = QValidator::Intermediate; + } + } + } +end: + if (state != QValidator::Acceptable) { + res.setValue(max > 0 ? min : max); + } + + input = copy; + return res; + } + + QLocale locale; + bool validInput; + bool pendingEmit; + QString validStr; + Base::Quantity quantity; + Base::Quantity cached; + Base::Unit unit; + double unitValue; + QString unitStr; + double maximum; + double minimum; + double singleStep; +}; +} + +QuantitySpinBox::QuantitySpinBox(QWidget *parent) + : QAbstractSpinBox(parent), + d_ptr(new QuantitySpinBoxPrivate()) +{ + d_ptr->locale = locale(); + this->setContextMenuPolicy(Qt::DefaultContextMenu); + QObject::connect(lineEdit(), SIGNAL(textChanged(QString)), + this, SLOT(userInput(QString))); + QObject::connect(this, SIGNAL(editingFinished()), + this, SLOT(handlePendingEmit())); } QuantitySpinBox::~QuantitySpinBox() { } -/// sets the field with a quantity -void QuantitySpinBox::setValue(double quant) +void QuantitySpinBox::resizeEvent(QResizeEvent * event) { - Value = quant; - lineEdit()->setText(QString("%1 %2").arg(Value).arg(UnitStr)); + QAbstractSpinBox::resizeEvent(event); } -/// sets the field with a quantity -double QuantitySpinBox::value() const +void Gui::QuantitySpinBox::keyPressEvent(QKeyEvent *event) { - return Value; + QAbstractSpinBox::keyPressEvent(event); } -/// get the value of the singleStep property -double QuantitySpinBox::singleStep(void)const + +void QuantitySpinBox::updateText(const Base::Quantity &quant) { - return StepSize; + Q_D(QuantitySpinBox); + + double dFactor; + QString txt = getUserString(quant, dFactor, d->unitStr); + d->unitValue = quant.getValue()/dFactor; + lineEdit()->setText(txt); + handlePendingEmit(); } -/// set the value of the singleStep property -void QuantitySpinBox::setSingleStep(double s) +Base::Quantity QuantitySpinBox::value() const { - StepSize = s; + Q_D(const QuantitySpinBox); + return d->quantity; } -/// get the value of the maximum property -double QuantitySpinBox::maximum(void)const +double QuantitySpinBox::rawValue() const { - return Maximum; + Q_D(const QuantitySpinBox); + return d->quantity.getValue(); } -/// set the value of the maximum property -void QuantitySpinBox::setMaximum(double m) +void QuantitySpinBox::setValue(const Base::Quantity& value) { - Maximum = m; + Q_D(QuantitySpinBox); + d->quantity = value; + // check limits + if (d->quantity.getValue() > d->maximum) + d->quantity.setValue(d->maximum); + if (d->quantity.getValue() < d->minimum) + d->quantity.setValue(d->minimum); + + d->unit = value.getUnit(); + + updateText(value); } -/// get the value of the minimum property -double QuantitySpinBox::minimum(void)const +void QuantitySpinBox::setValue(double value) { - return Minimum; + Q_D(QuantitySpinBox); + setValue(Base::Quantity(value, d->unit)); } -/// set the value of the minimum property -void QuantitySpinBox::setMinimum(double m) +bool QuantitySpinBox::hasValidInput() const { - Minimum = m; + Q_D(const QuantitySpinBox); + return d->validInput; +} + +// Gets called after call of 'validateAndInterpret' +void QuantitySpinBox::userInput(const QString & text) +{ + Q_D(QuantitySpinBox); + + d->pendingEmit = true; + + QString tmp = text; + Base::Quantity res; + if (d->validate(tmp, res)) { + d->validStr = tmp; + d->validInput = true; + } + else { + d->validInput = false; + return; + } + + if (keyboardTracking()) { + d->cached = res; + handlePendingEmit(); + } + else { + d->cached = res; + } +} + +void QuantitySpinBox::handlePendingEmit() +{ + updateFromCache(true); +} + +void QuantitySpinBox::updateFromCache(bool notify) +{ + Q_D(QuantitySpinBox); + if (d->pendingEmit) { + double factor; + const Base::Quantity& res = d->cached; + getUserString(res, factor, d->unitStr); + d->unitValue = res.getValue() / factor; + d->quantity = res; + + // signaling + if (notify) { + d->pendingEmit = false; + valueChanged(res); + valueChanged(res.getValue()); + } + } +} + +Base::Unit QuantitySpinBox::unit() const +{ + Q_D(const QuantitySpinBox); + return d->unit; +} + +void QuantitySpinBox::setUnit(const Base::Unit &unit) +{ + Q_D(QuantitySpinBox); + + d->unit = unit; + d->quantity.setUnit(unit); + updateText(d->quantity); +} + +void QuantitySpinBox::setUnitText(const QString& str) +{ + Base::Quantity quant = Base::Quantity::parse(str); + setUnit(quant.getUnit()); +} + +QString QuantitySpinBox::unitText(void) +{ + Q_D(QuantitySpinBox); + return d->unitStr; +} + +double QuantitySpinBox::singleStep() const +{ + Q_D(const QuantitySpinBox); + return d->singleStep; +} + +void QuantitySpinBox::setSingleStep(double value) +{ + Q_D(QuantitySpinBox); + + if (value >= 0) { + d->singleStep = value; + } +} + +double QuantitySpinBox::minimum() const +{ + Q_D(const QuantitySpinBox); + return d->minimum; +} + +void QuantitySpinBox::setMinimum(double minimum) +{ + Q_D(QuantitySpinBox); + d->minimum = minimum; +} + +double QuantitySpinBox::maximum() const +{ + Q_D(const QuantitySpinBox); + return d->maximum; +} + +void QuantitySpinBox::setMaximum(double maximum) +{ + Q_D(QuantitySpinBox); + d->maximum = maximum; +} + +void QuantitySpinBox::setRange(double minimum, double maximum) +{ + Q_D(QuantitySpinBox); + d->minimum = minimum; + d->maximum = maximum; +} + +int QuantitySpinBox::decimals() const +{ + Q_D(const QuantitySpinBox); + return d->quantity.getFormat().precision; +} + +void QuantitySpinBox::setDecimals(int v) +{ + Q_D(QuantitySpinBox); + Base::QuantityFormat f = d->quantity.getFormat(); + f.precision = v; + d->quantity.setFormat(f); + updateText(d->quantity); +} + +void QuantitySpinBox::clearSchema() +{ + Q_D(QuantitySpinBox); + updateText(d->quantity); +} + +QString QuantitySpinBox::getUserString(const Base::Quantity& val, double& factor, QString& unitString) const +{ + Q_D(const QuantitySpinBox); + return val.getUserString(factor, unitString); +} + +QString QuantitySpinBox::getUserString(const Base::Quantity& val) const +{ + Q_D(const QuantitySpinBox); + return val.getUserString(); } QAbstractSpinBox::StepEnabled QuantitySpinBox::stepEnabled() const { - if (isReadOnly()) + Q_D(const QuantitySpinBox); + if (isReadOnly()/* || !d->validInput*/) return StepNone; if (wrapping()) return StepEnabled(StepUpEnabled | StepDownEnabled); StepEnabled ret = StepNone; - if (Value < Maximum) { + if (d->quantity.getValue() < d->maximum) { ret |= StepUpEnabled; } - if (Value > Minimum) { + if (d->quantity.getValue() > d->minimum) { ret |= StepDownEnabled; } return ret; @@ -603,26 +1113,183 @@ QAbstractSpinBox::StepEnabled QuantitySpinBox::stepEnabled() const void QuantitySpinBox::stepBy(int steps) { - double step = StepSize * steps; - double val = Value + step; - if (val > Maximum) - val = Maximum; - else if (val < Minimum) - val = Minimum; + Q_D(QuantitySpinBox); + updateFromCache(false); - lineEdit()->setText(QString::fromUtf8("%L1 %2").arg(val).arg(UnitStr)); + double step = d->singleStep * steps; + double val = d->unitValue + step; + if (val > d->maximum) + val = d->maximum; + else if (val < d->minimum) + val = d->minimum; + + lineEdit()->setText(QString::fromUtf8("%L1 %2").arg(val).arg(d->unitStr)); + updateFromCache(true); update(); + selectNumber(); } -void QuantitySpinBox::setUnitText(QString str) +QSize QuantitySpinBox::sizeHint() const { - UnitStr = str; - lineEdit()->setText(QString("%1 %2").arg(Value).arg(UnitStr)); + return QAbstractSpinBox::sizeHint(); } -QString QuantitySpinBox::unitText(void) +QSize QuantitySpinBox::minimumSizeHint() const { - return UnitStr; + return QAbstractSpinBox::minimumSizeHint(); +} + +void QuantitySpinBox::showEvent(QShowEvent * event) +{ + Q_D(QuantitySpinBox); + + QAbstractSpinBox::showEvent(event); + + bool selected = lineEdit()->hasSelectedText(); + updateText(d->quantity); + if (selected) + selectNumber(); +} + +void QuantitySpinBox::hideEvent(QHideEvent * event) +{ + handlePendingEmit(); + QAbstractSpinBox::hideEvent(event); +} + +void QuantitySpinBox::closeEvent(QCloseEvent * event) +{ + handlePendingEmit(); + QAbstractSpinBox::closeEvent(event); +} + +bool QuantitySpinBox::event(QEvent * event) +{ + // issue #0004059: Tooltips for Gui::QuantitySpinBox not showing + // Here we must not try to show the tooltip of the icon label + // because it would override a custom tooltip set to this widget. + // + // We could also check if the text of this tooltip is empty but + // it will fail in cases where the widget is embedded into the + // property editor and the corresponding item has set a tooltip. + // Instead of showing the item's tooltip it will again show the + // tooltip of the icon label. +#if 0 + if (event->type() == QEvent::ToolTip) { + if (isBound() && getExpression() && lineEdit()->isReadOnly()) { + QHelpEvent * helpEvent = static_cast(event); + + QToolTip::showText( helpEvent->globalPos(), Base::Tools::fromStdString(getExpression()->toString()), this); + event->accept(); + return true; + } + } +#endif + + return QAbstractSpinBox::event(event); +} + +void QuantitySpinBox::focusInEvent(QFocusEvent * event) +{ + bool hasSel = lineEdit()->hasSelectedText(); + QAbstractSpinBox::focusInEvent(event); + + if (event->reason() == Qt::TabFocusReason || + event->reason() == Qt::BacktabFocusReason || + event->reason() == Qt::ShortcutFocusReason) { + + if (!hasSel) + selectNumber(); + } +} + +void QuantitySpinBox::focusOutEvent(QFocusEvent * event) +{ + Q_D(QuantitySpinBox); + + int pos = 0; + QString text = lineEdit()->text(); + QValidator::State state; + d->validateAndInterpret(text, pos, state); + if (state != QValidator::Acceptable) { + lineEdit()->setText(d->validStr); + } + + handlePendingEmit(); + + QToolTip::hideText(); + QAbstractSpinBox::focusOutEvent(event); +} + +void QuantitySpinBox::clear() +{ + QAbstractSpinBox::clear(); +} + +void QuantitySpinBox::selectNumber() +{ + QString str = lineEdit()->text(); + unsigned int i = 0; + + QChar d = locale().decimalPoint(); + QChar g = locale().groupSeparator(); + QChar n = locale().negativeSign(); + + for (QString::iterator it = str.begin(); it != str.end(); ++it) { + if (it->isDigit()) + i++; + else if (*it == d) + i++; + else if (*it == g) + i++; + else if (*it == n) + i++; + else // any non-number character + break; + } + + lineEdit()->setSelection(0, i); +} + +QString QuantitySpinBox::textFromValue(const Base::Quantity& value) const +{ + double factor; + QString unitStr; + QString str = getUserString(value, factor, unitStr); + if (qAbs(value.getValue()) >= 1000.0) { + str.remove(locale().groupSeparator()); + } + return str; +} + +Base::Quantity QuantitySpinBox::valueFromText(const QString &text) const +{ + Q_D(const QuantitySpinBox); + + QString copy = text; + int pos = lineEdit()->cursorPosition(); + QValidator::State state = QValidator::Acceptable; + Base::Quantity quant = d->validateAndInterpret(copy, pos, state); + if (state != QValidator::Acceptable) { + fixup(copy); + quant = d->validateAndInterpret(copy, pos, state); + } + + return quant; +} + +QValidator::State QuantitySpinBox::validate(QString &text, int &pos) const +{ + Q_D(const QuantitySpinBox); + + QValidator::State state; + d->validateAndInterpret(text, pos, state); + return state; +} + +void QuantitySpinBox::fixup(QString &input) const +{ + input.remove(locale().groupSeparator()); } // ------------------------------------------------------------------------------ diff --git a/src/Tools/plugins/widget/customwidgets.h b/src/Tools/plugins/widget/customwidgets.h index d9c69b3795..8206568baf 100644 --- a/src/Tools/plugins/widget/customwidgets.h +++ b/src/Tools/plugins/widget/customwidgets.h @@ -41,7 +41,108 @@ #include namespace Base { - class Quantity{}; + class Unit{ + public: + Unit(); + Unit(const QString&); + bool isEmpty() const; + bool operator ==(const Unit&); + bool operator !=(const Unit&); + const QString& getString() const; + + private: + QString unit; + }; + + struct QuantityFormat { + enum NumberOption { + None = 0x00, + OmitGroupSeparator = 0x01, + RejectGroupSeparator = 0x02 + }; + enum NumberFormat { + Default = 0, + Fixed = 1, + Scientific = 2 + }; + + typedef int NumberOptions; + NumberOptions option; + NumberFormat format; + int precision; + int denominator; + + // Default denominator of minimum fractional inch. Only used in certain + // schemas. + static int defaultDenominator; // i.e 8 for 1/8" + + static inline int getDefaultDenominator() { + return defaultDenominator; + } + + static inline void setDefaultDenominator(int denom) { + defaultDenominator = denom; + } + + inline int getDenominator() const { + return denominator; + } + + inline void setDenominator(int denom) { + denominator = denom; + } + QuantityFormat(); + inline char toFormat() const { + switch (format) { + case Fixed: + return 'f'; + case Scientific: + return 'e'; + default: + return 'g'; + } + } + static inline NumberFormat toFormat(char c, bool* ok = 0) { + if (ok) + *ok = true; + switch (c) { + case 'f': + return Fixed; + case 'e': + return Scientific; + case 'g': + return Default; + default: + if (ok) + *ok = false; + return Default; + } + } + }; + + class Quantity{ + public: + Quantity(void); + explicit Quantity(double Value, const Unit& unit=Unit()); + static Quantity parse(const QString&); + void setValue(double); + double getValue() const; + void setUnit(const Unit&); + Unit getUnit() const; + const QuantityFormat& getFormat() const { + return format; + } + void setFormat(const QuantityFormat& f) { + format = f; + } + QString getUserString() const; + QString getUserString(double& factor, QString& unitString) const; + + private: + double value; + Unit unit; + QuantityFormat format; + }; } Q_DECLARE_METATYPE(Base::Quantity) @@ -258,6 +359,7 @@ private: // ------------------------------------------------------------------------------ +class QuantitySpinBoxPrivate; class QuantitySpinBox : public QAbstractSpinBox { Q_OBJECT @@ -266,38 +368,120 @@ class QuantitySpinBox : public QAbstractSpinBox Q_PROPERTY(double minimum READ minimum WRITE setMinimum) Q_PROPERTY(double maximum READ maximum WRITE setMaximum) Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep) - Q_PROPERTY(double value READ value WRITE setValue NOTIFY valueChanged USER true) + Q_PROPERTY(double rawValue READ rawValue WRITE setValue NOTIFY valueChanged) + Q_PROPERTY(Base::Quantity value READ value WRITE setValue NOTIFY valueChanged USER true) public: - QuantitySpinBox (QWidget * parent = 0); + explicit QuantitySpinBox(QWidget *parent = 0); virtual ~QuantitySpinBox(); - void setValue(double); - double value(void) const; - double singleStep(void) const; - void setSingleStep(double); - double maximum(void) const; - void setMaximum(double); - double minimum(void) const; - void setMinimum(double); - void setUnitText(QString); + /// Get the current quantity + Base::Quantity value() const; + /// Get the current quantity without unit + double rawValue() const; + + /// Gives the current state of the user input, gives true if it is a valid input with correct quantity + /// or returns false if the input is a unparsable string or has a wrong unit. + bool hasValidInput() const; + + /** Sets the Unit this widget is working with. + * After setting the Unit the widget will only accept + * user input with this unit type. Or if the user input + * a value without unit, this one will be added to the resulting + * Quantity. + */ + Base::Unit unit() const; + void setUnit(const Base::Unit &unit); + /// Set the unit property + void setUnitText(const QString&); + /// Get the unit property QString unitText(void); - void stepBy(int steps); + + /// Get the value of the singleStep property + double singleStep() const; + /// Set the value of the singleStep property + void setSingleStep(double val); + + /// Gets the value of the minimum property + double minimum() const; + /// Sets the value of the minimum property + void setMinimum(double min); + + /// Gets the value of the maximum property + double maximum() const; + /// Sets the value of the maximum property + void setMaximum(double max); + + /// Gets the number of decimals + int decimals() const; + /// Sets the number of decimals + void setDecimals(int v); + + /// Clears the schemaand again use the system-wide schema. + void clearSchema(); + + /// Set the number portion selected + void selectNumber(); + + void setRange(double min, double max); + + Base::Quantity valueFromText(const QString &text) const; + QString textFromValue(const Base::Quantity& val) const; + virtual void stepBy(int steps); + virtual void clear(); + virtual QValidator::State validate(QString &input, int &pos) const; + virtual void fixup(QString &str) const; + + QSize sizeHint() const; + QSize minimumSizeHint() const; + bool event(QEvent *event); + +public Q_SLOTS: + /// Sets the field with a quantity + void setValue(const Base::Quantity& val); + /// Set a numerical value which gets converted to a quantity with the currently set unit type + void setValue(double); + +protected Q_SLOTS: + void userInput(const QString & text); + void handlePendingEmit(); protected: - StepEnabled stepEnabled() const; - -Q_SIGNALS: - void valueChanged(const Base::Quantity&); - void valueChanged(double); - void parseError(const QString& errorText); + virtual StepEnabled stepEnabled() const; + virtual void showEvent(QShowEvent * event); + virtual void hideEvent(QHideEvent * event); + virtual void closeEvent(QCloseEvent * event); + virtual void focusInEvent(QFocusEvent * event); + virtual void focusOutEvent(QFocusEvent * event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void resizeEvent(QResizeEvent *event); private: - QString UnitStr; - double Value; - double Maximum; - double Minimum; - double StepSize; + void updateText(const Base::Quantity&); + void updateFromCache(bool); + QString getUserString(const Base::Quantity& val, double& factor, QString& unitString) const; + QString getUserString(const Base::Quantity& val) const; + +Q_SIGNALS: + /** Gets emitted if the user has entered a VALID input + * Valid means the user inputted string obeys all restrictions + * like: minimum, maximum and/or the right Unit (if specified). + */ + void valueChanged(const Base::Quantity&); + /** Gets emitted if the user has entered a VALID input + * Valid means the user inputted string obeys all restrictions + * like: minimum, maximum and/or the right Unit (if specified). + */ + void valueChanged(double); + /** Gets emitted if formula dialog is about to be opened (true) + * or finished (false). + */ + void showFormulaDialog(bool); + +private: + QScopedPointer d_ptr; + Q_DISABLE_COPY(QuantitySpinBox) + Q_DECLARE_PRIVATE(QuantitySpinBox) }; // ------------------------------------------------------------------------------ @@ -329,8 +513,8 @@ class PrefQuantitySpinBox : public QuantitySpinBox { Q_OBJECT - Q_PROPERTY(QByteArray prefEntry READ entryName WRITE setEntryName) - Q_PROPERTY(QByteArray prefPath READ paramGrpPath WRITE setParamGrpPath) + Q_PROPERTY(QByteArray prefEntry READ entryName WRITE setEntryName) + Q_PROPERTY(QByteArray prefPath READ paramGrpPath WRITE setParamGrpPath) public: PrefQuantitySpinBox(QWidget* parent = 0);