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 <QScrollBar> |
32 | #include <QStyleOptionSlider> |
33 | #include <QScrollArea> |
34 | #include <QScreen> |
35 | |
36 | #include <QtTest/private/qtesthelpers_p.h> |
37 | |
38 | using namespace QTestPrivate; |
39 | |
40 | class tst_QScrollBar : public QObject |
41 | { |
42 | Q_OBJECT |
43 | private slots: |
44 | void scrollSingleStep(); |
45 | void task_209492(); |
46 | #if QT_CONFIG(wheelevent) |
47 | void QTBUG_27308(); |
48 | #endif |
49 | void QTBUG_42871(); |
50 | }; |
51 | |
52 | class SingleStepTestScrollBar : public QScrollBar { |
53 | Q_OBJECT |
54 | public: |
55 | explicit SingleStepTestScrollBar(Qt::Orientation o, QWidget *parent = 0) : QScrollBar(o, parent) {} |
56 | |
57 | public slots: |
58 | void hideAndShow() |
59 | { |
60 | hide(); |
61 | show(); |
62 | } |
63 | }; |
64 | |
65 | // Check that the scrollbar doesn't scroll after calling hide and show |
66 | // from a slot connected to the scrollbar's actionTriggered signal. |
67 | void tst_QScrollBar::scrollSingleStep() |
68 | { |
69 | SingleStepTestScrollBar testWidget(Qt::Horizontal); |
70 | connect(sender: &testWidget, signal: &QAbstractSlider::actionTriggered, receiver: &testWidget, slot: &SingleStepTestScrollBar::hideAndShow); |
71 | testWidget.resize(w: 100, h: testWidget.height()); |
72 | centerOnScreen(w: &testWidget); |
73 | testWidget.show(); |
74 | QVERIFY(QTest::qWaitForWindowExposed(&testWidget)); |
75 | |
76 | testWidget.setValue(testWidget.minimum()); |
77 | QCOMPARE(testWidget.value(), testWidget.minimum()); |
78 | |
79 | // Get rect for the area to click on |
80 | const QStyleOptionSlider opt = qt_qscrollbarStyleOption(scrollBar: &testWidget); |
81 | QRect sr = testWidget.style()->subControlRect(cc: QStyle::CC_ScrollBar, opt: &opt, |
82 | sc: QStyle::SC_ScrollBarAddLine, widget: &testWidget); |
83 | |
84 | if (!sr.isValid()) |
85 | QSKIP("SC_ScrollBarAddLine not valid" ); |
86 | |
87 | QTest::mouseClick(widget: &testWidget, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(sr.x(), sr.y())); |
88 | QTest::qWait(ms: 510); // initial delay is 500 for setRepeatAction |
89 | disconnect(sender: &testWidget, signal: &QAbstractSlider::actionTriggered, receiver: &testWidget, slot: &SingleStepTestScrollBar::hideAndShow); |
90 | #ifdef Q_OS_MAC |
91 | QEXPECT_FAIL("" , "This test fails on OS X, see QTBUG-25272" , Abort); |
92 | #endif |
93 | QCOMPARE(testWidget.value(), testWidget.singleStep()); |
94 | } |
95 | |
96 | void tst_QScrollBar::task_209492() |
97 | { |
98 | class MyScrollArea : public QScrollArea |
99 | { |
100 | public: |
101 | int scrollCount; |
102 | MyScrollArea(QWidget *parent = 0) : QScrollArea(parent), scrollCount(0) {} |
103 | protected: |
104 | void paintEvent(QPaintEvent *) { QTest::qSleep(ms: 600); } |
105 | void scrollContentsBy(int, int) { ++scrollCount; viewport()->update(); } |
106 | }; |
107 | |
108 | MyScrollArea scrollArea; |
109 | QScrollBar *verticalScrollBar = scrollArea.verticalScrollBar(); |
110 | verticalScrollBar->setRange(min: 0, max: 1000); |
111 | centerOnScreen(w: &scrollArea); |
112 | scrollArea.show(); |
113 | QVERIFY(QTest::qWaitForWindowExposed(&scrollArea)); |
114 | |
115 | QSignalSpy spy(verticalScrollBar, SIGNAL(actionTriggered(int))); |
116 | QCOMPARE(scrollArea.scrollCount, 0); |
117 | QCOMPARE(spy.count(), 0); |
118 | |
119 | // Simulate a mouse click on the "scroll down button". |
120 | const QPoint pressPoint(verticalScrollBar->width() / 2, verticalScrollBar->height() - 10); |
121 | const QPoint globalPressPoint = verticalScrollBar->mapToGlobal(globalPressPoint); |
122 | QMouseEvent mousePressEvent(QEvent::MouseButtonPress, pressPoint, globalPressPoint, |
123 | Qt::LeftButton, Qt::LeftButton, {}); |
124 | QApplication::sendEvent(receiver: verticalScrollBar, event: &mousePressEvent); |
125 | QTest::qWait(ms: 1); |
126 | QMouseEvent mouseReleaseEvent(QEvent::MouseButtonRelease, pressPoint, globalPressPoint, |
127 | Qt::LeftButton, Qt::LeftButton, {}); |
128 | QApplication::sendEvent(receiver: verticalScrollBar, event: &mouseReleaseEvent); |
129 | |
130 | // Check that the action was triggered once. |
131 | |
132 | #ifdef Q_OS_MAC |
133 | QSKIP("The result depends on system setting and is not relevant on Mac" ); |
134 | #endif |
135 | QCOMPARE(scrollArea.scrollCount, 1); |
136 | QCOMPARE(spy.count(), 1); |
137 | } |
138 | |
139 | #if QT_CONFIG(wheelevent) |
140 | #define WHEEL_DELTA 120 // copied from tst_QAbstractSlider / tst_QComboBox |
141 | void tst_QScrollBar::QTBUG_27308() |
142 | { |
143 | // QTBUG-27308 |
144 | // Check that a disabled scrollbar doesn't react on wheel events anymore |
145 | |
146 | QScrollBar testWidget(Qt::Horizontal); |
147 | testWidget.resize(w: 100, h: testWidget.height()); |
148 | centerOnScreen(w: &testWidget); |
149 | testWidget.show(); |
150 | QVERIFY(QTest::qWaitForWindowExposed(&testWidget)); |
151 | |
152 | testWidget.setValue(testWidget.minimum()); |
153 | testWidget.setEnabled(false); |
154 | const QPoint wheelPoint = testWidget.rect().center(); |
155 | const QPoint angleDelta(testWidget.orientation() == Qt::Horizontal ? -WHEEL_DELTA : 0, |
156 | testWidget.orientation() == Qt::Vertical ? -WHEEL_DELTA : 0); |
157 | QWheelEvent event(wheelPoint, testWidget.mapToGlobal(wheelPoint), QPoint(), angleDelta, |
158 | Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); |
159 | qApp->sendEvent(receiver: &testWidget, event: &event); |
160 | QCOMPARE(testWidget.value(), testWidget.minimum()); |
161 | } |
162 | #endif |
163 | |
164 | class QTBUG_42871_Handler : public QObject { |
165 | Q_OBJECT |
166 | public: |
167 | int updatesCount; |
168 | QTBUG_42871_Handler() : QObject(), updatesCount(0) {} |
169 | public slots: |
170 | void valueUpdated(int) { ++updatesCount; QTest::qSleep(ms: 600); } |
171 | }; |
172 | |
173 | void tst_QScrollBar::QTBUG_42871() |
174 | { |
175 | QTBUG_42871_Handler myHandler; |
176 | QScrollBar scrollBarWidget(Qt::Vertical); |
177 | bool connection = connect(sender: &scrollBarWidget, SIGNAL(valueChanged(int)), receiver: &myHandler, SLOT(valueUpdated(int))); |
178 | QVERIFY(connection); |
179 | scrollBarWidget.resize(w: 100, h: scrollBarWidget.height()); |
180 | centerOnScreen(w: &scrollBarWidget); |
181 | scrollBarWidget.show(); |
182 | QVERIFY(QTest::qWaitForWindowExposed(&scrollBarWidget)); |
183 | QSignalSpy spy(&scrollBarWidget, SIGNAL(actionTriggered(int))); |
184 | QVERIFY(spy.isValid()); |
185 | QCOMPARE(myHandler.updatesCount, 0); |
186 | QCOMPARE(spy.count(), 0); |
187 | |
188 | // Simulate a mouse click on the "scroll down button". |
189 | const QPoint pressPoint(scrollBarWidget.width() / 2, scrollBarWidget.height() - 10); |
190 | const QPoint globalPressPoint = scrollBarWidget.mapToGlobal(pressPoint); |
191 | QMouseEvent mousePressEvent(QEvent::MouseButtonPress, pressPoint, globalPressPoint, |
192 | Qt::LeftButton, Qt::LeftButton, {}); |
193 | QApplication::sendEvent(receiver: &scrollBarWidget, event: &mousePressEvent); |
194 | QTest::qWait(ms: 1); |
195 | QMouseEvent mouseReleaseEvent(QEvent::MouseButtonRelease, pressPoint, globalPressPoint, |
196 | Qt::LeftButton, Qt::LeftButton, {}); |
197 | QApplication::sendEvent(receiver: &scrollBarWidget, event: &mouseReleaseEvent); |
198 | // Check that the action was triggered once. |
199 | QCOMPARE(myHandler.updatesCount, 1); |
200 | QCOMPARE(spy.count(), 1); |
201 | } |
202 | |
203 | QTEST_MAIN(tst_QScrollBar) |
204 | #include "tst_qscrollbar.moc" |
205 | |