1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | #include <qapplication.h> |
32 | #include <limits.h> |
33 | |
34 | #include <cmath> |
35 | #include <float.h> |
36 | |
37 | #include <qspinbox.h> |
38 | #include <qlocale.h> |
39 | #include <qlayout.h> |
40 | |
41 | #include <qlineedit.h> |
42 | #include <qdebug.h> |
43 | |
44 | #include <QStyleOptionSpinBox> |
45 | #include <QStyle> |
46 | #include <QProxyStyle> |
47 | |
48 | class DoubleSpinBox : public QDoubleSpinBox |
49 | { |
50 | Q_OBJECT |
51 | public: |
52 | DoubleSpinBox(QWidget *parent = 0) |
53 | : QDoubleSpinBox(parent) |
54 | { /*connect(this, SIGNAL(valueChanged(double)), this, SLOT(foo(double)));*/ } |
55 | QString textFromValue(double v) const |
56 | { |
57 | return QDoubleSpinBox::textFromValue(val: v); |
58 | } |
59 | QValidator::State validate(QString &text, int &pos) const |
60 | { |
61 | return QDoubleSpinBox::validate(input&: text, pos); |
62 | } |
63 | double valueFromText(const QString &text) const |
64 | { |
65 | return QDoubleSpinBox::valueFromText(text); |
66 | } |
67 | #if QT_CONFIG(wheelevent) |
68 | void wheelEvent(QWheelEvent *event) |
69 | { |
70 | QDoubleSpinBox::wheelEvent(event); |
71 | } |
72 | #endif |
73 | void initStyleOption(QStyleOptionSpinBox *option) const |
74 | { |
75 | QDoubleSpinBox::initStyleOption(option); |
76 | } |
77 | |
78 | QLineEdit* lineEdit() const { return QDoubleSpinBox::lineEdit(); } |
79 | public slots: |
80 | void foo(double vla) |
81 | { |
82 | qDebug() << vla; |
83 | } |
84 | }; |
85 | |
86 | class PressAndHoldStyle : public QProxyStyle |
87 | { |
88 | Q_OBJECT |
89 | public: |
90 | using QProxyStyle::QProxyStyle; |
91 | |
92 | int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, |
93 | const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override |
94 | { |
95 | switch (hint) { |
96 | case QStyle::SH_SpinBox_ClickAutoRepeatRate: |
97 | return 5; |
98 | case QStyle::SH_SpinBox_ClickAutoRepeatThreshold: |
99 | return 10; |
100 | default: |
101 | return QProxyStyle::styleHint(hint, option, widget, returnData); |
102 | } |
103 | } |
104 | }; |
105 | |
106 | class StepModifierStyle : public QProxyStyle |
107 | { |
108 | Q_OBJECT |
109 | public: |
110 | using QProxyStyle::QProxyStyle; |
111 | |
112 | int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, |
113 | const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override |
114 | { |
115 | switch (hint) { |
116 | case QStyle::SH_SpinBox_StepModifier: |
117 | return stepModifier; |
118 | default: |
119 | return QProxyStyle::styleHint(hint, option, widget, returnData); |
120 | } |
121 | } |
122 | |
123 | Qt::KeyboardModifier stepModifier = Qt::ControlModifier; |
124 | }; |
125 | |
126 | |
127 | class tst_QDoubleSpinBox : public QObject |
128 | { |
129 | Q_OBJECT |
130 | public: |
131 | tst_QDoubleSpinBox(); |
132 | virtual ~tst_QDoubleSpinBox(); |
133 | public slots: |
134 | void initTestCase(); |
135 | void cleanupTestCase(); |
136 | void init(); |
137 | |
138 | private slots: |
139 | void germanTest(); |
140 | |
141 | void task54433(); |
142 | |
143 | void setValue_data(); |
144 | void setValue(); |
145 | |
146 | void setPrefixSuffix_data(); |
147 | void setPrefixSuffix(); |
148 | |
149 | void setTracking_data(); |
150 | void setTracking(); |
151 | |
152 | void setWrapping_data(); |
153 | void setWrapping(); |
154 | |
155 | void setSpecialValueText_data(); |
156 | void setSpecialValueText(); |
157 | |
158 | void setSingleStep_data(); |
159 | void setSingleStep(); |
160 | |
161 | void setMinMax_data(); |
162 | void setMinMax(); |
163 | |
164 | void setDecimals_data(); |
165 | void setDecimals(); |
166 | |
167 | void doubleDot(); |
168 | |
169 | void undoRedo(); |
170 | |
171 | void valueFromTextAndValidate_data(); |
172 | void valueFromTextAndValidate(); |
173 | |
174 | void setReadOnly(); |
175 | |
176 | void editingFinished(); |
177 | |
178 | void removeAll(); |
179 | |
180 | void task199226_stateAfterEnter(); |
181 | void task224497_fltMax(); |
182 | |
183 | void task221221(); |
184 | void task255471_decimalsValidation(); |
185 | |
186 | void taskQTBUG_5008_textFromValueAndValidate(); |
187 | void taskQTBUG_6670_selectAllWithPrefix(); |
188 | void taskQTBUG_6496_fiddlingWithPrecision(); |
189 | |
190 | void setGroupSeparatorShown_data(); |
191 | void setGroupSeparatorShown(); |
192 | |
193 | void adaptiveDecimalStep(); |
194 | |
195 | void wheelEvents_data(); |
196 | void wheelEvents(); |
197 | |
198 | void stepModifierKeys_data(); |
199 | void stepModifierKeys(); |
200 | |
201 | void stepModifierButtons_data(); |
202 | void stepModifierButtons(); |
203 | |
204 | void stepModifierPressAndHold_data(); |
205 | void stepModifierPressAndHold(); |
206 | public slots: |
207 | void valueChangedHelper(const QString &); |
208 | void valueChangedHelper(double); |
209 | private: |
210 | QStringList actualTexts; |
211 | QList<double> actualValues; |
212 | QWidget *testFocusWidget; |
213 | }; |
214 | |
215 | typedef QList<double> DoubleList; |
216 | |
217 | Q_DECLARE_METATYPE(QLocale::Language) |
218 | Q_DECLARE_METATYPE(QLocale::Country) |
219 | |
220 | static QLatin1String modifierToName(Qt::KeyboardModifier modifier) |
221 | { |
222 | switch (modifier) { |
223 | case Qt::NoModifier: |
224 | return QLatin1String("No" ); |
225 | break; |
226 | case Qt::ControlModifier: |
227 | return QLatin1String("Ctrl" ); |
228 | break; |
229 | case Qt::ShiftModifier: |
230 | return QLatin1String("Shift" ); |
231 | break; |
232 | case Qt::AltModifier: |
233 | return QLatin1String("Alt" ); |
234 | break; |
235 | case Qt::MetaModifier: |
236 | return QLatin1String("Meta" ); |
237 | break; |
238 | default: |
239 | qFatal(msg: "Unexpected keyboard modifier" ); |
240 | return QLatin1String(); |
241 | } |
242 | } |
243 | |
244 | tst_QDoubleSpinBox::tst_QDoubleSpinBox() |
245 | |
246 | { |
247 | } |
248 | |
249 | tst_QDoubleSpinBox::~tst_QDoubleSpinBox() |
250 | { |
251 | |
252 | } |
253 | |
254 | void tst_QDoubleSpinBox::initTestCase() |
255 | { |
256 | testFocusWidget = new QWidget(0); |
257 | testFocusWidget->resize(w: 200, h: 100); |
258 | testFocusWidget->show(); |
259 | |
260 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
261 | QSKIP("Wayland: This fails. Figure out why." ); |
262 | |
263 | QVERIFY(QTest::qWaitForWindowActive(testFocusWidget)); |
264 | } |
265 | |
266 | void tst_QDoubleSpinBox::cleanupTestCase() |
267 | { |
268 | delete testFocusWidget; |
269 | testFocusWidget = 0; |
270 | } |
271 | |
272 | void tst_QDoubleSpinBox::init() |
273 | { |
274 | QLocale::setDefault(QLocale(QLocale::C)); |
275 | } |
276 | |
277 | void tst_QDoubleSpinBox::setValue_data() |
278 | { |
279 | QTest::addColumn<double>(name: "val" ); |
280 | |
281 | QTest::newRow(dataTag: "data0" ) << 0.0; |
282 | QTest::newRow(dataTag: "data1" ) << 100.5; |
283 | QTest::newRow(dataTag: "data2" ) << -100.5; |
284 | QTest::newRow(dataTag: "data3" ) << -DBL_MAX; |
285 | QTest::newRow(dataTag: "data4" ) << DBL_MAX; |
286 | } |
287 | |
288 | void tst_QDoubleSpinBox::setValue() |
289 | { |
290 | QFETCH(double, val); |
291 | QDoubleSpinBox spin(0); |
292 | spin.setRange(min: -DBL_MAX, DBL_MAX); |
293 | spin.setValue(val); |
294 | QCOMPARE(spin.value(), val); |
295 | } |
296 | |
297 | void tst_QDoubleSpinBox::setPrefixSuffix_data() |
298 | { |
299 | QTest::addColumn<QString>(name: "prefix" ); |
300 | QTest::addColumn<QString>(name: "suffix" ); |
301 | QTest::addColumn<double>(name: "value" ); |
302 | QTest::addColumn<int>(name: "decimals" ); |
303 | QTest::addColumn<QString>(name: "expectedText" ); |
304 | QTest::addColumn<QString>(name: "expectedCleanText" ); |
305 | QTest::addColumn<bool>(name: "show" ); |
306 | |
307 | QTest::newRow(dataTag: "data0" ) << QString() << QString() << 10.5 << 1 << "10.5" << "10.5" << false; |
308 | QTest::newRow(dataTag: "data1" ) << QString() << "cm" << 10.5 << 2 << "10.50cm" << "10.50" << false; |
309 | |
310 | // 10.5 is rounded correctly to 11 when using libdouble-conversion, or incorrectly to 10 when |
311 | // using snprintf. This is not the point of this test, though. |
312 | QTest::newRow(dataTag: "data2" ) << "cm: " << QString() << 10.4 << 0 << "cm: 10" << "10" << false; |
313 | QTest::newRow(dataTag: "data3" ) << "length: " << "cm" << 10.5 << 3 << "length: 10.500cm" << "10.500" << false; |
314 | |
315 | QTest::newRow(dataTag: "data4" ) << QString() << QString() << 10.5 << 1 << "10.5" << "10.5" << true; |
316 | QTest::newRow(dataTag: "data5" ) << QString() << "cm" << 10.5 << 2 << "10.50cm" << "10.50" << true; |
317 | QTest::newRow(dataTag: "data6" ) << "cm: " << QString() << 10.4 << 0 << "cm: 10" << "10" << true; |
318 | QTest::newRow(dataTag: "data7" ) << "length: " << "cm" << 10.5 << 3 << "length: 10.500cm" << "10.500" << true; |
319 | } |
320 | |
321 | void tst_QDoubleSpinBox::setPrefixSuffix() |
322 | { |
323 | QFETCH(QString, prefix); |
324 | QFETCH(QString, suffix); |
325 | QFETCH(double, value); |
326 | QFETCH(int, decimals); |
327 | QFETCH(QString, expectedText); |
328 | QFETCH(QString, expectedCleanText); |
329 | QFETCH(bool, show); |
330 | |
331 | QDoubleSpinBox spin; |
332 | if (show) |
333 | spin.show(); |
334 | spin.setDecimals(decimals); |
335 | const QSize size1 = spin.sizeHint(); |
336 | spin.setPrefix(prefix); |
337 | const QSize size2 = spin.sizeHint(); |
338 | spin.setSuffix(suffix); |
339 | const QSize size3 = spin.sizeHint(); |
340 | spin.setValue(value); |
341 | |
342 | QCOMPARE(spin.text(), expectedText); |
343 | QCOMPARE(spin.cleanText(), expectedCleanText); |
344 | |
345 | if (!suffix.isEmpty()) { |
346 | QVERIFY(size2.width() < size3.width()); |
347 | spin.setSuffix(QString()); |
348 | QCOMPARE(spin.sizeHint(), size2); |
349 | } |
350 | if (!prefix.isEmpty()) { |
351 | QVERIFY(size1.width() < size2.width()); |
352 | spin.setPrefix(QString()); |
353 | QCOMPARE(spin.sizeHint(), size1); |
354 | } |
355 | } |
356 | |
357 | void tst_QDoubleSpinBox::valueChangedHelper(const QString &text) |
358 | { |
359 | actualTexts << text; |
360 | } |
361 | |
362 | void tst_QDoubleSpinBox::valueChangedHelper(double value) |
363 | { |
364 | actualValues << value; |
365 | } |
366 | |
367 | void tst_QDoubleSpinBox::setTracking_data() |
368 | { |
369 | QTest::addColumn<int>(name: "decimals" ); |
370 | QTest::addColumn<QTestEventList>(name: "keys" ); |
371 | QTest::addColumn<QStringList>(name: "texts" ); |
372 | QTest::addColumn<bool>(name: "tracking" ); |
373 | |
374 | QTestEventList keys; |
375 | QStringList texts1; |
376 | QStringList texts2; |
377 | #ifdef Q_OS_MAC |
378 | keys.addKeyClick(Qt::Key_Right, Qt::ControlModifier); |
379 | #else |
380 | keys.addKeyClick(qtKey: Qt::Key_End); |
381 | #endif |
382 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
383 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
384 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
385 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
386 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
387 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
388 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
389 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
390 | keys.addKeyClick(ascii: '7'); |
391 | keys.addKeyClick(ascii: '.'); |
392 | keys.addKeyClick(ascii: '9'); |
393 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
394 | keys.addKeyClick(ascii: '2'); |
395 | keys.addKeyClick(qtKey: Qt::Key_Enter); |
396 | keys.addKeyClick(qtKey: Qt::Key_Enter); |
397 | keys.addKeyClick(qtKey: Qt::Key_Enter); |
398 | texts1 << "7" << "7.9" << "7." << "7.2" << "7.200" << "7.200" << "7.200" ; |
399 | texts2 << "7.200" ; |
400 | QTest::newRow(dataTag: "data1" ) << 3 << keys << texts1 << true; |
401 | QTest::newRow(dataTag: "data2" ) << 3 << keys << texts2 << false; |
402 | |
403 | } |
404 | |
405 | void tst_QDoubleSpinBox::setTracking() |
406 | { |
407 | QLocale::setDefault(QLocale(QLocale::C)); |
408 | |
409 | actualTexts.clear(); |
410 | QFETCH(int, decimals); |
411 | QFETCH(QTestEventList, keys); |
412 | QFETCH(QStringList, texts); |
413 | QFETCH(bool, tracking); |
414 | |
415 | QDoubleSpinBox spin(0); |
416 | spin.setKeyboardTracking(tracking); |
417 | spin.setDecimals(decimals); |
418 | spin.show(); |
419 | |
420 | connect(sender: &spin, SIGNAL(valueChanged(QString)), receiver: this, SLOT(valueChangedHelper(QString))); |
421 | |
422 | keys.simulate(w: &spin); |
423 | QCOMPARE(actualTexts, texts); |
424 | } |
425 | |
426 | void tst_QDoubleSpinBox::setWrapping_data() |
427 | { |
428 | QTest::addColumn<bool>(name: "wrapping" ); |
429 | QTest::addColumn<double>(name: "minimum" ); |
430 | QTest::addColumn<double>(name: "maximum" ); |
431 | QTest::addColumn<double>(name: "startValue" ); |
432 | QTest::addColumn<QTestEventList>(name: "keys" ); |
433 | QTest::addColumn<DoubleList>(name: "expected" ); |
434 | |
435 | QTestEventList keys; |
436 | DoubleList values; |
437 | keys.addKeyClick(qtKey: Qt::Key_Up); |
438 | values << 10; |
439 | keys.addKeyClick(qtKey: Qt::Key_Up); |
440 | QTest::newRow(dataTag: "data0" ) << false << 0.0 << 10.0 << 9.0 << keys << values; |
441 | |
442 | keys.clear(); |
443 | values.clear(); |
444 | keys.addKeyClick(qtKey: Qt::Key_Up); |
445 | values << 10; |
446 | keys.addKeyClick(qtKey: Qt::Key_Up); |
447 | values << 0; |
448 | QTest::newRow(dataTag: "data1" ) << true << 0.0 << 10.0 << 9.0 << keys << values; |
449 | |
450 | keys.clear(); |
451 | values.clear(); |
452 | #ifdef Q_OS_MAC |
453 | keys.addKeyClick(Qt::Key_Right, Qt::ControlModifier); |
454 | #else |
455 | keys.addKeyClick(qtKey: Qt::Key_End); |
456 | #endif |
457 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
458 | keys.addKeyClick(ascii: '1'); |
459 | keys.addKeyClick(qtKey: Qt::Key_Down); |
460 | keys.addKeyClick(qtKey: Qt::Key_Down); |
461 | keys.addKeyClick(qtKey: Qt::Key_PageDown); |
462 | values << 9.01 << 8.01 << 7.01 << 0.0; |
463 | QTest::newRow(dataTag: "data2" ) << false << 0.0 << 10.0 << 9.0 << keys << values; |
464 | |
465 | keys.clear(); |
466 | values.clear(); |
467 | #ifdef Q_OS_MAC |
468 | keys.addKeyClick(Qt::Key_Left, Qt::ControlModifier); |
469 | #else |
470 | keys.addKeyClick(qtKey: Qt::Key_Home); |
471 | #endif |
472 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
473 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
474 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
475 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
476 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
477 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
478 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
479 | keys.addKeyClick(ascii: '1'); |
480 | keys.addKeyClick(qtKey: Qt::Key_Down); |
481 | keys.addKeyClick(qtKey: Qt::Key_Down); |
482 | values << 0 << 1 << 0 << 10; |
483 | QTest::newRow(dataTag: "data3" ) << true << 0.0 << 10.0 << 9.0 << keys << values; |
484 | |
485 | keys.clear(); |
486 | values.clear(); |
487 | keys.addKeyClick(qtKey: Qt::Key_PageDown); |
488 | keys.addKeyClick(qtKey: Qt::Key_Down); |
489 | values << 0; |
490 | QTest::newRow(dataTag: "data4" ) << false << 0.0 << 10.0 << 6.0 << keys << values; |
491 | |
492 | keys.clear(); |
493 | values.clear(); |
494 | keys.addKeyClick(qtKey: Qt::Key_PageDown); |
495 | keys.addKeyClick(qtKey: Qt::Key_Down); |
496 | values << 0 << 10; |
497 | QTest::newRow(dataTag: "data5" ) << true << 0.0 << 10.0 << 6.0 << keys << values; |
498 | |
499 | keys.clear(); |
500 | values.clear(); |
501 | keys.addKeyClick(qtKey: Qt::Key_PageUp); |
502 | keys.addKeyClick(qtKey: Qt::Key_PageDown); |
503 | keys.addKeyClick(qtKey: Qt::Key_Down); |
504 | keys.addKeyClick(qtKey: Qt::Key_Up); |
505 | keys.addKeyClick(qtKey: Qt::Key_PageDown); |
506 | keys.addKeyClick(qtKey: Qt::Key_PageDown); |
507 | values << 10 << 0 << 10 << 0 << 10 << 0; |
508 | QTest::newRow(dataTag: "data6" ) << true << 0.0 << 10.0 << 6.0 << keys << values; |
509 | |
510 | } |
511 | |
512 | |
513 | void tst_QDoubleSpinBox::setWrapping() |
514 | { |
515 | QLocale::setDefault(QLocale(QLocale::C)); |
516 | QFETCH(bool, wrapping); |
517 | QFETCH(double, minimum); |
518 | QFETCH(double, maximum); |
519 | QFETCH(double, startValue); |
520 | QFETCH(QTestEventList, keys); |
521 | QFETCH(DoubleList, expected); |
522 | |
523 | QDoubleSpinBox spin(0); |
524 | spin.setMinimum(minimum); |
525 | spin.setMaximum(maximum); |
526 | spin.setValue(startValue); |
527 | spin.setWrapping(wrapping); |
528 | spin.show(); |
529 | actualValues.clear(); |
530 | connect(sender: &spin, SIGNAL(valueChanged(double)), receiver: this, SLOT(valueChangedHelper(double))); |
531 | |
532 | keys.simulate(w: &spin); |
533 | |
534 | QCOMPARE(actualValues.size(), expected.size()); |
535 | for (int i=0; i<qMin(a: actualValues.size(), b: expected.size()); ++i) { |
536 | QCOMPARE(actualValues.at(i), expected.at(i)); |
537 | } |
538 | } |
539 | |
540 | void tst_QDoubleSpinBox::setSpecialValueText_data() |
541 | { |
542 | QTest::addColumn<QString>(name: "specialValueText" ); |
543 | QTest::addColumn<double>(name: "minimum" ); |
544 | QTest::addColumn<double>(name: "maximum" ); |
545 | QTest::addColumn<double>(name: "value" ); |
546 | QTest::addColumn<int>(name: "decimals" ); |
547 | QTest::addColumn<QString>(name: "expected" ); |
548 | QTest::addColumn<bool>(name: "show" ); |
549 | |
550 | QTest::newRow(dataTag: "data0" ) << QString() << 0.0 << 10.0 << 1.0 << 4 << "1.0000" << false; |
551 | QTest::newRow(dataTag: "data1" ) << QString() << 0.0 << 10.0 << 1.0 << 4 << "1.0000" << true; |
552 | QTest::newRow(dataTag: "data2" ) << "foo" << 0.0 << 10.0 << 0.0 << 2 << "foo" << false; |
553 | QTest::newRow(dataTag: "data3" ) << "foo" << 0.0 << 10.0 << 0.0 << 2 << "foo" << true; |
554 | } |
555 | |
556 | void tst_QDoubleSpinBox::setSpecialValueText() |
557 | { |
558 | QFETCH(QString, specialValueText); |
559 | QFETCH(double, minimum); |
560 | QFETCH(double, maximum); |
561 | QFETCH(double, value); |
562 | QFETCH(int, decimals); |
563 | QFETCH(QString, expected); |
564 | QFETCH(bool, show); |
565 | |
566 | QDoubleSpinBox spin(0); |
567 | spin.setSpecialValueText(specialValueText); |
568 | spin.setMinimum(minimum); |
569 | spin.setMaximum(maximum); |
570 | spin.setValue(value); |
571 | spin.setDecimals(decimals); |
572 | if (show) |
573 | spin.show(); |
574 | |
575 | QCOMPARE(spin.text(), expected); |
576 | } |
577 | |
578 | void tst_QDoubleSpinBox::setSingleStep_data() |
579 | { |
580 | QTest::addColumn<double>(name: "singleStep" ); |
581 | QTest::addColumn<double>(name: "startValue" ); |
582 | QTest::addColumn<QTestEventList>(name: "keys" ); |
583 | QTest::addColumn<DoubleList>(name: "expected" ); |
584 | QTest::addColumn<bool>(name: "show" ); |
585 | |
586 | QTestEventList keys; |
587 | DoubleList values; |
588 | keys.addKeyClick(qtKey: Qt::Key_Up); |
589 | keys.addKeyClick(qtKey: Qt::Key_Down); |
590 | keys.addKeyClick(qtKey: Qt::Key_Up); |
591 | values << 11 << 10 << 11; |
592 | QTest::newRow(dataTag: "data0" ) << 1.0 << 10.0 << keys << values << false; |
593 | QTest::newRow(dataTag: "data1" ) << 1.0 << 10.0 << keys << values << true; |
594 | |
595 | keys.clear(); |
596 | values.clear(); |
597 | keys.addKeyClick(qtKey: Qt::Key_Up); |
598 | keys.addKeyClick(qtKey: Qt::Key_Down); |
599 | keys.addKeyClick(qtKey: Qt::Key_Up); |
600 | values << 12.5 << 10.0 << 12.5; |
601 | QTest::newRow(dataTag: "data2" ) << 2.5 << 10.0 << keys << values << false; |
602 | QTest::newRow(dataTag: "data3" ) << 2.5 << 10.0 << keys << values << true; |
603 | } |
604 | |
605 | void tst_QDoubleSpinBox::setSingleStep() |
606 | { |
607 | QFETCH(double, singleStep); |
608 | QFETCH(double, startValue); |
609 | QFETCH(QTestEventList, keys); |
610 | QFETCH(DoubleList, expected); |
611 | QFETCH(bool, show); |
612 | |
613 | QDoubleSpinBox spin(0); |
614 | actualValues.clear(); |
615 | spin.setSingleStep(singleStep); |
616 | spin.setValue(startValue); |
617 | if (show) |
618 | spin.show(); |
619 | connect(sender: &spin, SIGNAL(valueChanged(double)), receiver: this, SLOT(valueChangedHelper(double))); |
620 | |
621 | QCOMPARE(actualValues.size(), 0); |
622 | keys.simulate(w: &spin); |
623 | QCOMPARE(actualValues.size(), expected.size()); |
624 | for (int i=0; i<qMin(a: actualValues.size(), b: expected.size()); ++i) { |
625 | QCOMPARE(actualValues.at(i), expected.at(i)); |
626 | } |
627 | } |
628 | |
629 | void tst_QDoubleSpinBox::setMinMax_data() |
630 | { |
631 | QTest::addColumn<double>(name: "startValue" ); |
632 | QTest::addColumn<double>(name: "minimum" ); |
633 | QTest::addColumn<double>(name: "maximum" ); |
634 | QTest::addColumn<QTestEventList>(name: "keys" ); |
635 | QTest::addColumn<double>(name: "expected" ); |
636 | QTest::addColumn<bool>(name: "show" ); |
637 | |
638 | QTestEventList keys; |
639 | keys.addKeyClick(qtKey: Qt::Key_Up); |
640 | keys.addKeyClick(qtKey: Qt::Key_Up); |
641 | keys.addKeyClick(qtKey: Qt::Key_Up); |
642 | keys.addKeyClick(qtKey: Qt::Key_Up); |
643 | keys.addKeyClick(qtKey: Qt::Key_Up); |
644 | QTest::newRow(dataTag: "data0" ) << 1.0 << -DBL_MAX << 2.0 << keys << 2.0 << false; |
645 | QTest::newRow(dataTag: "data1" ) << 1.0 << -DBL_MAX << 2.0 << keys << 2.0 << true; |
646 | QTest::newRow(dataTag: "data2" ) << -20000.0 << -15000.0 << -13000.0 << keys << -14995.0 << false; |
647 | QTest::newRow(dataTag: "data3" ) << -20000.0 << -15000.0 << -13000.0 << keys << -14995.0 << true; |
648 | QTest::newRow(dataTag: "data4" ) << 20.0 << -101.2 << -102.0 << QTestEventList() << -102.0 << false; |
649 | QTest::newRow(dataTag: "data5" ) << 20.0 << -101.2 << -102.0 << QTestEventList() << -102.0 << true; |
650 | } |
651 | |
652 | void tst_QDoubleSpinBox::setMinMax() |
653 | { |
654 | QFETCH(double, startValue); |
655 | QFETCH(double, minimum); |
656 | QFETCH(double, maximum); |
657 | QFETCH(QTestEventList, keys); |
658 | QFETCH(double, expected); |
659 | QFETCH(bool, show); |
660 | |
661 | { |
662 | QDoubleSpinBox spin(0); |
663 | spin.setMinimum(minimum); |
664 | spin.setMaximum(maximum); |
665 | spin.setValue(startValue); |
666 | |
667 | if (show) |
668 | spin.show(); |
669 | keys.simulate(w: &spin); |
670 | QCOMPARE(spin.value(), expected); |
671 | } |
672 | |
673 | { |
674 | QDoubleSpinBox spin(0); |
675 | spin.setMaximum(maximum); |
676 | spin.setMinimum(minimum); |
677 | spin.setValue(startValue); |
678 | |
679 | if (show) |
680 | spin.show(); |
681 | keys.simulate(w: &spin); |
682 | } |
683 | |
684 | { |
685 | QDoubleSpinBox spin(0); |
686 | spin.setRange(min: minimum, max: maximum); |
687 | spin.setValue(startValue); |
688 | |
689 | if (show) |
690 | spin.show(); |
691 | keys.simulate(w: &spin); |
692 | } |
693 | |
694 | |
695 | } |
696 | |
697 | void tst_QDoubleSpinBox::setDecimals_data() |
698 | { |
699 | QTest::addColumn<int>(name: "decimals" ); |
700 | QTest::addColumn<int>(name: "expectedDecimals" ); |
701 | QTest::addColumn<double>(name: "startValue" ); |
702 | QTest::addColumn<QString>(name: "expected" ); |
703 | |
704 | QTest::newRow(dataTag: "data0" ) << 4 << 4 << 1.0 << "1.0000" ; |
705 | QTest::newRow(dataTag: "data1" ) << 1 << 1 << 1.243443 << "1.2" ; |
706 | QTest::newRow(dataTag: "data2" ) << 6 << 6 << 1.29 << "1.290000" ; |
707 | QTest::newRow(dataTag: "data3" ) << 8 << 8 << 9.1234567809 << "9.12345678" ; |
708 | QTest::newRow(dataTag: "data4" ) << 13 << 13 << 0.12345678901237 << "0.1234567890124" ; |
709 | QTest::newRow(dataTag: "data5" ) << 13 << 13 << -0.12345678901237 << "-0.1234567890124" ; |
710 | QTest::newRow(dataTag: "data6" ) << 13 << 13 << -0.12345678901237 << "-0.1234567890124" ; |
711 | QTest::newRow(dataTag: "data7" ) << -1 << 0 << 0.1 << "0" ; |
712 | QTest::newRow(dataTag: "data8" ) << 120 << 120 << -0.12345678901237 << "-0.123456789012370005131913330842508003115653991699218750000000000000000000000000000000000000000000000000000000000000000000" ; |
713 | |
714 | } |
715 | |
716 | void tst_QDoubleSpinBox::setDecimals() |
717 | { |
718 | QFETCH(int, decimals); |
719 | QFETCH(int, expectedDecimals); |
720 | QFETCH(double, startValue); |
721 | QFETCH(QString, expected); |
722 | |
723 | QDoubleSpinBox spin(0); |
724 | spin.setRange(min: -DBL_MAX, DBL_MAX); |
725 | spin.setDecimals(decimals); |
726 | spin.setValue(startValue); |
727 | QCOMPARE(spin.decimals(), expectedDecimals); |
728 | if (sizeof(qreal) == sizeof(float)) |
729 | QCOMPARE(spin.text().left(17), expected.left(17)); |
730 | else |
731 | QCOMPARE(spin.text(), expected); |
732 | |
733 | if (spin.decimals() > 0) { |
734 | #ifdef Q_OS_MAC |
735 | QTest::keyClick(&spin, Qt::Key_Right, Qt::ControlModifier); |
736 | #else |
737 | QTest::keyClick(widget: &spin, key: Qt::Key_End); |
738 | #endif |
739 | QTest::keyClick(widget: &spin, key: Qt::Key_1); // just make sure we can't input more decimals than what is specified |
740 | QTest::keyClick(widget: &spin, key: Qt::Key_1); |
741 | QTest::keyClick(widget: &spin, key: Qt::Key_1); |
742 | QTest::keyClick(widget: &spin, key: Qt::Key_1); |
743 | QTest::keyClick(widget: &spin, key: Qt::Key_1); |
744 | if (sizeof(qreal) == sizeof(float)) |
745 | QCOMPARE(spin.text().left(17), expected.left(17)); |
746 | else |
747 | QCOMPARE(spin.text(), expected); |
748 | } |
749 | } |
750 | |
751 | static QString stateName(int state) |
752 | { |
753 | switch (state) { |
754 | case QValidator::Acceptable: return QString("Acceptable" ); |
755 | case QValidator::Intermediate: return QString("Intermediate" ); |
756 | case QValidator::Invalid: return QString("Invalid" ); |
757 | default: break; |
758 | } |
759 | qWarning(msg: "%s %d: this should never happen" , __FILE__, __LINE__); |
760 | return QString(); |
761 | } |
762 | |
763 | void tst_QDoubleSpinBox::valueFromTextAndValidate_data() |
764 | { |
765 | const int Intermediate = QValidator::Intermediate; |
766 | const int Invalid = QValidator::Invalid; |
767 | const int Acceptable = QValidator::Acceptable; |
768 | |
769 | QTest::addColumn<QString>(name: "txt" ); |
770 | QTest::addColumn<int>(name: "state" ); |
771 | QTest::addColumn<double>(name: "mini" ); |
772 | QTest::addColumn<double>(name: "maxi" ); |
773 | QTest::addColumn<int>(name: "language" ); |
774 | QTest::addColumn<QString>(name: "expectedText" ); // if empty we don't check |
775 | |
776 | QTest::newRow(dataTag: "data0" ) << QString("2.2" ) << Intermediate << 3.0 << 5.0 << (int)QLocale::C << QString(); |
777 | QTest::newRow(dataTag: "data1" ) << QString() << Intermediate << 0.0 << 100.0 << (int)QLocale::C << QString(); |
778 | QTest::newRow(dataTag: "data2" ) << QString("asd" ) << Invalid << 0.0 << 100.0 << (int)QLocale::C << QString(); |
779 | QTest::newRow(dataTag: "data3" ) << QString("2.2" ) << Acceptable << 0.0 << 100.0 << (int)QLocale::C << QString(); |
780 | QTest::newRow(dataTag: "data4" ) << QString(" " ) << Intermediate << 0.0 << 100.0 << (int)QLocale::NorwegianBokmal << QString(); |
781 | QTest::newRow(dataTag: "data5" ) << QString(" " ) << Intermediate << 0.0 << 100.0 << (int)QLocale::C << QString(); |
782 | QTest::newRow(dataTag: "data6" ) << QString("," ) << Intermediate << 0.0 << 100.0 << (int)QLocale::NorwegianBokmal << QString(); |
783 | QTest::newRow(dataTag: "data7" ) << QString("," ) << Invalid << 0.0 << 100.0 << (int)QLocale::C << QString(); |
784 | QTest::newRow(dataTag: "data8" ) << QString("1 " ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::NorwegianBokmal << QString("1" ); |
785 | QTest::newRow(dataTag: "data9" ) << QString("1 " ) << Acceptable << 0.0 << 100.0 << (int)QLocale::C << QString("1" ); |
786 | QTest::newRow(dataTag: "data10" ) << QString(" 1" ) << Acceptable << 0.0 << 100.0 << (int)QLocale::NorwegianBokmal << QString("1" ); |
787 | QTest::newRow(dataTag: "data11" ) << QString(" 1" ) << Acceptable << 0.0 << 100.0 << (int)QLocale::C << QString("1" ); |
788 | QTest::newRow(dataTag: "data12" ) << QString("1," ) << Acceptable << 0.0 << 100.0 << (int)QLocale::NorwegianBokmal << QString(); |
789 | QTest::newRow(dataTag: "data13" ) << QString("1," ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::C << QString(); |
790 | QTest::newRow(dataTag: "data14" ) << QString("1, " ) << Acceptable << 0.0 << 100.0 << (int)QLocale::NorwegianBokmal << QString("1," ); |
791 | QTest::newRow(dataTag: "data15" ) << QString("1, " ) << Invalid << 0.0 << 100.0 << (int)QLocale::C << QString(); |
792 | QTest::newRow(dataTag: "data16" ) << QString("2" ) << Intermediate << 100.0 << 102.0 << (int)QLocale::C << QString(); |
793 | QTest::newRow(dataTag: "data17" ) << QString("22.0" ) << Intermediate << 100.0 << 102.0 << (int)QLocale::C << QString(); |
794 | QTest::newRow(dataTag: "data18" ) << QString("12.0" ) << Intermediate << 100.0 << 102.0 << (int)QLocale::C << QString(); |
795 | QTest::newRow(dataTag: "data19" ) << QString("12.2" ) << Intermediate << 100. << 102.0 << (int)QLocale::C << QString(); |
796 | QTest::newRow(dataTag: "data20" ) << QString("21." ) << Intermediate << 100.0 << 102.0 << (int)QLocale::C << QString(); |
797 | QTest::newRow(dataTag: "data21" ) << QString("-21." ) << Intermediate << -102.0 << -100.0 << (int)QLocale::C << QString(); |
798 | QTest::newRow(dataTag: "data22" ) << QString("-12." ) << Intermediate << -102.0 << -100.0 << (int)QLocale::C << QString(); |
799 | QTest::newRow(dataTag: "data23" ) << QString("-11.11" ) << Intermediate << -102.0 << -101.2 << (int)QLocale::C << QString(); |
800 | QTest::newRow(dataTag: "data24" ) << QString("-11.4" ) << Intermediate << -102.0 << -101.3 << (int)QLocale::C << QString(); |
801 | QTest::newRow(dataTag: "data25" ) << QString("11.400" ) << Invalid << 0.0 << 100.0 << (int)QLocale::C << QString(); |
802 | QTest::newRow(dataTag: "data26" ) << QString(".4" ) << Intermediate << 0.45 << 0.5 << (int)QLocale::C << QString(); |
803 | QTest::newRow(dataTag: "data27" ) << QString("+.4" ) << Intermediate << 0.45 << 0.5 << (int)QLocale::C << QString(); |
804 | QTest::newRow(dataTag: "data28" ) << QString("-.4" ) << Intermediate << -0.5 << -0.45 << (int)QLocale::C << QString(); |
805 | QTest::newRow(dataTag: "data29" ) << QString(".4" ) << Intermediate << 1.0 << 2.4 << (int)QLocale::C << QString(); |
806 | QTest::newRow(dataTag: "data30" ) << QString("-.4" ) << Intermediate << -2.3 << -1.9 << (int)QLocale::C << QString(); |
807 | QTest::newRow(dataTag: "data31" ) << QString("-42" ) << Invalid << -2.43 << -1.0 << (int)QLocale::C << QString(); |
808 | QTest::newRow(dataTag: "data32" ) << QString("-4" ) << Invalid << -1.4 << -1.0 << (int)QLocale::C << QString(); |
809 | QTest::newRow(dataTag: "data33" ) << QString("-42" ) << Invalid << -1.4 << -1.0 << (int)QLocale::C << QString(); |
810 | QTest::newRow(dataTag: "data34" ) << QString("1000000000000" ) << Invalid << -140.0 << -120.2 << (int)QLocale::C << QString(); |
811 | QTest::newRow(dataTag: "data35" ) << QString("+.12" ) << Invalid << -5.0 << -3.2 << (int)QLocale::C << QString(); |
812 | QTest::newRow(dataTag: "data36" ) << QString("-.12" ) << Invalid << 5.0 << 33.2 << (int)QLocale::C << QString(); |
813 | QTest::newRow(dataTag: "data37" ) << QString("12.2" ) << Intermediate << 100. << 103.0 << (int)QLocale::C << QString(); |
814 | QTest::newRow(dataTag: "data38" ) << QString("12.2" ) << Intermediate << 100. << 102.3 << (int)QLocale::C << QString(); |
815 | QTest::newRow(dataTag: "data39" ) << QString("-12." ) << Acceptable << -102.0 << 102.0 << (int)QLocale::C << QString(); |
816 | QTest::newRow(dataTag: "data40" ) << QString("12." ) << Invalid << -102.0 << 11.0 << (int)QLocale::C << QString(); |
817 | QTest::newRow(dataTag: "data41" ) << QString("103." ) << Invalid << -102.0 << 11.0 << (int)QLocale::C << QString(); |
818 | QTest::newRow(dataTag: "data42" ) << QString("122" ) << Invalid << 10.0 << 12.2 << (int)QLocale::C << QString(); |
819 | QTest::newRow(dataTag: "data43" ) << QString("-2.2" ) << Intermediate << -12.2 << -3.2 << (int)QLocale::C << QString(); |
820 | QTest::newRow(dataTag: "data44" ) << QString("-2.20" ) << Intermediate << -12.1 << -3.2 << (int)QLocale::C << QString(); |
821 | QTest::newRow(dataTag: "data45" ) << QString("200,2" ) << Invalid << 0.0 << 1000.0 << (int)QLocale::C << QString(); |
822 | QTest::newRow(dataTag: "data46" ) << QString("200,2" ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::German << QString(); |
823 | QTest::newRow(dataTag: "data47" ) << QString("2.2" ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::C << QString(); |
824 | QTest::newRow(dataTag: "data48" ) << QString("2.2" ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::German << QString(); |
825 | QTest::newRow(dataTag: "data49" ) << QString("2.2,00" ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::German << QString(); |
826 | QTest::newRow(dataTag: "data50" ) << QString("2.2" ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::C << QString(); |
827 | QTest::newRow(dataTag: "data51" ) << QString("2.2,00" ) << Invalid << 0.0 << 1000.0 << (int)QLocale::C << QString(); |
828 | QTest::newRow(dataTag: "data52" ) << QString("2..2,00" ) << Invalid << 0.0 << 1000.0 << (int)QLocale::German << QString(); |
829 | QTest::newRow(dataTag: "data53" ) << QString("2.2" ) << Invalid << 0.0 << 1000.0 << (int)QLocale::NorwegianBokmal << QString(); |
830 | QTest::newRow(dataTag: "data54" ) << QString(" 2.2" ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::C << QString(); |
831 | QTest::newRow(dataTag: "data55" ) << QString("2.2 " ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::C << QString("2.2" ); |
832 | QTest::newRow(dataTag: "data56" ) << QString(" 2.2 " ) << Acceptable << 0.0 << 1000.0 << (int)QLocale::C << QString("2.2" ); |
833 | QTest::newRow(dataTag: "data57" ) << QString("2 2" ) << Invalid << 0.0 << 1000.0 << (int)QLocale::C << QString(); |
834 | } |
835 | |
836 | void tst_QDoubleSpinBox::valueFromTextAndValidate() |
837 | { |
838 | QFETCH(QString, txt); |
839 | QFETCH(int, state); |
840 | QFETCH(double, mini); |
841 | QFETCH(double, maxi); |
842 | QFETCH(int, language); |
843 | QFETCH(QString, expectedText); |
844 | QLocale::setDefault(QLocale((QLocale::Language)language)); |
845 | |
846 | DoubleSpinBox sb(0); |
847 | sb.show(); |
848 | sb.setRange(min: mini, max: maxi); |
849 | |
850 | int unused = 0; |
851 | QCOMPARE(stateName(sb.validate(txt, unused)), stateName(state)); |
852 | if (!expectedText.isEmpty()) |
853 | QCOMPARE(txt, expectedText); |
854 | } |
855 | |
856 | void tst_QDoubleSpinBox::setReadOnly() |
857 | { |
858 | QDoubleSpinBox spin(0); |
859 | spin.setValue(0.2); |
860 | spin.show(); |
861 | QVERIFY(QTest::qWaitForWindowActive(&spin)); |
862 | QCOMPARE(spin.value(), 0.2); |
863 | QTest::keyClick(widget: &spin, key: Qt::Key_Up); |
864 | QCOMPARE(spin.value(), 1.2); |
865 | spin.setReadOnly(true); |
866 | QTest::keyClick(widget: &spin, key: Qt::Key_Up); |
867 | QCOMPARE(spin.value(), 1.2); |
868 | spin.stepBy(steps: 1); |
869 | QCOMPARE(spin.value(), 2.2); |
870 | spin.setReadOnly(false); |
871 | QTest::keyClick(widget: &spin, key: Qt::Key_Up); |
872 | QCOMPARE(spin.value(), 3.2); |
873 | } |
874 | |
875 | void tst_QDoubleSpinBox::editingFinished() |
876 | { |
877 | QVBoxLayout *layout = new QVBoxLayout(testFocusWidget); |
878 | QDoubleSpinBox *box = new QDoubleSpinBox(testFocusWidget); |
879 | layout->addWidget(box); |
880 | QDoubleSpinBox *box2 = new QDoubleSpinBox(testFocusWidget); |
881 | layout->addWidget(box2); |
882 | |
883 | testFocusWidget->show(); |
884 | testFocusWidget->activateWindow(); |
885 | QVERIFY(QTest::qWaitForWindowActive(testFocusWidget)); |
886 | box->setFocus(); |
887 | QTRY_VERIFY(box->hasFocus()); |
888 | |
889 | QSignalSpy editingFinishedSpy1(box, SIGNAL(editingFinished())); |
890 | QSignalSpy editingFinishedSpy2(box2, SIGNAL(editingFinished())); |
891 | |
892 | QTest::keyClick(widget: box, key: Qt::Key_Up); |
893 | QTest::keyClick(widget: box, key: Qt::Key_Up); |
894 | |
895 | |
896 | QCOMPARE(editingFinishedSpy1.count(), 0); |
897 | QCOMPARE(editingFinishedSpy2.count(), 0); |
898 | |
899 | QTest::keyClick(widget: box2, key: Qt::Key_Up); |
900 | QTest::keyClick(widget: box2, key: Qt::Key_Up); |
901 | box2->setFocus(); |
902 | QCOMPARE(editingFinishedSpy1.count(), 1); |
903 | box->setFocus(); |
904 | QCOMPARE(editingFinishedSpy1.count(), 1); |
905 | QCOMPARE(editingFinishedSpy2.count(), 1); |
906 | QTest::keyClick(widget: box, key: Qt::Key_Up); |
907 | QCOMPARE(editingFinishedSpy1.count(), 1); |
908 | QCOMPARE(editingFinishedSpy2.count(), 1); |
909 | QTest::keyClick(widget: box, key: Qt::Key_Enter); |
910 | QCOMPARE(editingFinishedSpy1.count(), 2); |
911 | QCOMPARE(editingFinishedSpy2.count(), 1); |
912 | QTest::keyClick(widget: box, key: Qt::Key_Return); |
913 | QCOMPARE(editingFinishedSpy1.count(), 3); |
914 | QCOMPARE(editingFinishedSpy2.count(), 1); |
915 | box2->setFocus(); |
916 | QCOMPARE(editingFinishedSpy1.count(), 4); |
917 | QCOMPARE(editingFinishedSpy2.count(), 1); |
918 | QTest::keyClick(widget: box2, key: Qt::Key_Enter); |
919 | QCOMPARE(editingFinishedSpy1.count(), 4); |
920 | QCOMPARE(editingFinishedSpy2.count(), 2); |
921 | QTest::keyClick(widget: box2, key: Qt::Key_Return); |
922 | QCOMPARE(editingFinishedSpy1.count(), 4); |
923 | QCOMPARE(editingFinishedSpy2.count(), 3); |
924 | testFocusWidget->hide(); |
925 | QCOMPARE(editingFinishedSpy1.count(), 4); |
926 | QCOMPARE(editingFinishedSpy2.count(), 4); |
927 | |
928 | // On some platforms this is our root window |
929 | // we need to show it again otherwise subsequent |
930 | // tests will fail |
931 | testFocusWidget->show(); |
932 | } |
933 | |
934 | void tst_QDoubleSpinBox::removeAll() |
935 | { |
936 | DoubleSpinBox spin(0); |
937 | spin.setPrefix("foo" ); |
938 | spin.setSuffix("bar" ); |
939 | spin.setValue(0.2); |
940 | spin.setDecimals(1); |
941 | spin.show(); |
942 | #ifdef Q_OS_MAC |
943 | QTest::keyClick(&spin, Qt::Key_Left, Qt::ControlModifier); |
944 | #else |
945 | QTest::keyClick(widget: &spin, key: Qt::Key_Home); |
946 | #endif |
947 | |
948 | #ifdef Q_OS_MAC |
949 | QTest::keyClick(&spin, Qt::Key_Right, Qt::ControlModifier|Qt::ShiftModifier); |
950 | #else |
951 | QTest::keyClick(widget: &spin, key: Qt::Key_End, modifier: Qt::ShiftModifier); |
952 | #endif |
953 | |
954 | QCOMPARE(spin.lineEdit()->selectedText(), QString("foo0.2bar" )); |
955 | QTest::keyClick(widget: &spin, key: Qt::Key_1); |
956 | QCOMPARE(spin.text(), QString("foo1bar" )); |
957 | } |
958 | |
959 | void tst_QDoubleSpinBox::task54433() |
960 | { |
961 | DoubleSpinBox priceSpinBox; |
962 | QCOMPARE(priceSpinBox.decimals(), 2); |
963 | priceSpinBox.show(); |
964 | priceSpinBox.setRange(min: 0.0, max: 999.99); |
965 | priceSpinBox.setDecimals(2); |
966 | priceSpinBox.setValue(999.99); |
967 | QCOMPARE(priceSpinBox.text(), QString("999.99" )); |
968 | QCOMPARE(priceSpinBox.value(), 999.99); |
969 | QCOMPARE(priceSpinBox.maximum(), 999.99); |
970 | priceSpinBox.setDecimals(1); |
971 | QCOMPARE(priceSpinBox.value(), 1000.0); |
972 | QCOMPARE(priceSpinBox.maximum(), 1000.0); |
973 | QCOMPARE(priceSpinBox.text(), QString("1000.0" )); |
974 | |
975 | priceSpinBox.setDecimals(2); |
976 | priceSpinBox.setRange(min: -999.99, max: 0.0); |
977 | priceSpinBox.setValue(-999.99); |
978 | QCOMPARE(priceSpinBox.text(), QString("-999.99" )); |
979 | QCOMPARE(priceSpinBox.value(), -999.99); |
980 | QCOMPARE(priceSpinBox.minimum(), -999.99); |
981 | priceSpinBox.setDecimals(1); |
982 | QCOMPARE(priceSpinBox.value(), -1000.0); |
983 | QCOMPARE(priceSpinBox.minimum(), -1000.0); |
984 | QCOMPARE(priceSpinBox.text(), QString("-1000.0" )); |
985 | } |
986 | |
987 | |
988 | |
989 | void tst_QDoubleSpinBox::germanTest() |
990 | { |
991 | QLocale::setDefault(QLocale(QLocale::German)); |
992 | DoubleSpinBox spin; |
993 | spin.show(); |
994 | spin.setValue(2.12); |
995 | #ifdef Q_OS_MAC |
996 | QTest::keyClick(&spin, Qt::Key_Right, Qt::ControlModifier); |
997 | #else |
998 | QTest::keyClick(widget: &spin, key: Qt::Key_End); |
999 | #endif |
1000 | QTest::keyClick(widget: &spin, key: Qt::Key_Backspace); |
1001 | QCOMPARE(spin.text(), QString("2,1" )); |
1002 | QTest::keyClick(widget: &spin, key: Qt::Key_Enter); |
1003 | QCOMPARE(spin.text(), QString("2,10" )); |
1004 | } |
1005 | |
1006 | void tst_QDoubleSpinBox::doubleDot() |
1007 | { |
1008 | DoubleSpinBox spin; |
1009 | spin.show(); |
1010 | spin.setValue(2.12); |
1011 | QTest::keyClick(widget: &spin, key: Qt::Key_Backspace); |
1012 | QCOMPARE(spin.text(), QString("2.12" )); |
1013 | #ifdef Q_OS_MAC |
1014 | QTest::keyClick(&spin, Qt::Key_Left, Qt::ControlModifier); |
1015 | #else |
1016 | QTest::keyClick(widget: &spin, key: Qt::Key_Home); |
1017 | #endif |
1018 | QTest::keyClick(widget: &spin, key: Qt::Key_Right, modifier: Qt::ShiftModifier); |
1019 | QCOMPARE(spin.lineEdit()->selectedText(), QString("2" )); |
1020 | QTest::keyClick(widget: &spin, key: Qt::Key_1); |
1021 | QCOMPARE(spin.text(), QString("1.12" )); |
1022 | QCOMPARE(spin.lineEdit()->cursorPosition(), 1); |
1023 | QTest::keyClick(widget: &spin, key: Qt::Key_Period); |
1024 | QCOMPARE(spin.text(), QString("1.12" )); |
1025 | QCOMPARE(spin.lineEdit()->cursorPosition(), 2); |
1026 | } |
1027 | |
1028 | void tst_QDoubleSpinBox::undoRedo() |
1029 | { |
1030 | //test undo/redo feature (in conjunction with the "undoRedoEnabled" property) |
1031 | DoubleSpinBox spin(0); |
1032 | spin.show(); |
1033 | |
1034 | //the undo/redo is disabled by default |
1035 | |
1036 | QCOMPARE(spin.value(), 0.0); //this is the default value |
1037 | QVERIFY(!spin.lineEdit()->isUndoAvailable()); |
1038 | QVERIFY(!spin.lineEdit()->isRedoAvailable()); |
1039 | |
1040 | spin.lineEdit()->selectAll(); //ensures everything is selected and will be cleared by typing a key |
1041 | QTest::keyClick(widget: &spin, key: Qt::Key_1); //we put 1 into the spinbox |
1042 | QCOMPARE(spin.value(), 1.0); |
1043 | QVERIFY(spin.lineEdit()->isUndoAvailable()); |
1044 | |
1045 | //testing CTRL+Z (undo) |
1046 | int val = QKeySequence(QKeySequence::Undo)[0]; |
1047 | if (val != 0) { |
1048 | Qt::KeyboardModifiers mods = (Qt::KeyboardModifiers)(val & Qt::KeyboardModifierMask); |
1049 | QTest::keyClick(widget: &spin, key: val & ~mods, modifier: mods); |
1050 | QCOMPARE(spin.value(), 0.0); |
1051 | QVERIFY(!spin.lineEdit()->isUndoAvailable()); |
1052 | QVERIFY(spin.lineEdit()->isRedoAvailable()); |
1053 | } else { |
1054 | QWARN("Undo not tested because no key sequence associated to QKeySequence::Redo" ); |
1055 | } |
1056 | |
1057 | |
1058 | //testing CTRL+Y (redo) |
1059 | val = QKeySequence(QKeySequence::Redo)[0]; |
1060 | if (val != 0) { |
1061 | Qt::KeyboardModifiers mods = (Qt::KeyboardModifiers)(val & Qt::KeyboardModifierMask); |
1062 | QTest::keyClick(widget: &spin, key: val & ~mods, modifier: mods); |
1063 | QCOMPARE(spin.value(), 1.0); |
1064 | QVERIFY(!spin.lineEdit()->isRedoAvailable()); |
1065 | QVERIFY(spin.lineEdit()->isUndoAvailable()); |
1066 | } else { |
1067 | QWARN("Redo not tested because no key sequence associated to QKeySequence::Redo" ); |
1068 | } |
1069 | |
1070 | |
1071 | spin.setValue(55.0); |
1072 | QVERIFY(!spin.lineEdit()->isUndoAvailable()); |
1073 | QVERIFY(!spin.lineEdit()->isRedoAvailable()); |
1074 | } |
1075 | |
1076 | struct task199226_DoubleSpinBox : public QDoubleSpinBox |
1077 | { |
1078 | task199226_DoubleSpinBox(QWidget *parent = 0) : QDoubleSpinBox(parent) {} |
1079 | QLineEdit *lineEdit() { return QAbstractSpinBox::lineEdit(); } |
1080 | }; |
1081 | |
1082 | void tst_QDoubleSpinBox::task199226_stateAfterEnter() |
1083 | { |
1084 | task199226_DoubleSpinBox spin; |
1085 | spin.setMinimum(0); |
1086 | spin.setMaximum(10); |
1087 | spin.setDecimals(0); |
1088 | spin.show(); |
1089 | QTest::mouseDClick(widget: spin.lineEdit(), button: Qt::LeftButton); |
1090 | QTest::keyClick(widget: spin.lineEdit(), key: Qt::Key_3); |
1091 | QVERIFY(spin.lineEdit()->isModified()); |
1092 | QVERIFY(spin.lineEdit()->isUndoAvailable()); |
1093 | QTest::keyClick(widget: spin.lineEdit(), key: Qt::Key_Enter); |
1094 | QVERIFY(!spin.lineEdit()->isModified()); |
1095 | QVERIFY(!spin.lineEdit()->isUndoAvailable()); |
1096 | } |
1097 | |
1098 | class task224497_fltMax_DoubleSpinBox : public QDoubleSpinBox |
1099 | { |
1100 | public: |
1101 | QLineEdit * lineEdit () const { return QDoubleSpinBox::lineEdit(); } |
1102 | }; |
1103 | |
1104 | void tst_QDoubleSpinBox::task224497_fltMax() |
1105 | { |
1106 | task224497_fltMax_DoubleSpinBox *dspin = new task224497_fltMax_DoubleSpinBox; |
1107 | dspin->setMinimum(3); |
1108 | dspin->setMaximum(FLT_MAX); |
1109 | dspin->show(); |
1110 | QVERIFY(QTest::qWaitForWindowActive(dspin)); |
1111 | dspin->lineEdit()->selectAll(); |
1112 | QTest::keyClick(widget: dspin->lineEdit(), key: Qt::Key_Delete); |
1113 | QTest::keyClick(widget: dspin->lineEdit(), key: Qt::Key_1); |
1114 | QCOMPARE(dspin->cleanText(), QLatin1String("1" )); |
1115 | } |
1116 | |
1117 | void tst_QDoubleSpinBox::task221221() |
1118 | { |
1119 | QDoubleSpinBox spin; |
1120 | QTest::keyClick(widget: &spin, key: Qt::Key_1); |
1121 | spin.show(); |
1122 | QVERIFY(QTest::qWaitForWindowExposed(&spin)); |
1123 | QCOMPARE(spin.text(), QLatin1String("1" )); |
1124 | } |
1125 | |
1126 | void tst_QDoubleSpinBox::task255471_decimalsValidation() |
1127 | { |
1128 | // QDoubleSpinBox shouldn't crash with large numbers of decimals. Even if |
1129 | // the results are useless ;-) |
1130 | for (int i = 0; i < 32; ++i) |
1131 | { |
1132 | QDoubleSpinBox spinBox; |
1133 | spinBox.setDecimals(i); |
1134 | spinBox.setMinimum(0.3); |
1135 | spinBox.setMaximum(12); |
1136 | |
1137 | spinBox.show(); |
1138 | QVERIFY(QTest::qWaitForWindowExposed(&spinBox)); |
1139 | spinBox.setFocus(); |
1140 | QTRY_VERIFY(spinBox.hasFocus()); |
1141 | |
1142 | QTest::keyPress(widget: &spinBox, key: Qt::Key_Right); |
1143 | QTest::keyPress(widget: &spinBox, key: Qt::Key_Right); |
1144 | QTest::keyPress(widget: &spinBox, key: Qt::Key_Delete); |
1145 | |
1146 | // Don't crash! |
1147 | QTest::keyPress(widget: &spinBox, key: Qt::Key_2); |
1148 | } |
1149 | } |
1150 | |
1151 | void tst_QDoubleSpinBox::taskQTBUG_5008_textFromValueAndValidate() |
1152 | { |
1153 | class DecoratedSpinBox : public QDoubleSpinBox |
1154 | { |
1155 | public: |
1156 | DecoratedSpinBox() |
1157 | { |
1158 | setLocale(QLocale::French); |
1159 | setMaximum(100000000); |
1160 | setValue(1000); |
1161 | } |
1162 | |
1163 | QLineEdit *lineEdit() const |
1164 | { |
1165 | return QDoubleSpinBox::lineEdit(); |
1166 | } |
1167 | |
1168 | //we use the French delimiters here |
1169 | QString textFromValue (double value) const |
1170 | { |
1171 | return locale().toString(i: value); |
1172 | } |
1173 | } spinbox; |
1174 | spinbox.show(); |
1175 | spinbox.activateWindow(); |
1176 | spinbox.setFocus(); |
1177 | QApplication::setActiveWindow(&spinbox); |
1178 | QVERIFY(QTest::qWaitForWindowActive(&spinbox)); |
1179 | QCOMPARE(static_cast<QWidget *>(&spinbox), QApplication::activeWindow()); |
1180 | QTRY_VERIFY(spinbox.hasFocus()); |
1181 | QCOMPARE(spinbox.text(), spinbox.locale().toString(spinbox.value())); |
1182 | spinbox.lineEdit()->setCursorPosition(2); //just after the first thousand separator |
1183 | QTest::keyClick(widget: static_cast<QWidget *>(0), key: Qt::Key_0); // let's insert a 0 |
1184 | QCOMPARE(spinbox.value(), 10000.); |
1185 | spinbox.clearFocus(); //make sure the value is correctly formatted |
1186 | QCOMPARE(spinbox.text(), spinbox.locale().toString(spinbox.value())); |
1187 | } |
1188 | |
1189 | void tst_QDoubleSpinBox::taskQTBUG_6670_selectAllWithPrefix() |
1190 | { |
1191 | DoubleSpinBox spin; |
1192 | spin.setPrefix("$ " ); |
1193 | spin.lineEdit()->selectAll(); |
1194 | QTest::keyClick(widget: spin.lineEdit(), key: Qt::Key_1); |
1195 | QCOMPARE(spin.value(), 1.); |
1196 | QTest::keyClick(widget: spin.lineEdit(), key: Qt::Key_2); |
1197 | QCOMPARE(spin.value(), 12.); |
1198 | } |
1199 | |
1200 | void tst_QDoubleSpinBox::taskQTBUG_6496_fiddlingWithPrecision() |
1201 | { |
1202 | QDoubleSpinBox dsb; |
1203 | dsb.setRange(min: 0, max: 0.991); |
1204 | dsb.setDecimals(1); |
1205 | QCOMPARE(dsb.maximum(), 1.0); |
1206 | dsb.setDecimals(2); |
1207 | QCOMPARE(dsb.maximum(), 0.99); |
1208 | dsb.setDecimals(3); |
1209 | QCOMPARE(dsb.maximum(), 0.991); |
1210 | } |
1211 | |
1212 | void tst_QDoubleSpinBox::setGroupSeparatorShown_data() |
1213 | { |
1214 | QTest::addColumn<QLocale::Language>(name: "lang" ); |
1215 | QTest::addColumn<QLocale::Country>(name: "country" ); |
1216 | |
1217 | QTest::newRow(dataTag: "data0" ) << QLocale::English << QLocale::UnitedStates; |
1218 | QTest::newRow(dataTag: "data1" ) << QLocale::Swedish << QLocale::Sweden; |
1219 | QTest::newRow(dataTag: "data2" ) << QLocale::German << QLocale::Germany; |
1220 | QTest::newRow(dataTag: "data3" ) << QLocale::Georgian << QLocale::Georgia; |
1221 | QTest::newRow(dataTag: "data3" ) << QLocale::Macedonian << QLocale::Macedonia; |
1222 | } |
1223 | |
1224 | void tst_QDoubleSpinBox::setGroupSeparatorShown() |
1225 | { |
1226 | QFETCH(QLocale::Language, lang); |
1227 | QFETCH(QLocale::Country, country); |
1228 | |
1229 | QLocale loc(lang, country); |
1230 | QLocale::setDefault(loc); |
1231 | DoubleSpinBox spinBox; |
1232 | spinBox.setMaximum(99999999); |
1233 | spinBox.setValue(1300000.00); |
1234 | spinBox.setGroupSeparatorShown(true); |
1235 | QCOMPARE(spinBox.lineEdit()->text(), spinBox.locale().toString(1300000.00, 'f', 2)); |
1236 | QCOMPARE(spinBox.isGroupSeparatorShown(), true); |
1237 | QCOMPARE(spinBox.textFromValue(23421),spinBox.locale().toString(23421.00, 'f', 2)); |
1238 | |
1239 | spinBox.setGroupSeparatorShown(false); |
1240 | QCOMPARE(spinBox.lineEdit()->text(), spinBox.locale().toString(1300000.00, 'f', 2).remove( |
1241 | spinBox.locale().groupSeparator())); |
1242 | QCOMPARE(spinBox.isGroupSeparatorShown(), false); |
1243 | |
1244 | spinBox.setMaximum(72000); |
1245 | spinBox.lineEdit()->setText(spinBox.locale().toString(i: 32000.64, f: 'f', prec: 2)); |
1246 | QCOMPARE(spinBox.value()+1000, 33000.64); |
1247 | |
1248 | spinBox.lineEdit()->setText(spinBox.locale().toString(i: 32000.44, f: 'f', prec: 2)); |
1249 | QCOMPARE(spinBox.value()+1000, 33000.44); |
1250 | } |
1251 | |
1252 | void tst_QDoubleSpinBox::adaptiveDecimalStep() |
1253 | { |
1254 | DoubleSpinBox spinBox; |
1255 | spinBox.setRange(min: -100000, max: 100000); |
1256 | spinBox.setDecimals(4); |
1257 | spinBox.setStepType(DoubleSpinBox::StepType::AdaptiveDecimalStepType); |
1258 | |
1259 | // Positive values |
1260 | |
1261 | spinBox.setValue(0); |
1262 | |
1263 | // Go from 0 to 0.01 |
1264 | for (double i = 0; i < 0.00999; i += 0.0001) { |
1265 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1266 | spinBox.stepBy(steps: 1); |
1267 | } |
1268 | |
1269 | // Go from 0.01 to 0.1 |
1270 | for (double i = 0.01; i < 0.0999; i += 0.001) { |
1271 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1272 | spinBox.stepBy(steps: 1); |
1273 | } |
1274 | |
1275 | // Go from 0.1 to 1 |
1276 | for (double i = 0.1; i < 0.999; i += 0.01) { |
1277 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1278 | spinBox.stepBy(steps: 1); |
1279 | } |
1280 | |
1281 | // Go from 1 to 10 |
1282 | for (double i = 1; i < 9.99; i += 0.1) { |
1283 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1284 | spinBox.stepBy(steps: 1); |
1285 | } |
1286 | |
1287 | // Go from 10 to 100 |
1288 | for (int i = 10; i < 100; i++) { |
1289 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1290 | spinBox.stepBy(steps: 1); |
1291 | } |
1292 | |
1293 | // Go from 100 to 1000 |
1294 | for (int i = 100; i < 1000; i += 10) { |
1295 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1296 | spinBox.stepBy(steps: 1); |
1297 | } |
1298 | |
1299 | // Go from 1000 to 10000 |
1300 | for (int i = 1000; i < 10000; i += 100) { |
1301 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1302 | spinBox.stepBy(steps: 1); |
1303 | } |
1304 | |
1305 | // Test decreasing the values now |
1306 | |
1307 | // Go from 10000 down to 1000 |
1308 | for (int i = 10000; i > 1000; i -= 100) { |
1309 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1310 | spinBox.stepBy(steps: -1); |
1311 | } |
1312 | |
1313 | // Go from 1000 down to 100 |
1314 | for (int i = 1000; i > 100; i -= 10) { |
1315 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1316 | spinBox.stepBy(steps: -1); |
1317 | } |
1318 | |
1319 | // Negative values |
1320 | |
1321 | spinBox.setValue(0); |
1322 | |
1323 | // Go from 0 to -0.01 |
1324 | for (double i = 0; i > -0.00999; i -= 0.0001) { |
1325 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1326 | spinBox.stepBy(steps: -1); |
1327 | } |
1328 | |
1329 | // Go from -0.01 to -0.1 |
1330 | for (double i = -0.01; i > -0.0999; i -= 0.001) { |
1331 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1332 | spinBox.stepBy(steps: -1); |
1333 | } |
1334 | |
1335 | // Go from -0.1 to -1 |
1336 | for (double i = -0.1; i > -0.999; i -= 0.01) { |
1337 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1338 | spinBox.stepBy(steps: -1); |
1339 | } |
1340 | |
1341 | // Go from -1 to -10 |
1342 | for (double i = -1; i > -9.99; i -= 0.1) { |
1343 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1344 | spinBox.stepBy(steps: -1); |
1345 | } |
1346 | |
1347 | // Go from -10 to -100 |
1348 | for (int i = -10; i > -100; i--) { |
1349 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1350 | spinBox.stepBy(steps: -1); |
1351 | } |
1352 | |
1353 | // Go from -100 to -1000 |
1354 | for (int i = -100; i > -1000; i -= 10) { |
1355 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1356 | spinBox.stepBy(steps: -1); |
1357 | } |
1358 | |
1359 | // Go from 1000 to 10000 |
1360 | for (int i = -1000; i > -10000; i -= 100) { |
1361 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1362 | spinBox.stepBy(steps: -1); |
1363 | } |
1364 | |
1365 | // Test increasing the values now |
1366 | |
1367 | // Go from -10000 up to -1000 |
1368 | for (int i = -10000; i < -1000; i += 100) { |
1369 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1370 | spinBox.stepBy(steps: 1); |
1371 | } |
1372 | |
1373 | // Go from -1000 up to -100 |
1374 | for (int i = -1000; i < -100; i += 10) { |
1375 | QVERIFY(qFuzzyCompare(spinBox.value(), i)); |
1376 | spinBox.stepBy(steps: 1); |
1377 | } |
1378 | } |
1379 | |
1380 | void tst_QDoubleSpinBox::wheelEvents_data() |
1381 | { |
1382 | #if QT_CONFIG(wheelevent) |
1383 | QTest::addColumn<QPoint>(name: "angleDelta" ); |
1384 | QTest::addColumn<int>(name: "stepModifier" ); |
1385 | QTest::addColumn<Qt::KeyboardModifiers>(name: "modifier" ); |
1386 | QTest::addColumn<Qt::MouseEventSource>(name: "source" ); |
1387 | QTest::addColumn<double>(name: "start" ); |
1388 | QTest::addColumn<DoubleList>(name: "expectedValues" ); |
1389 | |
1390 | const auto fractions = {false, true}; |
1391 | |
1392 | const auto directions = {true, false}; |
1393 | |
1394 | const auto modifierList = {Qt::NoModifier, |
1395 | Qt::ShiftModifier, |
1396 | Qt::ControlModifier, |
1397 | Qt::AltModifier, |
1398 | Qt::MetaModifier}; |
1399 | |
1400 | const auto validStepModifierList = {Qt::NoModifier, |
1401 | Qt::ControlModifier, |
1402 | Qt::ShiftModifier}; |
1403 | |
1404 | const auto sources = {Qt::MouseEventNotSynthesized, |
1405 | Qt::MouseEventSynthesizedBySystem, |
1406 | Qt::MouseEventSynthesizedByQt, |
1407 | Qt::MouseEventSynthesizedByApplication}; |
1408 | |
1409 | const double startValue = 0.0; |
1410 | |
1411 | for (auto fraction : fractions) { |
1412 | for (auto up : directions) { |
1413 | |
1414 | const int units = (fraction ? 60 : 120) * (up ? 1 : -1); |
1415 | |
1416 | for (auto modifier : modifierList) { |
1417 | |
1418 | const Qt::KeyboardModifiers modifiers(modifier); |
1419 | |
1420 | const auto modifierName = modifierToName(modifier); |
1421 | if (modifierName.isEmpty()) |
1422 | continue; |
1423 | |
1424 | for (auto stepModifier : validStepModifierList) { |
1425 | |
1426 | const auto stepModifierName = modifierToName(modifier: stepModifier); |
1427 | if (stepModifierName.isEmpty()) |
1428 | continue; |
1429 | |
1430 | const int steps = (modifier & stepModifier ? 10 : 1) |
1431 | * (up ? 1 : -1); |
1432 | |
1433 | for (auto source : sources) { |
1434 | |
1435 | #ifdef Q_OS_MACOS |
1436 | QPoint angleDelta; |
1437 | if ((modifier & Qt::ShiftModifier) && |
1438 | source == Qt::MouseEventNotSynthesized) { |
1439 | // On macOS the Shift modifier converts vertical |
1440 | // mouse wheel events to horizontal. |
1441 | angleDelta = { units, 0 }; |
1442 | } else { |
1443 | // However, this is not the case for trackpad scroll |
1444 | // events. |
1445 | angleDelta = { 0, units }; |
1446 | } |
1447 | #else |
1448 | const QPoint angleDelta(0, units); |
1449 | #endif |
1450 | |
1451 | QLatin1String sourceName; |
1452 | switch (source) { |
1453 | case Qt::MouseEventNotSynthesized: |
1454 | sourceName = QLatin1String("NotSynthesized" ); |
1455 | break; |
1456 | case Qt::MouseEventSynthesizedBySystem: |
1457 | sourceName = QLatin1String("SynthesizedBySystem" ); |
1458 | break; |
1459 | case Qt::MouseEventSynthesizedByQt: |
1460 | sourceName = QLatin1String("SynthesizedByQt" ); |
1461 | break; |
1462 | case Qt::MouseEventSynthesizedByApplication: |
1463 | sourceName = QLatin1String("SynthesizedByApplication" ); |
1464 | break; |
1465 | default: |
1466 | qFatal(msg: "Unexpected wheel event source" ); |
1467 | continue; |
1468 | } |
1469 | |
1470 | DoubleList expectedValues; |
1471 | if (fraction) |
1472 | expectedValues << startValue; |
1473 | expectedValues << startValue + steps; |
1474 | |
1475 | QTest::addRow(format: "%s%s%sWith%sKeyboardModifier%s" , |
1476 | fraction ? "half" : "full" , |
1477 | up ? "Up" : "Down" , |
1478 | stepModifierName.latin1(), |
1479 | modifierName.latin1(), |
1480 | sourceName.latin1()) |
1481 | << angleDelta |
1482 | << static_cast<int>(stepModifier) |
1483 | << modifiers |
1484 | << source |
1485 | << startValue |
1486 | << expectedValues; |
1487 | } |
1488 | } |
1489 | } |
1490 | } |
1491 | } |
1492 | #else |
1493 | QSKIP("Built with --no-feature-wheelevent" ); |
1494 | #endif |
1495 | } |
1496 | |
1497 | void tst_QDoubleSpinBox::wheelEvents() |
1498 | { |
1499 | #if QT_CONFIG(wheelevent) |
1500 | QFETCH(QPoint, angleDelta); |
1501 | QFETCH(int, stepModifier); |
1502 | QFETCH(Qt::KeyboardModifiers, modifier); |
1503 | QFETCH(Qt::MouseEventSource, source); |
1504 | QFETCH(double, start); |
1505 | QFETCH(DoubleList, expectedValues); |
1506 | |
1507 | DoubleSpinBox spinBox; |
1508 | spinBox.setRange(min: -20, max: 20); |
1509 | spinBox.setValue(start); |
1510 | |
1511 | QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style( |
1512 | new StepModifierStyle); |
1513 | style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier); |
1514 | spinBox.setStyle(style.data()); |
1515 | |
1516 | QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, |
1517 | Qt::NoButton, modifier, Qt::NoScrollPhase, false, source); |
1518 | for (int expected : expectedValues) { |
1519 | qApp->sendEvent(receiver: &spinBox, event: &event); |
1520 | QCOMPARE(spinBox.value(), expected); |
1521 | } |
1522 | #else |
1523 | QSKIP("Built with --no-feature-wheelevent" ); |
1524 | #endif |
1525 | } |
1526 | |
1527 | void tst_QDoubleSpinBox::stepModifierKeys_data() |
1528 | { |
1529 | QTest::addColumn<double>(name: "startValue" ); |
1530 | QTest::addColumn<int>(name: "stepModifier" ); |
1531 | QTest::addColumn<QTestEventList>(name: "keys" ); |
1532 | QTest::addColumn<double>(name: "expectedValue" ); |
1533 | |
1534 | const auto keyList = {Qt::Key_Up, Qt::Key_Down}; |
1535 | |
1536 | const auto modifierList = {Qt::NoModifier, |
1537 | Qt::ShiftModifier, |
1538 | Qt::ControlModifier, |
1539 | Qt::AltModifier, |
1540 | Qt::MetaModifier}; |
1541 | |
1542 | const auto validStepModifierList = {Qt::NoModifier, |
1543 | Qt::ControlModifier, |
1544 | Qt::ShiftModifier}; |
1545 | |
1546 | |
1547 | for (auto key : keyList) { |
1548 | |
1549 | const bool up = key == Qt::Key_Up; |
1550 | Q_ASSERT(up || key == Qt::Key_Down); |
1551 | |
1552 | const double startValue = up ? 0.0 : 10.0; |
1553 | |
1554 | for (auto modifier : modifierList) { |
1555 | |
1556 | QTestEventList keys; |
1557 | keys.addKeyClick(qtKey: key, modifiers: modifier); |
1558 | |
1559 | const auto modifierName = modifierToName(modifier); |
1560 | if (modifierName.isEmpty()) |
1561 | continue; |
1562 | |
1563 | for (auto stepModifier : validStepModifierList) { |
1564 | |
1565 | const auto stepModifierName = modifierToName(modifier: stepModifier); |
1566 | if (stepModifierName.isEmpty()) |
1567 | continue; |
1568 | |
1569 | const int steps = (modifier & stepModifier ? 10 : 1) |
1570 | * (up ? 1 : -1); |
1571 | |
1572 | const double expectedValue = startValue + steps; |
1573 | |
1574 | QTest::addRow(format: "%s%sWith%sKeyboardModifier" , |
1575 | up ? "up" : "down" , |
1576 | stepModifierName.latin1(), |
1577 | modifierName.latin1()) |
1578 | << startValue |
1579 | << static_cast<int>(stepModifier) |
1580 | << keys |
1581 | << expectedValue; |
1582 | } |
1583 | } |
1584 | } |
1585 | } |
1586 | |
1587 | void tst_QDoubleSpinBox::stepModifierKeys() |
1588 | { |
1589 | QFETCH(double, startValue); |
1590 | QFETCH(int, stepModifier); |
1591 | QFETCH(QTestEventList, keys); |
1592 | QFETCH(double, expectedValue); |
1593 | |
1594 | QDoubleSpinBox spin(0); |
1595 | spin.setValue(startValue); |
1596 | |
1597 | QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style( |
1598 | new StepModifierStyle); |
1599 | style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier); |
1600 | spin.setStyle(style.data()); |
1601 | |
1602 | spin.show(); |
1603 | QVERIFY(QTest::qWaitForWindowActive(&spin)); |
1604 | |
1605 | QCOMPARE(spin.value(), startValue); |
1606 | keys.simulate(w: &spin); |
1607 | QCOMPARE(spin.value(), expectedValue); |
1608 | } |
1609 | |
1610 | void tst_QDoubleSpinBox::stepModifierButtons_data() |
1611 | { |
1612 | QTest::addColumn<QStyle::SubControl>(name: "subControl" ); |
1613 | QTest::addColumn<int>(name: "stepModifier" ); |
1614 | QTest::addColumn<Qt::KeyboardModifiers>(name: "modifiers" ); |
1615 | QTest::addColumn<double>(name: "startValue" ); |
1616 | QTest::addColumn<double>(name: "expectedValue" ); |
1617 | |
1618 | const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; |
1619 | |
1620 | const auto modifierList = {Qt::NoModifier, |
1621 | Qt::ShiftModifier, |
1622 | Qt::ControlModifier, |
1623 | Qt::AltModifier, |
1624 | Qt::MetaModifier}; |
1625 | |
1626 | const auto validStepModifierList = {Qt::NoModifier, |
1627 | Qt::ControlModifier, |
1628 | Qt::ShiftModifier}; |
1629 | |
1630 | for (auto subControl : subControls) { |
1631 | |
1632 | const bool up = subControl == QStyle::SC_SpinBoxUp; |
1633 | Q_ASSERT(up || subControl == QStyle::SC_SpinBoxDown); |
1634 | |
1635 | const double startValue = up ? 0 : 10; |
1636 | |
1637 | for (auto modifier : modifierList) { |
1638 | |
1639 | const Qt::KeyboardModifiers modifiers(modifier); |
1640 | |
1641 | const auto modifierName = modifierToName(modifier); |
1642 | if (modifierName.isEmpty()) |
1643 | continue; |
1644 | |
1645 | for (auto stepModifier : validStepModifierList) { |
1646 | |
1647 | const auto stepModifierName = modifierToName(modifier: stepModifier); |
1648 | if (stepModifierName.isEmpty()) |
1649 | continue; |
1650 | |
1651 | const int steps = (modifier & stepModifier ? 10 : 1) |
1652 | * (up ? 1 : -1); |
1653 | |
1654 | const double expectedValue = startValue + steps; |
1655 | |
1656 | QTest::addRow(format: "%s%sWith%sKeyboardModifier" , |
1657 | up ? "up" : "down" , |
1658 | stepModifierName.latin1(), |
1659 | modifierName.latin1()) |
1660 | << subControl |
1661 | << static_cast<int>(stepModifier) |
1662 | << modifiers |
1663 | << startValue |
1664 | << expectedValue; |
1665 | } |
1666 | } |
1667 | } |
1668 | } |
1669 | |
1670 | void tst_QDoubleSpinBox::stepModifierButtons() |
1671 | { |
1672 | QFETCH(QStyle::SubControl, subControl); |
1673 | QFETCH(int, stepModifier); |
1674 | QFETCH(Qt::KeyboardModifiers, modifiers); |
1675 | QFETCH(double, startValue); |
1676 | QFETCH(double, expectedValue); |
1677 | |
1678 | DoubleSpinBox spin(0); |
1679 | spin.setRange(min: -20, max: 20); |
1680 | spin.setValue(startValue); |
1681 | |
1682 | QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> style( |
1683 | new StepModifierStyle); |
1684 | style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier); |
1685 | spin.setStyle(style.data()); |
1686 | |
1687 | spin.show(); |
1688 | QVERIFY(QTest::qWaitForWindowActive(&spin)); |
1689 | |
1690 | QStyleOptionSpinBox spinBoxStyleOption; |
1691 | spin.initStyleOption(option: &spinBoxStyleOption); |
1692 | |
1693 | const QRect buttonRect = spin.style()->subControlRect( |
1694 | cc: QStyle::CC_SpinBox, opt: &spinBoxStyleOption, sc: subControl, widget: &spin); |
1695 | |
1696 | QCOMPARE(spin.value(), startValue); |
1697 | QTest::mouseClick(widget: &spin, button: Qt::LeftButton, stateKey: modifiers, pos: buttonRect.center()); |
1698 | QCOMPARE(spin.value(), expectedValue); |
1699 | } |
1700 | |
1701 | void tst_QDoubleSpinBox::stepModifierPressAndHold_data() |
1702 | { |
1703 | QTest::addColumn<QStyle::SubControl>(name: "subControl" ); |
1704 | QTest::addColumn<int>(name: "stepModifier" ); |
1705 | QTest::addColumn<Qt::KeyboardModifiers>(name: "modifiers" ); |
1706 | QTest::addColumn<int>(name: "expectedStepModifier" ); |
1707 | |
1708 | const auto subControls = {QStyle::SC_SpinBoxUp, QStyle::SC_SpinBoxDown}; |
1709 | |
1710 | const auto modifierList = {Qt::NoModifier, |
1711 | Qt::ShiftModifier, |
1712 | Qt::ControlModifier, |
1713 | Qt::AltModifier, |
1714 | Qt::MetaModifier}; |
1715 | |
1716 | const auto validStepModifierList = {Qt::NoModifier, |
1717 | Qt::ControlModifier, |
1718 | Qt::ShiftModifier}; |
1719 | |
1720 | for (auto subControl : subControls) { |
1721 | |
1722 | const bool up = subControl == QStyle::SC_SpinBoxUp; |
1723 | Q_ASSERT(up || subControl == QStyle::SC_SpinBoxDown); |
1724 | |
1725 | for (auto modifier : modifierList) { |
1726 | |
1727 | const Qt::KeyboardModifiers modifiers(modifier); |
1728 | |
1729 | const auto modifierName = modifierToName(modifier); |
1730 | if (modifierName.isEmpty()) |
1731 | continue; |
1732 | |
1733 | for (auto stepModifier : validStepModifierList) { |
1734 | |
1735 | const auto stepModifierName = modifierToName(modifier: stepModifier); |
1736 | if (stepModifierName.isEmpty()) |
1737 | continue; |
1738 | |
1739 | const int steps = (modifier & stepModifier ? 10 : 1) |
1740 | * (up ? 1 : -1); |
1741 | |
1742 | QTest::addRow(format: "%s%sWith%sKeyboardModifier" , |
1743 | up ? "up" : "down" , |
1744 | stepModifierName.latin1(), |
1745 | modifierName.latin1()) |
1746 | << subControl |
1747 | << static_cast<int>(stepModifier) |
1748 | << modifiers |
1749 | << steps; |
1750 | } |
1751 | } |
1752 | } |
1753 | } |
1754 | |
1755 | void tst_QDoubleSpinBox::stepModifierPressAndHold() |
1756 | { |
1757 | QFETCH(QStyle::SubControl, subControl); |
1758 | QFETCH(int, stepModifier); |
1759 | QFETCH(Qt::KeyboardModifiers, modifiers); |
1760 | QFETCH(int, expectedStepModifier); |
1761 | |
1762 | DoubleSpinBox spin(0); |
1763 | spin.setRange(min: -100.0, max: 100.0); |
1764 | spin.setValue(0.0); |
1765 | |
1766 | QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> stepModifierStyle( |
1767 | new StepModifierStyle(new PressAndHoldStyle)); |
1768 | stepModifierStyle->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier); |
1769 | spin.setStyle(stepModifierStyle.data()); |
1770 | |
1771 | QSignalSpy spy(&spin, QOverload<double>::of(ptr: &DoubleSpinBox::valueChanged)); |
1772 | |
1773 | spin.show(); |
1774 | QVERIFY(QTest::qWaitForWindowExposed(&spin)); |
1775 | |
1776 | QStyleOptionSpinBox spinBoxStyleOption; |
1777 | spin.initStyleOption(option: &spinBoxStyleOption); |
1778 | |
1779 | const QRect buttonRect = spin.style()->subControlRect( |
1780 | cc: QStyle::CC_SpinBox, opt: &spinBoxStyleOption, sc: subControl, widget: &spin); |
1781 | |
1782 | QTest::mousePress(widget: &spin, button: Qt::LeftButton, stateKey: modifiers, pos: buttonRect.center()); |
1783 | QTRY_VERIFY(spy.length() >= 3); |
1784 | QTest::mouseRelease(widget: &spin, button: Qt::LeftButton, stateKey: modifiers, pos: buttonRect.center()); |
1785 | |
1786 | const auto value = spy.last().at(i: 0); |
1787 | QVERIFY(value.type() == QVariant::Double); |
1788 | QCOMPARE(value.toDouble(), spy.length() * expectedStepModifier); |
1789 | } |
1790 | |
1791 | QTEST_MAIN(tst_QDoubleSpinBox) |
1792 | #include "tst_qdoublespinbox.moc" |
1793 | |