diff options
Diffstat (limited to 'tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp')
-rw-r--r-- | tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp index 9c56d30dfb..36fd0eb54a 100644 --- a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp +++ b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp @@ -41,6 +41,10 @@ #include <qlineedit.h> #include <qdebug.h> +#include <QStyleOptionSpinBox> +#include <QStyle> +#include <QProxyStyle> + class DoubleSpinBox : public QDoubleSpinBox { Q_OBJECT @@ -60,6 +64,16 @@ public: { return QDoubleSpinBox::valueFromText(text); } +#if QT_CONFIG(wheelevent) + void wheelEvent(QWheelEvent *event) + { + QDoubleSpinBox::wheelEvent(event); + } +#endif + void initStyleOption(QStyleOptionSpinBox *option) const + { + QDoubleSpinBox::initStyleOption(option); + } QLineEdit* lineEdit() const { return QDoubleSpinBox::lineEdit(); } public slots: @@ -69,6 +83,26 @@ public slots: } }; +class PressAndHoldStyle : public QProxyStyle +{ + Q_OBJECT +public: + using QProxyStyle::QProxyStyle; + + int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, + const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override + { + switch (hint) { + case QStyle::SH_SpinBox_ClickAutoRepeatRate: + return 5; + case QStyle::SH_SpinBox_ClickAutoRepeatThreshold: + return 10; + default: + return QProxyStyle::styleHint(hint, option, widget, returnData); + } + } +}; + class tst_QDoubleSpinBox : public QObject { @@ -138,6 +172,17 @@ private slots: void adaptiveDecimalStep(); + void wheelEvents_data(); + void wheelEvents(); + + void stepModifierKeys_data(); + void stepModifierKeys(); + + void stepModifierButtons_data(); + void stepModifierButtons(); + + void stepModifierPressAndHold_data(); + void stepModifierPressAndHold(); public slots: void valueChangedHelper(const QString &); void valueChangedHelper(double); @@ -152,6 +197,24 @@ typedef QList<double> DoubleList; Q_DECLARE_METATYPE(QLocale::Language) Q_DECLARE_METATYPE(QLocale::Country) +static QLatin1String modifierToName(Qt::KeyboardModifier modifier) +{ + switch (modifier) { + case Qt::NoModifier: + return QLatin1Literal("No"); + break; + case Qt::ControlModifier: + return QLatin1Literal("Ctrl"); + break; + case Qt::ShiftModifier: + return QLatin1Literal("Shift"); + break; + default: + qFatal("Unexpected keyboard modifier"); + return QLatin1String(); + } +} + tst_QDoubleSpinBox::tst_QDoubleSpinBox() { @@ -1270,5 +1333,332 @@ void tst_QDoubleSpinBox::adaptiveDecimalStep() } } +void tst_QDoubleSpinBox::wheelEvents_data() +{ +#if QT_CONFIG(wheelevent) + QTest::addColumn<QPoint>("angleDelta"); + QTest::addColumn<int>("qt4Delta"); + QTest::addColumn<Qt::KeyboardModifiers>("modifier"); + QTest::addColumn<Qt::MouseEventSource>("source"); + QTest::addColumn<double>("start"); + QTest::addColumn<DoubleList>("expectedValues"); + + const auto fractions = {false, true}; + + const auto directions = {true, false}; + + const auto modifierList = {Qt::NoModifier, + Qt::ControlModifier, + Qt::ShiftModifier}; + + const auto sources = {Qt::MouseEventNotSynthesized, + Qt::MouseEventSynthesizedBySystem, + Qt::MouseEventSynthesizedByQt, + Qt::MouseEventSynthesizedByApplication}; + + const double startValue = 0.0; + + for (auto fraction : fractions) { + for (auto up : directions) { + + const int units = (fraction ? 60 : 120) * (up ? 1 : -1); + + for (auto modifier : modifierList) { + + const Qt::KeyboardModifiers modifiers(modifier); + + const auto modifierName = modifierToName(modifier); + if (modifierName.isEmpty()) + continue; + + const int steps = (modifier & Qt::ControlModifier ? 10 : 1) + * (up ? 1 : -1); + + for (auto source : sources) { + +#ifdef Q_OS_MACOS + QPoint angleDelta; + if ((modifier & Qt::ShiftModifier) && + source == Qt::MouseEventNotSynthesized) { + // On macOS the Shift modifier converts vertical + // mouse wheel events to horizontal. + angleDelta = { units, 0 }; + } else { + // However, this is not the case for trackpad scroll + // events. + angleDelta = { 0, units }; + } +#else + const QPoint angleDelta(0, units); +#endif + + QLatin1String sourceName; + switch (source) { + case Qt::MouseEventNotSynthesized: + sourceName = QLatin1Literal("NotSynthesized"); + break; + case Qt::MouseEventSynthesizedBySystem: + sourceName = QLatin1Literal("SynthesizedBySystem"); + break; + case Qt::MouseEventSynthesizedByQt: + sourceName = QLatin1Literal("SynthesizedByQt"); + break; + case Qt::MouseEventSynthesizedByApplication: + sourceName = QLatin1Literal("SynthesizedByApplication"); + break; + default: + qFatal("Unexpected wheel event source"); + continue; + } + + DoubleList expectedValues; + if (fraction) + expectedValues << startValue; + expectedValues << startValue + steps; + + QTest::addRow("%s%sWith%sKeyboardModifier%s", + fraction ? "half" : "full", + up ? "Up" : "Down", + modifierName.latin1(), + sourceName.latin1()) + << angleDelta + << units + << modifiers + << source + << startValue + << expectedValues; + } + } + } + } +#else + QSKIP("Built with --no-feature-wheelevent"); +#endif +} + +void tst_QDoubleSpinBox::wheelEvents() +{ +#if QT_CONFIG(wheelevent) + QFETCH(QPoint, angleDelta); + QFETCH(int, qt4Delta); + QFETCH(Qt::KeyboardModifiers, modifier); + QFETCH(Qt::MouseEventSource, source); + QFETCH(double, start); + QFETCH(DoubleList, expectedValues); + + DoubleSpinBox spinBox; + spinBox.setRange(-20, 20); + spinBox.setValue(start); + + QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta, + Qt::Vertical, Qt::NoButton, modifier, Qt::NoScrollPhase, + source); + for (int expected : expectedValues) { + qApp->sendEvent(&spinBox, &event); + QCOMPARE(spinBox.value(), expected); + } +#else + QSKIP("Built with --no-feature-wheelevent"); +#endif +} + +void tst_QDoubleSpinBox::stepModifierKeys_data() +{ + QTest::addColumn<double>("startValue"); + QTest::addColumn<QTestEventList>("keys"); + QTest::addColumn<double>("expectedValue"); + + const auto keyList = {Qt::Key_Up, Qt::Key_Down}; + + const auto modifierList = {Qt::NoModifier, + Qt::ControlModifier, + Qt::ShiftModifier}; + + for (auto key : keyList) { + + const bool up = key == Qt::Key_Up; + Q_ASSERT(up || key == Qt::Key_Down); + + const double startValue = up ? 0.0 : 10.0; + + for (auto modifier : modifierList) { + + QTestEventList keys; + keys.addKeyClick(key, modifier); + + const auto modifierName = modifierToName(modifier); + if (modifierName.isEmpty()) + continue; + + const int steps = (modifier & Qt::ControlModifier ? 10 : 1) + * (up ? 1 : -1); + + const double expectedValue = startValue + steps; + + QTest::addRow("%sWith%sKeyboardModifier", + up ? "up" : "down", + modifierName.latin1()) + << startValue + << keys + << expectedValue; + } + } +} + +void tst_QDoubleSpinBox::stepModifierKeys() +{ + QFETCH(double, startValue); + QFETCH(QTestEventList, keys); + QFETCH(double, expectedValue); + + QDoubleSpinBox spin(0); + spin.setValue(startValue); + spin.show(); + QVERIFY(QTest::qWaitForWindowActive(&spin)); + + QCOMPARE(spin.value(), startValue); + keys.simulate(&spin); + QCOMPARE(spin.value(), expectedValue); +} + +void tst_QDoubleSpinBox::stepModifierButtons_data() +{ + QTest::addColumn<QStyle::SubControl>("subControl"); + QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); + QTest::addColumn<double>("startValue"); + QTest::addColumn<double>("expectedValue"); + + const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; + + const auto modifierList = {Qt::NoModifier, + Qt::ControlModifier, + Qt::ShiftModifier}; + + for (auto subControl : subControls) { + + const bool up = subControl == QStyle::SC_SpinBoxUp; + Q_ASSERT(up || subControl == QStyle::SC_SpinBoxDown); + + const double startValue = up ? 0 : 10; + + for (auto modifier : modifierList) { + + const Qt::KeyboardModifiers modifiers(modifier); + + const auto modifierName = modifierToName(modifier); + if (modifierName.isEmpty()) + continue; + + const int steps = (modifier & Qt::ControlModifier ? 10 : 1) + * (up ? 1 : -1); + + const double expectedValue = startValue + steps; + + QTest::addRow("%sWith%sKeyboardModifier", + up ? "up" : "down", + modifierName.latin1()) + << subControl + << modifiers + << startValue + << expectedValue; + } + } +} + +void tst_QDoubleSpinBox::stepModifierButtons() +{ + QFETCH(QStyle::SubControl, subControl); + QFETCH(Qt::KeyboardModifiers, modifiers); + QFETCH(double, startValue); + QFETCH(double, expectedValue); + + DoubleSpinBox spin(0); + spin.setRange(-20, 20); + spin.setValue(startValue); + spin.show(); + QVERIFY(QTest::qWaitForWindowActive(&spin)); + + QStyleOptionSpinBox spinBoxStyleOption; + spin.initStyleOption(&spinBoxStyleOption); + + const QRect buttonRect = spin.style()->subControlRect( + QStyle::CC_SpinBox, &spinBoxStyleOption, subControl, &spin); + + QCOMPARE(spin.value(), startValue); + QTest::mouseClick(&spin, Qt::LeftButton, modifiers, buttonRect.center()); + QCOMPARE(spin.value(), expectedValue); +} + +void tst_QDoubleSpinBox::stepModifierPressAndHold_data() +{ + QTest::addColumn<QStyle::SubControl>("subControl"); + QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); + QTest::addColumn<int>("expectedStepModifier"); + + const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; + + const auto modifierList = {Qt::NoModifier, + Qt::ControlModifier, + Qt::ShiftModifier}; + + for (auto subControl : subControls) { + + const bool up = subControl == QStyle::SC_SpinBoxUp; + Q_ASSERT(up || subControl == QStyle::SC_SpinBoxDown); + + for (auto modifier : modifierList) { + + const Qt::KeyboardModifiers modifiers(modifier); + + const auto modifierName = modifierToName(modifier); + if (modifierName.isEmpty()) + continue; + + const int steps = (modifier & Qt::ControlModifier ? 10 : 1) + * (up ? 1 : -1); + + QTest::addRow("%sWith%sKeyboardModifier", + up ? "up" : "down", + modifierName.latin1()) + << subControl + << modifiers + << steps; + } + } +} + +void tst_QDoubleSpinBox::stepModifierPressAndHold() +{ + QFETCH(QStyle::SubControl, subControl); + QFETCH(Qt::KeyboardModifiers, modifiers); + QFETCH(int, expectedStepModifier); + + DoubleSpinBox spin(0); + QScopedPointer<PressAndHoldStyle, QScopedPointerDeleteLater> pressAndHoldStyle( + new PressAndHoldStyle); + spin.setStyle(pressAndHoldStyle.data()); + spin.setRange(-100.0, 100.0); + spin.setValue(0.0); + + QSignalSpy spy(&spin, QOverload<double>::of(&DoubleSpinBox::valueChanged)); + + spin.show(); + QVERIFY(QTest::qWaitForWindowExposed(&spin)); + + QStyleOptionSpinBox spinBoxStyleOption; + spin.initStyleOption(&spinBoxStyleOption); + + const QRect buttonRect = spin.style()->subControlRect( + QStyle::CC_SpinBox, &spinBoxStyleOption, subControl, &spin); + + QTest::mousePress(&spin, Qt::LeftButton, modifiers, buttonRect.center()); + QTRY_VERIFY(spy.length() >= 3); + QTest::mouseRelease(&spin, Qt::LeftButton, modifiers, buttonRect.center()); + + const auto value = spy.last().at(0); + QVERIFY(value.type() == QVariant::Double); + QCOMPARE(value.toDouble(), spy.length() * expectedStepModifier); +} + QTEST_MAIN(tst_QDoubleSpinBox) #include "tst_qdoublespinbox.moc" |