1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
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 http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include <QtTest> |
38 | #include <QtQuick> |
39 | |
40 | class tst_PressAndHold : public QObject |
41 | { |
42 | Q_OBJECT |
43 | |
44 | private slots: |
45 | void initTestCase(); |
46 | void cleanupTestCase(); |
47 | |
48 | void pressAndHold_data(); |
49 | void pressAndHold(); |
50 | |
51 | void keepSelection_data(); |
52 | void keepSelection(); |
53 | }; |
54 | |
55 | void tst_PressAndHold::initTestCase() |
56 | { |
57 | QGuiApplication::styleHints()->setMousePressAndHoldInterval(100); |
58 | } |
59 | |
60 | void tst_PressAndHold::cleanupTestCase() |
61 | { |
62 | QGuiApplication::styleHints()->setMousePressAndHoldInterval(-1); |
63 | } |
64 | |
65 | void tst_PressAndHold::pressAndHold_data() |
66 | { |
67 | QTest::addColumn<QByteArray>(name: "data" ); |
68 | QTest::addColumn<QByteArray>(name: "signal" ); |
69 | |
70 | QTest::newRow(dataTag: "Button" ) << QByteArray("import QtQuick.Controls 2.1; Button { text: 'Button' }" ) << QByteArray(SIGNAL(pressAndHold())); |
71 | QTest::newRow(dataTag: "SwipeDelegate" ) << QByteArray("import QtQuick.Controls 2.1; SwipeDelegate { text: 'SwipeDelegate' }" ) << QByteArray(SIGNAL(pressAndHold())); |
72 | QTest::newRow(dataTag: "TextField" ) << QByteArray("import QtQuick.Controls 2.1; TextField { text: 'TextField' }" ) << QByteArray(SIGNAL(pressAndHold(QQuickMouseEvent*))); |
73 | QTest::newRow(dataTag: "TextArea" ) << QByteArray("import QtQuick.Controls 2.1; TextArea { text: 'TextArea' }" ) << QByteArray(SIGNAL(pressAndHold(QQuickMouseEvent*))); |
74 | } |
75 | |
76 | void tst_PressAndHold::pressAndHold() |
77 | { |
78 | QFETCH(QByteArray, data); |
79 | QFETCH(QByteArray, signal); |
80 | |
81 | QQmlEngine engine; |
82 | QQmlComponent component(&engine); |
83 | component.setData(data, baseUrl: QUrl()); |
84 | |
85 | QScopedPointer<QObject> control(component.create()); |
86 | QScopedPointer<QObject> waitControl(component.create()); |
87 | QVERIFY(!control.isNull() && !waitControl.isNull()); |
88 | |
89 | QSignalSpy spy(control.data(), signal); |
90 | QSignalSpy waitSpy(waitControl.data(), signal); |
91 | QVERIFY(spy.isValid() && waitSpy.isValid()); |
92 | |
93 | int startDragDistance = QGuiApplication::styleHints()->startDragDistance(); |
94 | QMouseEvent press(QEvent::MouseButtonPress, QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); |
95 | QMouseEvent press2(QEvent::MouseButtonPress, QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier); |
96 | QMouseEvent move(QEvent::MouseMove, QPointF(2 * startDragDistance, 2 * startDragDistance), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); |
97 | QMouseEvent release(QEvent::MouseButtonRelease, QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); |
98 | |
99 | // pressAndHold() emitted |
100 | QGuiApplication::sendEvent(receiver: control.data(), event: &press); |
101 | QTRY_COMPARE(spy.count(), 1); |
102 | QGuiApplication::sendEvent(receiver: control.data(), event: &release); |
103 | QCOMPARE(spy.count(), 1); |
104 | spy.clear(); |
105 | |
106 | // pressAndHold() canceled by release |
107 | QGuiApplication::sendEvent(receiver: control.data(), event: &press); |
108 | QGuiApplication::processEvents(); |
109 | QGuiApplication::sendEvent(receiver: control.data(), event: &release); |
110 | QCOMPARE(spy.count(), 0); |
111 | |
112 | // pressAndHold() canceled by move |
113 | QGuiApplication::sendEvent(receiver: control.data(), event: &press); |
114 | QGuiApplication::sendEvent(receiver: control.data(), event: &move); // cancels pressAndHold() |
115 | QGuiApplication::sendEvent(receiver: waitControl.data(), event: &press); |
116 | // by the time the second control emits pressAndHold(), we can reliably |
117 | // assume that the first control would have emitted pressAndHold() if it |
118 | // wasn't canceled as appropriate by the move event above |
119 | QTRY_COMPARE(waitSpy.count(), 1); |
120 | QCOMPARE(spy.count(), 0); |
121 | QGuiApplication::sendEvent(receiver: control.data(), event: &release); |
122 | QGuiApplication::sendEvent(receiver: waitControl.data(), event: &release); |
123 | QCOMPARE(waitSpy.count(), 1); |
124 | QCOMPARE(spy.count(), 0); |
125 | waitSpy.clear(); |
126 | |
127 | // pressAndHold() canceled by 2nd press |
128 | QGuiApplication::sendEvent(receiver: control.data(), event: &press); |
129 | QGuiApplication::sendEvent(receiver: control.data(), event: &press2); // cancels pressAndHold() |
130 | QGuiApplication::sendEvent(receiver: waitControl.data(), event: &press); |
131 | // by the time the second control emits pressAndHold(), we can reliably |
132 | // assume that the first control would have emitted pressAndHold() if it |
133 | // wasn't canceled as appropriate by the 2nd press event above |
134 | QTRY_COMPARE(waitSpy.count(), 1); |
135 | QCOMPARE(spy.count(), 0); |
136 | QGuiApplication::sendEvent(receiver: control.data(), event: &release); |
137 | QGuiApplication::sendEvent(receiver: waitControl.data(), event: &release); |
138 | QCOMPARE(waitSpy.count(), 1); |
139 | QCOMPARE(spy.count(), 0); |
140 | waitSpy.clear(); |
141 | } |
142 | |
143 | void tst_PressAndHold::keepSelection_data() |
144 | { |
145 | QTest::addColumn<QByteArray>(name: "data" ); |
146 | |
147 | QTest::newRow(dataTag: "TextField" ) << QByteArray("import QtQuick.Controls 2.1; TextField { text: 'TextField' }" ); |
148 | QTest::newRow(dataTag: "TextArea" ) << QByteArray("import QtQuick.Controls 2.1; TextArea { text: 'TextArea' }" ); |
149 | } |
150 | |
151 | void tst_PressAndHold::keepSelection() |
152 | { |
153 | QFETCH(QByteArray, data); |
154 | |
155 | QQmlEngine engine; |
156 | QQmlComponent component(&engine); |
157 | component.setData(data, baseUrl: QUrl()); |
158 | |
159 | QScopedPointer<QObject> control(component.create()); |
160 | QScopedPointer<QObject> waitControl(component.create()); |
161 | QVERIFY(!control.isNull() && !waitControl.isNull()); |
162 | |
163 | QSignalSpy spy(control.data(), SIGNAL(pressAndHold(QQuickMouseEvent*))); |
164 | QSignalSpy waitSpy(waitControl.data(), SIGNAL(pressAndHold(QQuickMouseEvent*))); |
165 | QVERIFY(spy.isValid() && waitSpy.isValid()); |
166 | |
167 | QMouseEvent press(QEvent::MouseButtonPress, QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); |
168 | QMouseEvent press2(QEvent::MouseButtonPress, QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier); |
169 | QMouseEvent release(QEvent::MouseButtonRelease, QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); |
170 | |
171 | QVERIFY(!control->property("text" ).toString().isEmpty()); |
172 | QVERIFY(QMetaObject::invokeMethod(control.data(), "selectAll" )); |
173 | QCOMPARE(control->property("selectedText" ), control->property("text" )); |
174 | |
175 | // pressAndHold() emitted => selection remains |
176 | QGuiApplication::sendEvent(receiver: control.data(), event: &press); |
177 | QTRY_COMPARE(spy.count(), 1); |
178 | QGuiApplication::sendEvent(receiver: control.data(), event: &release); |
179 | QCOMPARE(spy.count(), 1); |
180 | QCOMPARE(control->property("selectedText" ), control->property("text" )); |
181 | spy.clear(); |
182 | |
183 | // pressAndHold() canceled by release => selection cleared |
184 | QGuiApplication::sendEvent(receiver: control.data(), event: &press); |
185 | QGuiApplication::processEvents(); |
186 | QGuiApplication::sendEvent(receiver: control.data(), event: &release); |
187 | QCOMPARE(spy.count(), 0); |
188 | QVERIFY(control->property("selectedText" ).toString().isEmpty()); |
189 | |
190 | QVERIFY(QMetaObject::invokeMethod(control.data(), "selectAll" )); |
191 | QCOMPARE(control->property("selectedText" ), control->property("text" )); |
192 | |
193 | // pressAndHold() canceled by 2nd press => selection cleared |
194 | QGuiApplication::sendEvent(receiver: control.data(), event: &press); |
195 | QGuiApplication::sendEvent(receiver: control.data(), event: &press2); // cancels pressAndHold() |
196 | QGuiApplication::sendEvent(receiver: waitControl.data(), event: &press); |
197 | // by the time the second control emits pressAndHold(), we can reliably |
198 | // assume that the first control would have emitted pressAndHold() if it |
199 | // wasn't canceled as appropriate by the move event above |
200 | QTRY_COMPARE(waitSpy.count(), 1); |
201 | QCOMPARE(spy.count(), 0); |
202 | QGuiApplication::sendEvent(receiver: control.data(), event: &release); |
203 | QGuiApplication::sendEvent(receiver: waitControl.data(), event: &release); |
204 | QCOMPARE(waitSpy.count(), 1); |
205 | QCOMPARE(spy.count(), 0); |
206 | QVERIFY(control->property("selectedText" ).toString().isEmpty()); |
207 | waitSpy.clear(); |
208 | } |
209 | |
210 | QTEST_MAIN(tst_PressAndHold) |
211 | |
212 | #include "tst_pressandhold.moc" |
213 | |