| 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 <qtest.h> |
| 38 | #include <QtTest/QSignalSpy> |
| 39 | #include <QtQml/qqmlengine.h> |
| 40 | #include <QtQml/qqmlcomponent.h> |
| 41 | #include <QtQml/qqmlcontext.h> |
| 42 | #include <QtQuick/qquickview.h> |
| 43 | #include <QtQuick/private/qquickitem_p.h> |
| 44 | #include <QtQuickTemplates2/private/qquickcontrol_p.h> |
| 45 | #include <QtGui/private/qguiapplication_p.h> |
| 46 | #include <QtGui/qstylehints.h> |
| 47 | #include <QtGui/qtouchdevice.h> |
| 48 | #include "../shared/util.h" |
| 49 | #include "../shared/visualtestutil.h" |
| 50 | |
| 51 | using namespace QQuickVisualTestUtil; |
| 52 | |
| 53 | class tst_focus : public QQmlDataTest |
| 54 | { |
| 55 | Q_OBJECT |
| 56 | |
| 57 | private slots: |
| 58 | void initTestCase(); |
| 59 | |
| 60 | void navigation_data(); |
| 61 | void navigation(); |
| 62 | |
| 63 | void policy_data(); |
| 64 | void policy(); |
| 65 | |
| 66 | void reason_data(); |
| 67 | void reason(); |
| 68 | |
| 69 | void visualFocus(); |
| 70 | |
| 71 | void scope_data(); |
| 72 | void scope(); |
| 73 | }; |
| 74 | |
| 75 | void tst_focus::initTestCase() |
| 76 | { |
| 77 | QQmlDataTest::initTestCase(); |
| 78 | } |
| 79 | |
| 80 | void tst_focus::navigation_data() |
| 81 | { |
| 82 | QTest::addColumn<Qt::Key>(name: "key" ); |
| 83 | QTest::addColumn<QString>(name: "testFile" ); |
| 84 | QTest::addColumn<Qt::TabFocusBehavior>(name: "behavior" ); |
| 85 | QTest::addColumn<QStringList>(name: "order" ); |
| 86 | |
| 87 | QTest::newRow(dataTag: "tab-all-controls" ) << Qt::Key_Tab << QString("activeFocusOnTab.qml" ) << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "rangeslider.first" << "rangeslider.second" << "slider" << "spinbox" << "switch" << "tabbutton1" << "tabbutton2" << "textfield" << "toolbutton" << "textarea" << "button1" ); |
| 88 | QTest::newRow(dataTag: "backtab-all-controls" ) << Qt::Key_Backtab << QString("activeFocusOnTab.qml" ) << Qt::TabFocusAllControls << (QStringList() << "textarea" << "toolbutton" << "textfield" << "tabbutton2" << "tabbutton1" << "switch" << "spinbox" << "slider" << "rangeslider.second" << "rangeslider.first" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1" ); |
| 89 | |
| 90 | QTest::newRow(dataTag: "tab-text-controls" ) << Qt::Key_Tab << QString("activeFocusOnTab.qml" ) << Qt::TabFocusTextControls << (QStringList() << "spinbox" << "textfield" << "textarea" ); |
| 91 | QTest::newRow(dataTag: "backtab-text-controls" ) << Qt::Key_Backtab << QString("activeFocusOnTab.qml" ) << Qt::TabFocusTextControls << (QStringList() << "textarea" << "textfield" << "spinbox" ); |
| 92 | |
| 93 | QTest::newRow(dataTag: "key-up" ) << Qt::Key_Up << QString("keyNavigation.qml" ) << Qt::TabFocusAllControls << (QStringList() << "textarea" << "toolbutton" << "textfield" << "tabbutton2" << "tabbutton1" << "switch" << "slider" << "rangeslider.first" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1" ); |
| 94 | QTest::newRow(dataTag: "key-down" ) << Qt::Key_Down << QString("keyNavigation.qml" ) << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "rangeslider.first" << "slider" << "switch" << "tabbutton1" << "tabbutton2" << "textfield" << "toolbutton" << "textarea" << "button1" ); |
| 95 | QTest::newRow(dataTag: "key-left" ) << Qt::Key_Left << QString("keyNavigation.qml" ) << Qt::TabFocusAllControls << (QStringList() << "toolbutton" << "tabbutton2" << "tabbutton1" << "switch" << "spinbox" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1" ); |
| 96 | QTest::newRow(dataTag: "key-right" ) << Qt::Key_Right << QString("keyNavigation.qml" ) << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "spinbox" << "switch" << "tabbutton1" << "tabbutton2" << "toolbutton" << "button1" ); |
| 97 | } |
| 98 | |
| 99 | void tst_focus::navigation() |
| 100 | { |
| 101 | QFETCH(Qt::Key, key); |
| 102 | QFETCH(QString, testFile); |
| 103 | QFETCH(Qt::TabFocusBehavior, behavior); |
| 104 | QFETCH(QStringList, order); |
| 105 | |
| 106 | QGuiApplication::styleHints()->setTabFocusBehavior(behavior); |
| 107 | |
| 108 | QQuickView view; |
| 109 | view.contentItem()->setObjectName("contentItem" ); |
| 110 | |
| 111 | view.setSource(testFileUrl(fileName: testFile)); |
| 112 | view.show(); |
| 113 | view.requestActivate(); |
| 114 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
| 115 | QVERIFY(QGuiApplication::focusWindow() == &view); |
| 116 | |
| 117 | for (const QString &name : qAsConst(t&: order)) { |
| 118 | QKeyEvent event(QEvent::KeyPress, key, Qt::NoModifier); |
| 119 | QGuiApplication::sendEvent(receiver: &view, event: &event); |
| 120 | QVERIFY(event.isAccepted()); |
| 121 | |
| 122 | QQuickItem *item = findItem<QQuickItem>(parent: view.rootObject(), objectName: name); |
| 123 | QVERIFY2(item, qPrintable(name)); |
| 124 | QVERIFY2(item->hasActiveFocus(), qPrintable(QString("expected: '%1', actual: '%2'" ).arg(name).arg(view.activeFocusItem() ? view.activeFocusItem()->objectName() : "null" ))); |
| 125 | } |
| 126 | |
| 127 | QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1)); |
| 128 | } |
| 129 | |
| 130 | void tst_focus::policy_data() |
| 131 | { |
| 132 | QTest::addColumn<QString>(name: "name" ); |
| 133 | |
| 134 | QTest::newRow(dataTag: "Control" ) << "Control" ; |
| 135 | QTest::newRow(dataTag: "ComboBox" ) << "ComboBox" ; |
| 136 | QTest::newRow(dataTag: "Button" ) << "Button" ; |
| 137 | QTest::newRow(dataTag: "Slider" ) << "Slider" ; |
| 138 | QTest::newRow(dataTag: "ScrollBar" ) << "ScrollBar" ; |
| 139 | } |
| 140 | |
| 141 | void tst_focus::policy() |
| 142 | { |
| 143 | QFETCH(QString, name); |
| 144 | |
| 145 | QQmlEngine engine; |
| 146 | QQmlComponent component(&engine); |
| 147 | component.setData(QString("import QtQuick.Controls 2.1; ApplicationWindow { width: 100; height: 100; %1 { anchors.fill: parent } }" ).arg(a: name).toUtf8(), baseUrl: QUrl()); |
| 148 | |
| 149 | QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(object: component.create())); |
| 150 | QVERIFY(window); |
| 151 | |
| 152 | QQuickControl *control = qobject_cast<QQuickControl *>(object: window->contentItem()->childItems().first()); |
| 153 | QVERIFY(control); |
| 154 | |
| 155 | QVERIFY(!control->hasActiveFocus()); |
| 156 | QVERIFY(!control->hasVisualFocus()); |
| 157 | |
| 158 | window->show(); |
| 159 | window->requestActivate(); |
| 160 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| 161 | |
| 162 | struct TouchDeviceDeleter |
| 163 | { |
| 164 | static inline void cleanup(QTouchDevice *device) |
| 165 | { |
| 166 | QWindowSystemInterface::unregisterTouchDevice(device); |
| 167 | delete device; |
| 168 | } |
| 169 | }; |
| 170 | |
| 171 | QScopedPointer<QTouchDevice, TouchDeviceDeleter> device(new QTouchDevice); |
| 172 | device->setType(QTouchDevice::TouchScreen); |
| 173 | QWindowSystemInterface::registerTouchDevice(device: device.data()); |
| 174 | |
| 175 | control->setFocusPolicy(Qt::NoFocus); |
| 176 | QCOMPARE(control->focusPolicy(), Qt::NoFocus); |
| 177 | |
| 178 | // Qt::TabFocus vs. QQuickItem::activeFocusOnTab |
| 179 | control->setActiveFocusOnTab(true); |
| 180 | QCOMPARE(control->focusPolicy(), Qt::TabFocus); |
| 181 | control->setActiveFocusOnTab(false); |
| 182 | QCOMPARE(control->focusPolicy(), Qt::NoFocus); |
| 183 | |
| 184 | control->setFocusPolicy(Qt::TabFocus); |
| 185 | QCOMPARE(control->focusPolicy(), Qt::TabFocus); |
| 186 | QCOMPARE(control->activeFocusOnTab(), true); |
| 187 | |
| 188 | // Qt::TabFocus |
| 189 | QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusAllControls); |
| 190 | QTest::keyClick(window: window.data(), key: Qt::Key_Tab); |
| 191 | QVERIFY(control->hasActiveFocus()); |
| 192 | QVERIFY(control->hasVisualFocus()); |
| 193 | QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1)); |
| 194 | |
| 195 | // reset |
| 196 | control->setFocus(false); |
| 197 | QVERIFY(!control->hasActiveFocus()); |
| 198 | |
| 199 | // Qt::ClickFocus (mouse) |
| 200 | control->setFocusPolicy(Qt::NoFocus); |
| 201 | control->setAcceptedMouseButtons(Qt::LeftButton); |
| 202 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(control->width() / 2, control->height() / 2)); |
| 203 | QVERIFY(!control->hasActiveFocus()); |
| 204 | QVERIFY(!control->hasVisualFocus()); |
| 205 | |
| 206 | control->setFocusPolicy(Qt::ClickFocus); |
| 207 | QCOMPARE(control->focusPolicy(), Qt::ClickFocus); |
| 208 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(control->width() / 2, control->height() / 2)); |
| 209 | QVERIFY(control->hasActiveFocus()); |
| 210 | QVERIFY(!control->hasVisualFocus()); |
| 211 | |
| 212 | // reset |
| 213 | control->setFocus(false); |
| 214 | QVERIFY(!control->hasActiveFocus()); |
| 215 | |
| 216 | // Qt::ClickFocus (touch) |
| 217 | control->setFocusPolicy(Qt::NoFocus); |
| 218 | QTest::touchEvent(window: window.data(), device: device.data()).press(touchId: 0, pt: QPoint(control->width() / 2, control->height() / 2)); |
| 219 | QTest::touchEvent(window: window.data(), device: device.data()).release(touchId: 0, pt: QPoint(control->width() / 2, control->height() / 2)); |
| 220 | QVERIFY(!control->hasActiveFocus()); |
| 221 | QVERIFY(!control->hasVisualFocus()); |
| 222 | |
| 223 | control->setFocusPolicy(Qt::ClickFocus); |
| 224 | QCOMPARE(control->focusPolicy(), Qt::ClickFocus); |
| 225 | QTest::touchEvent(window: window.data(), device: device.data()).press(touchId: 0, pt: QPoint(control->width() / 2, control->height() / 2)); |
| 226 | QTest::touchEvent(window: window.data(), device: device.data()).release(touchId: 0, pt: QPoint(control->width() / 2, control->height() / 2)); |
| 227 | QVERIFY(control->hasActiveFocus()); |
| 228 | QVERIFY(!control->hasVisualFocus()); |
| 229 | |
| 230 | // reset |
| 231 | control->setFocus(false); |
| 232 | QVERIFY(!control->hasActiveFocus()); |
| 233 | |
| 234 | // Qt::WheelFocus |
| 235 | QWheelEvent wheelEvent(QPoint(control->width() / 2, control->height() / 2), 10, Qt::NoButton, Qt::NoModifier); |
| 236 | QGuiApplication::sendEvent(receiver: control, event: &wheelEvent); |
| 237 | QVERIFY(!control->hasActiveFocus()); |
| 238 | QVERIFY(!control->hasVisualFocus()); |
| 239 | |
| 240 | control->setFocusPolicy(Qt::WheelFocus); |
| 241 | QCOMPARE(control->focusPolicy(), Qt::WheelFocus); |
| 242 | |
| 243 | QGuiApplication::sendEvent(receiver: control, event: &wheelEvent); |
| 244 | QVERIFY(control->hasActiveFocus()); |
| 245 | QVERIFY(!control->hasVisualFocus()); |
| 246 | } |
| 247 | |
| 248 | void tst_focus::reason_data() |
| 249 | { |
| 250 | QTest::addColumn<QString>(name: "name" ); |
| 251 | |
| 252 | QTest::newRow(dataTag: "Control" ) << "Control" ; |
| 253 | QTest::newRow(dataTag: "TextField" ) << "TextField" ; |
| 254 | QTest::newRow(dataTag: "TextArea" ) << "TextArea" ; |
| 255 | QTest::newRow(dataTag: "SpinBox" ) << "SpinBox" ; |
| 256 | QTest::newRow(dataTag: "ComboBox" ) << "ComboBox" ; |
| 257 | } |
| 258 | |
| 259 | void tst_focus::reason() |
| 260 | { |
| 261 | QFETCH(QString, name); |
| 262 | |
| 263 | QQmlEngine engine; |
| 264 | QQmlComponent component(&engine); |
| 265 | component.setData(QString("import QtQuick.Controls 2.1; ApplicationWindow { width: 100; height: 100; %1 { anchors.fill: parent } }" ).arg(a: name).toUtf8(), baseUrl: QUrl()); |
| 266 | |
| 267 | QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(object: component.create())); |
| 268 | QVERIFY(window.data()); |
| 269 | |
| 270 | QQuickItem *control = window->contentItem()->childItems().first(); |
| 271 | QVERIFY(control); |
| 272 | |
| 273 | window->show(); |
| 274 | window->requestActivate(); |
| 275 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| 276 | |
| 277 | QCOMPARE(control->property("focusReason" ).toInt(), int(Qt::OtherFocusReason)); |
| 278 | control->forceActiveFocus(reason: Qt::MouseFocusReason); |
| 279 | QVERIFY(control->hasActiveFocus()); |
| 280 | QCOMPARE(control->property("focusReason" ).toInt(), int(Qt::MouseFocusReason)); |
| 281 | |
| 282 | QEXPECT_FAIL("TextArea" , "TODO: TextArea::visualFocus?" , Continue); |
| 283 | QEXPECT_FAIL("TextField" , "TODO: TextField::visualFocus?" , Continue); |
| 284 | QCOMPARE(control->property("visualFocus" ), QVariant(false)); |
| 285 | |
| 286 | window->contentItem()->setFocus(focus: false, reason: Qt::TabFocusReason); |
| 287 | QVERIFY(!control->hasActiveFocus()); |
| 288 | QCOMPARE(control->property("focusReason" ).toInt(), int(Qt::TabFocusReason)); |
| 289 | |
| 290 | QEXPECT_FAIL("TextArea" , "" , Continue); |
| 291 | QEXPECT_FAIL("TextField" , "" , Continue); |
| 292 | QCOMPARE(control->property("visualFocus" ), QVariant(false)); |
| 293 | |
| 294 | control->forceActiveFocus(reason: Qt::TabFocusReason); |
| 295 | QVERIFY(control->hasActiveFocus()); |
| 296 | QCOMPARE(control->property("focusReason" ).toInt(), int(Qt::TabFocusReason)); |
| 297 | |
| 298 | QEXPECT_FAIL("TextArea" , "" , Continue); |
| 299 | QEXPECT_FAIL("TextField" , "" , Continue); |
| 300 | QCOMPARE(control->property("visualFocus" ), QVariant(true)); |
| 301 | } |
| 302 | |
| 303 | void tst_focus::visualFocus() |
| 304 | { |
| 305 | QQuickView view; |
| 306 | view.setSource(testFileUrl(fileName: "visualFocus.qml" )); |
| 307 | view.show(); |
| 308 | view.requestActivate(); |
| 309 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
| 310 | |
| 311 | QQuickItem *column = view.rootObject(); |
| 312 | QVERIFY(column); |
| 313 | QCOMPARE(column->childItems().count(), 2); |
| 314 | |
| 315 | QQuickControl *button = qobject_cast<QQuickControl *>(object: column->childItems().first()); |
| 316 | QVERIFY(button); |
| 317 | |
| 318 | QQuickItem *textfield = column->childItems().last(); |
| 319 | QVERIFY(textfield); |
| 320 | |
| 321 | button->forceActiveFocus(reason: Qt::TabFocusReason); |
| 322 | QVERIFY(button->hasActiveFocus()); |
| 323 | QVERIFY(button->hasVisualFocus()); |
| 324 | QVERIFY(button->property("showFocus" ).toBool()); |
| 325 | |
| 326 | QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(textfield->x() + textfield->width() / 2, textfield->y() + textfield->height() / 2)); |
| 327 | QVERIFY(!button->hasActiveFocus()); |
| 328 | QVERIFY(!button->hasVisualFocus()); |
| 329 | QVERIFY(!button->property("showFocus" ).toBool()); |
| 330 | } |
| 331 | |
| 332 | void tst_focus::scope_data() |
| 333 | { |
| 334 | QTest::addColumn<QString>(name: "name" ); |
| 335 | |
| 336 | QTest::newRow(dataTag: "Frame" ) << "Frame" ; |
| 337 | QTest::newRow(dataTag: "GroupBox" ) << "Frame" ; |
| 338 | QTest::newRow(dataTag: "Page" ) << "Page" ; |
| 339 | QTest::newRow(dataTag: "Pane" ) << "Pane" ; |
| 340 | QTest::newRow(dataTag: "StackView" ) << "StackView" ; |
| 341 | } |
| 342 | |
| 343 | void tst_focus::scope() |
| 344 | { |
| 345 | QFETCH(QString, name); |
| 346 | |
| 347 | QQmlEngine engine; |
| 348 | QQmlComponent component(&engine); |
| 349 | component.setData(QString("import QtQuick 2.9; import QtQuick.Controls 2.2; ApplicationWindow { property alias child: child; width: 100; height: 100; %1 { anchors.fill: parent; Item { id: child; width: 10; height: 10 } } }" ).arg(a: name).toUtf8(), baseUrl: QUrl()); |
| 350 | |
| 351 | QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(object: component.create())); |
| 352 | QVERIFY2(window, qPrintable(component.errorString())); |
| 353 | |
| 354 | QQuickControl *control = qobject_cast<QQuickControl *>(object: window->contentItem()->childItems().first()); |
| 355 | QVERIFY(control); |
| 356 | |
| 357 | control->setFocusPolicy(Qt::WheelFocus); |
| 358 | control->setAcceptedMouseButtons(Qt::LeftButton); |
| 359 | |
| 360 | QQuickItem *child = window->property(name: "child" ).value<QQuickItem *>(); |
| 361 | QVERIFY(child); |
| 362 | |
| 363 | window->show(); |
| 364 | window->requestActivate(); |
| 365 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| 366 | |
| 367 | struct TouchDeviceDeleter |
| 368 | { |
| 369 | static inline void cleanup(QTouchDevice *device) |
| 370 | { |
| 371 | QWindowSystemInterface::unregisterTouchDevice(device); |
| 372 | delete device; |
| 373 | } |
| 374 | }; |
| 375 | |
| 376 | QScopedPointer<QTouchDevice, TouchDeviceDeleter> device(new QTouchDevice); |
| 377 | device->setType(QTouchDevice::TouchScreen); |
| 378 | QWindowSystemInterface::registerTouchDevice(device: device.data()); |
| 379 | |
| 380 | child->forceActiveFocus(); |
| 381 | QVERIFY(child->hasActiveFocus()); |
| 382 | QVERIFY(control->hasActiveFocus()); |
| 383 | |
| 384 | // Qt::ClickFocus (mouse) |
| 385 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(control->width() / 2, control->height() / 2)); |
| 386 | QVERIFY(!child->hasActiveFocus()); |
| 387 | QVERIFY(control->hasActiveFocus()); |
| 388 | |
| 389 | // reset |
| 390 | child->forceActiveFocus(); |
| 391 | QVERIFY(child->hasActiveFocus()); |
| 392 | QVERIFY(control->hasActiveFocus()); |
| 393 | |
| 394 | // Qt::ClickFocus (touch) |
| 395 | QTest::touchEvent(window: window.data(), device: device.data()).press(touchId: 0, pt: QPoint(control->width() / 2, control->height() / 2)); |
| 396 | QTest::touchEvent(window: window.data(), device: device.data()).release(touchId: 0, pt: QPoint(control->width() / 2, control->height() / 2)); |
| 397 | QVERIFY(!child->hasActiveFocus()); |
| 398 | QVERIFY(control->hasActiveFocus()); |
| 399 | |
| 400 | // reset |
| 401 | child->forceActiveFocus(); |
| 402 | QVERIFY(child->hasActiveFocus()); |
| 403 | QVERIFY(control->hasActiveFocus()); |
| 404 | |
| 405 | // Qt::WheelFocus |
| 406 | QWheelEvent wheelEvent(QPoint(control->width() / 2, control->height() / 2), 10, Qt::NoButton, Qt::NoModifier); |
| 407 | QGuiApplication::sendEvent(receiver: control, event: &wheelEvent); |
| 408 | QVERIFY(!child->hasActiveFocus()); |
| 409 | QVERIFY(control->hasActiveFocus()); |
| 410 | } |
| 411 | |
| 412 | QTEST_MAIN(tst_focus) |
| 413 | |
| 414 | #include "tst_focus.moc" |
| 415 | |