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#include <qtest.h>
29#include <QSignalSpy>
30#include <QtQml/qqmlengine.h>
31#include <QtQml/qqmlcomponent.h>
32#include <QtQuick/qquickview.h>
33#include <QtQuick/private/qquickrectangle_p.h>
34#include <private/qquicktextedit_p.h>
35#include <QtQuick/private/qquicktext_p.h>
36#include <QtQuick/private/qquickfocusscope_p.h>
37#include "../../shared/util.h"
38#include "../shared/visualtestutil.h"
39
40using namespace QQuickVisualTestUtil;
41
42class tst_qquickfocusscope : public QQmlDataTest
43{
44 Q_OBJECT
45public:
46 tst_qquickfocusscope() {}
47
48private slots:
49 void basic();
50 void nested();
51 void noFocus();
52 void textEdit();
53 void forceFocus();
54 void noParentFocus();
55 void signalEmission();
56 void qtBug13380();
57 void forceActiveFocus();
58 void canvasFocus();
59};
60
61void tst_qquickfocusscope::basic()
62{
63 QQuickView *view = new QQuickView;
64 view->setSource(testFileUrl(fileName: "test.qml"));
65
66 QQuickFocusScope *item0 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item0"));
67 QQuickRectangle *item1 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item1"));
68 QQuickRectangle *item2 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item2"));
69 QQuickRectangle *item3 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item3"));
70 QVERIFY(item0 != nullptr);
71 QVERIFY(item1 != nullptr);
72 QVERIFY(item2 != nullptr);
73 QVERIFY(item3 != nullptr);
74
75 view->show();
76 view->requestActivate();
77
78 QVERIFY(QTest::qWaitForWindowActive(view));
79 QTRY_COMPARE(view, qGuiApp->focusWindow());
80
81 QVERIFY(view->isTopLevel());
82 QVERIFY(item0->hasActiveFocus());
83 QVERIFY(item1->hasActiveFocus());
84 QVERIFY(!item2->hasActiveFocus());
85 QVERIFY(!item3->hasActiveFocus());
86
87 QTest::keyClick(window: view, key: Qt::Key_Right);
88 QTest::qWait(ms: 50);
89 QVERIFY(item0->hasActiveFocus());
90 QVERIFY(!item1->hasActiveFocus());
91 QVERIFY(item2->hasActiveFocus());
92 QVERIFY(!item3->hasActiveFocus());
93
94 QTest::keyClick(window: view, key: Qt::Key_Down);
95 QTest::qWait(ms: 50);
96 QVERIFY(!item0->hasActiveFocus());
97 QVERIFY(!item1->hasActiveFocus());
98 QVERIFY(!item2->hasActiveFocus());
99 QVERIFY(item3->hasActiveFocus());
100
101 delete view;
102}
103
104void tst_qquickfocusscope::nested()
105{
106 QQuickView *view = new QQuickView;
107 view->setSource(testFileUrl(fileName: "test2.qml"));
108
109 QQuickFocusScope *item1 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item1"));
110 QQuickFocusScope *item2 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item2"));
111 QQuickFocusScope *item3 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item3"));
112 QQuickFocusScope *item4 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item4"));
113 QQuickFocusScope *item5 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item5"));
114 QVERIFY(item1 != nullptr);
115 QVERIFY(item2 != nullptr);
116 QVERIFY(item3 != nullptr);
117 QVERIFY(item4 != nullptr);
118 QVERIFY(item5 != nullptr);
119
120 view->show();
121 view->requestActivate();
122
123 QVERIFY(QTest::qWaitForWindowActive(view));
124 QTRY_COMPARE(view, qGuiApp->focusWindow());
125
126 QVERIFY(item1->hasActiveFocus());
127 QVERIFY(item2->hasActiveFocus());
128 QVERIFY(item3->hasActiveFocus());
129 QVERIFY(item4->hasActiveFocus());
130 QVERIFY(item5->hasActiveFocus());
131 delete view;
132}
133
134void tst_qquickfocusscope::noFocus()
135{
136 QQuickView *view = new QQuickView;
137 view->setSource(testFileUrl(fileName: "test4.qml"));
138
139 QQuickRectangle *item0 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item0"));
140 QQuickRectangle *item1 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item1"));
141 QQuickRectangle *item2 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item2"));
142 QQuickRectangle *item3 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item3"));
143 QVERIFY(item0 != nullptr);
144 QVERIFY(item1 != nullptr);
145 QVERIFY(item2 != nullptr);
146 QVERIFY(item3 != nullptr);
147
148 view->show();
149 view->requestActivate();
150 QVERIFY(QTest::qWaitForWindowActive(view));
151 QCOMPARE(view, qGuiApp->focusWindow());
152
153 QVERIFY(!item0->hasActiveFocus());
154 QVERIFY(!item1->hasActiveFocus());
155 QVERIFY(!item2->hasActiveFocus());
156 QVERIFY(!item3->hasActiveFocus());
157
158 QTest::keyClick(window: view, key: Qt::Key_Right);
159 QVERIFY(!item0->hasActiveFocus());
160 QVERIFY(!item1->hasActiveFocus());
161 QVERIFY(!item2->hasActiveFocus());
162 QVERIFY(!item3->hasActiveFocus());
163
164 QTest::keyClick(window: view, key: Qt::Key_Down);
165 QVERIFY(!item0->hasActiveFocus());
166 QVERIFY(!item1->hasActiveFocus());
167 QVERIFY(!item2->hasActiveFocus());
168 QVERIFY(!item3->hasActiveFocus());
169
170 delete view;
171}
172
173void tst_qquickfocusscope::textEdit()
174{
175 QQuickView *view = new QQuickView;
176 view->setSource(testFileUrl(fileName: "test5.qml"));
177
178 QQuickFocusScope *item0 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item0"));
179 QQuickTextEdit *item1 = findItem<QQuickTextEdit>(parent: view->rootObject(), objectName: QLatin1String("item1"));
180 QQuickRectangle *item2 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item2"));
181 QQuickTextEdit *item3 = findItem<QQuickTextEdit>(parent: view->rootObject(), objectName: QLatin1String("item3"));
182 QVERIFY(item0 != nullptr);
183 QVERIFY(item1 != nullptr);
184 QVERIFY(item2 != nullptr);
185 QVERIFY(item3 != nullptr);
186
187 view->show();
188 view->requestActivate();
189
190 QVERIFY(QTest::qWaitForWindowActive(view));
191
192 QTRY_COMPARE(view, qGuiApp->focusWindow());
193 QVERIFY(item0->hasActiveFocus());
194 QVERIFY(item1->hasActiveFocus());
195 QVERIFY(!item2->hasActiveFocus());
196 QVERIFY(!item3->hasActiveFocus());
197
198 QTest::keyClick(window: view, key: Qt::Key_Right);
199 QVERIFY(item0->hasActiveFocus());
200 QVERIFY(item1->hasActiveFocus());
201 QVERIFY(!item2->hasActiveFocus());
202 QVERIFY(!item3->hasActiveFocus());
203
204 QTest::keyClick(window: view, key: Qt::Key_Right);
205 QTest::keyClick(window: view, key: Qt::Key_Right);
206 QTest::keyClick(window: view, key: Qt::Key_Right);
207 QTest::keyClick(window: view, key: Qt::Key_Right);
208 QTest::keyClick(window: view, key: Qt::Key_Right);
209 QVERIFY(item0->hasActiveFocus());
210 QVERIFY(!item1->hasActiveFocus());
211 QVERIFY(item2->hasActiveFocus());
212 QVERIFY(!item3->hasActiveFocus());
213
214 QTest::keyClick(window: view, key: Qt::Key_Down);
215 QVERIFY(!item0->hasActiveFocus());
216 QVERIFY(!item1->hasActiveFocus());
217 QVERIFY(!item2->hasActiveFocus());
218 QVERIFY(item3->hasActiveFocus());
219
220 delete view;
221}
222
223void tst_qquickfocusscope::forceFocus()
224{
225 QQuickView *view = new QQuickView;
226 view->setSource(testFileUrl(fileName: "forcefocus.qml"));
227
228 QQuickFocusScope *item0 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item0"));
229 QQuickRectangle *item1 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item1"));
230 QQuickRectangle *item2 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item2"));
231 QQuickFocusScope *item3 = findItem<QQuickFocusScope>(parent: view->rootObject(), objectName: QLatin1String("item3"));
232 QQuickRectangle *item4 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item4"));
233 QQuickRectangle *item5 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item5"));
234 QVERIFY(item0 != nullptr);
235 QVERIFY(item1 != nullptr);
236 QVERIFY(item2 != nullptr);
237 QVERIFY(item3 != nullptr);
238 QVERIFY(item4 != nullptr);
239 QVERIFY(item5 != nullptr);
240
241 view->show();
242 view->requestActivate();
243 QVERIFY(QTest::qWaitForWindowActive(view));
244 QTRY_COMPARE(view, qGuiApp->focusWindow());
245
246 QVERIFY(item0->hasActiveFocus());
247 QVERIFY(item1->hasActiveFocus());
248 QVERIFY(!item2->hasActiveFocus());
249 QVERIFY(!item3->hasActiveFocus());
250 QVERIFY(!item4->hasActiveFocus());
251 QVERIFY(!item5->hasActiveFocus());
252
253 QTest::keyClick(window: view, key: Qt::Key_4);
254 QVERIFY(item0->hasActiveFocus());
255 QVERIFY(item1->hasActiveFocus());
256 QVERIFY(!item2->hasActiveFocus());
257 QVERIFY(!item3->hasActiveFocus());
258 QVERIFY(!item4->hasActiveFocus());
259 QVERIFY(!item5->hasActiveFocus());
260
261 QTest::keyClick(window: view, key: Qt::Key_5);
262 QVERIFY(!item0->hasActiveFocus());
263 QVERIFY(!item1->hasActiveFocus());
264 QVERIFY(!item2->hasActiveFocus());
265 QVERIFY(item3->hasActiveFocus());
266 QVERIFY(!item4->hasActiveFocus());
267 QVERIFY(item5->hasActiveFocus());
268
269 delete view;
270}
271
272void tst_qquickfocusscope::noParentFocus()
273{
274 QQuickView *view = new QQuickView;
275 view->setSource(testFileUrl(fileName: "chain.qml"));
276 QVERIFY(view->rootObject());
277
278 view->show();
279 view->requestActivate();
280 QVERIFY(QTest::qWaitForWindowActive(view));
281 QTRY_COMPARE(view, qGuiApp->focusWindow());
282
283 QVERIFY(!view->rootObject()->property("focus1").toBool());
284 QVERIFY(!view->rootObject()->property("focus2").toBool());
285 QVERIFY(view->rootObject()->property("focus3").toBool());
286 QVERIFY(view->rootObject()->property("focus4").toBool());
287 QVERIFY(view->rootObject()->property("focus5").toBool());
288
289 delete view;
290}
291
292void tst_qquickfocusscope::signalEmission()
293{
294 QQuickView *view = new QQuickView;
295 view->setSource(testFileUrl(fileName: "signalEmission.qml"));
296
297 QQuickRectangle *item1 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item1"));
298 QQuickRectangle *item2 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item2"));
299 QQuickRectangle *item3 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item3"));
300 QQuickRectangle *item4 = findItem<QQuickRectangle>(parent: view->rootObject(), objectName: QLatin1String("item4"));
301 QVERIFY(item1 != nullptr);
302 QVERIFY(item2 != nullptr);
303 QVERIFY(item3 != nullptr);
304 QVERIFY(item4 != nullptr);
305
306 view->show();
307 view->requestActivate();
308
309 QVERIFY(QTest::qWaitForWindowActive(view));
310 QTRY_COMPARE(view, qGuiApp->focusWindow());
311
312 QVariant blue(QColor("blue"));
313 QVariant red(QColor("red"));
314
315 item1->setFocus(true);
316 QCOMPARE(item1->property("color"), red);
317 QCOMPARE(item2->property("color"), blue);
318 QCOMPARE(item3->property("color"), blue);
319 QCOMPARE(item4->property("color"), blue);
320
321 item2->setFocus(true);
322 QCOMPARE(item1->property("color"), blue);
323 QCOMPARE(item2->property("color"), red);
324 QCOMPARE(item3->property("color"), blue);
325 QCOMPARE(item4->property("color"), blue);
326
327 item3->setFocus(true);
328 QCOMPARE(item1->property("color"), blue);
329 QCOMPARE(item2->property("color"), red);
330 QCOMPARE(item3->property("color"), red);
331 QCOMPARE(item4->property("color"), blue);
332
333 item4->setFocus(true);
334 QCOMPARE(item1->property("color"), blue);
335 QCOMPARE(item2->property("color"), red);
336 QCOMPARE(item3->property("color"), blue);
337 QCOMPARE(item4->property("color"), red);
338
339 item4->setFocus(false);
340 QCOMPARE(item1->property("color"), blue);
341 QCOMPARE(item2->property("color"), red);
342 QCOMPARE(item3->property("color"), blue);
343 QCOMPARE(item4->property("color"), blue);
344
345 delete view;
346}
347
348void tst_qquickfocusscope::qtBug13380()
349{
350 QQuickView *view = new QQuickView;
351 view->setSource(testFileUrl(fileName: "qtBug13380.qml"));
352
353 view->show();
354 QVERIFY(view->rootObject());
355 view->requestActivate();
356 qApp->processEvents();
357
358 QVERIFY(QTest::qWaitForWindowExposed(view));
359
360 QTRY_COMPARE(view, qGuiApp->focusWindow());
361 QVERIFY(view->rootObject()->property("noFocus").toBool());
362
363 view->rootObject()->setProperty(name: "showRect", value: true);
364 QVERIFY(view->rootObject()->property("noFocus").toBool());
365
366 delete view;
367}
368
369void tst_qquickfocusscope::forceActiveFocus()
370{
371 QQuickView *view = new QQuickView;
372 view->setSource(testFileUrl(fileName: "forceActiveFocus.qml"));
373
374 view->show();
375 view->requestActivate();
376 QVERIFY(QTest::qWaitForWindowExposed(view));
377 QTRY_COMPARE(view, qGuiApp->focusWindow());
378
379 QQuickItem *rootObject = view->rootObject();
380 QVERIFY(rootObject);
381
382 QQuickItem *scope = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("scope"));
383 QQuickItem *itemA1 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("item-a1"));
384 QQuickItem *scopeA = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("scope-a"));
385 QQuickItem *itemA2 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("item-a2"));
386 QQuickItem *itemB1 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("item-b1"));
387 QQuickItem *scopeB = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("scope-b"));
388 QQuickItem *itemB2 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("item-b2"));
389
390 QVERIFY(scope);
391 QVERIFY(itemA1);
392 QVERIFY(scopeA);
393 QVERIFY(itemA2);
394 QVERIFY(itemB1);
395 QVERIFY(scopeB);
396 QVERIFY(itemB2);
397
398 QSignalSpy rootSpy(rootObject, SIGNAL(activeFocusChanged(bool)));
399 QSignalSpy scopeSpy(scope, SIGNAL(activeFocusChanged(bool)));
400 QSignalSpy scopeASpy(scopeA, SIGNAL(activeFocusChanged(bool)));
401 QSignalSpy scopeBSpy(scopeB, SIGNAL(activeFocusChanged(bool)));
402
403 // First, walk the focus from item-a1 down to item-a2 and back again
404 itemA1->forceActiveFocus();
405 QVERIFY(itemA1->hasActiveFocus());
406 QVERIFY(!rootObject->hasActiveFocus());
407 QCOMPARE(rootSpy.count(), 0);
408 QCOMPARE(scopeSpy.count(), 1);
409
410 scopeA->forceActiveFocus();
411 QVERIFY(!itemA1->hasActiveFocus());
412 QVERIFY(scopeA->hasActiveFocus());
413 QCOMPARE(scopeASpy.count(), 1);
414 QCOMPARE(rootSpy.count(), 0);
415 QCOMPARE(scopeSpy.count(), 1);
416
417 itemA2->forceActiveFocus();
418 QVERIFY(!itemA1->hasActiveFocus());
419 QVERIFY(itemA2->hasActiveFocus());
420 QVERIFY(scopeA->hasActiveFocus());
421 QCOMPARE(scopeASpy.count(), 1);
422 QCOMPARE(rootSpy.count(), 0);
423 QCOMPARE(scopeSpy.count(), 1);
424
425 scopeA->forceActiveFocus();
426 QVERIFY(!itemA1->hasActiveFocus());
427 QVERIFY(itemA2->hasActiveFocus());
428 QVERIFY(scopeA->hasActiveFocus());
429 QCOMPARE(scopeASpy.count(), 1);
430 QCOMPARE(rootSpy.count(), 0);
431 QCOMPARE(scopeSpy.count(), 1);
432
433 itemA1->forceActiveFocus();
434 QVERIFY(itemA1->hasActiveFocus());
435 QVERIFY(!scopeA->hasActiveFocus());
436 QVERIFY(!itemA2->hasActiveFocus());
437 QCOMPARE(scopeASpy.count(), 2);
438 QCOMPARE(rootSpy.count(), 0);
439 QCOMPARE(scopeSpy.count(), 1);
440
441 // Then jump back and forth between branch 'a' and 'b'
442 itemB1->forceActiveFocus();
443 QVERIFY(itemB1->hasActiveFocus());
444 QCOMPARE(rootSpy.count(), 0);
445 QCOMPARE(scopeSpy.count(), 1);
446
447 scopeA->forceActiveFocus();
448 QVERIFY(!itemA1->hasActiveFocus());
449 QVERIFY(!itemB1->hasActiveFocus());
450 QVERIFY(scopeA->hasActiveFocus());
451 QCOMPARE(scopeASpy.count(), 3);
452 QCOMPARE(rootSpy.count(), 0);
453 QCOMPARE(scopeSpy.count(), 1);
454
455 scopeB->forceActiveFocus();
456 QVERIFY(!scopeA->hasActiveFocus());
457 QVERIFY(!itemB1->hasActiveFocus());
458 QVERIFY(scopeB->hasActiveFocus());
459 QCOMPARE(scopeASpy.count(), 4);
460 QCOMPARE(scopeBSpy.count(), 1);
461 QCOMPARE(rootSpy.count(), 0);
462 QCOMPARE(scopeSpy.count(), 1);
463
464 itemA2->forceActiveFocus();
465 QVERIFY(!scopeB->hasActiveFocus());
466 QVERIFY(itemA2->hasActiveFocus());
467 QCOMPARE(scopeASpy.count(), 5);
468 QCOMPARE(scopeBSpy.count(), 2);
469 QCOMPARE(rootSpy.count(), 0);
470 QCOMPARE(scopeSpy.count(), 1);
471
472 itemB2->forceActiveFocus();
473 QVERIFY(!itemA2->hasActiveFocus());
474 QVERIFY(itemB2->hasActiveFocus());
475 QCOMPARE(scopeASpy.count(), 6);
476 QCOMPARE(scopeBSpy.count(), 3);
477 QCOMPARE(rootSpy.count(), 0);
478 QCOMPARE(scopeSpy.count(), 1);
479
480 delete view;
481}
482
483void tst_qquickfocusscope::canvasFocus()
484{
485 QQuickView *view = new QQuickView;
486 view->setSource(testFileUrl(fileName: "canvasFocus.qml"));
487
488 QQuickView alternateView;
489
490 QQuickItem *rootObject = view->rootObject();
491 QVERIFY(rootObject);
492
493 QQuickItem *rootItem = view->contentItem();
494 QQuickItem *scope1 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("scope1"));
495 QQuickItem *item1 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("item1"));
496 QQuickItem *scope2 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("scope2"));
497 QQuickItem *item2 = findItem<QQuickItem>(parent: rootObject, objectName: QLatin1String("item2"));
498
499 QVERIFY(scope1);
500 QVERIFY(item1);
501 QVERIFY(scope2);
502 QVERIFY(item2);
503
504 QSignalSpy rootFocusSpy(rootItem, SIGNAL(focusChanged(bool)));
505 QSignalSpy scope1FocusSpy(scope1, SIGNAL(focusChanged(bool)));
506 QSignalSpy item1FocusSpy(item1, SIGNAL(focusChanged(bool)));
507 QSignalSpy scope2FocusSpy(scope2, SIGNAL(focusChanged(bool)));
508 QSignalSpy item2FocusSpy(item2, SIGNAL(focusChanged(bool)));
509 QSignalSpy rootActiveFocusSpy(rootItem, SIGNAL(activeFocusChanged(bool)));
510 QSignalSpy scope1ActiveFocusSpy(scope1, SIGNAL(activeFocusChanged(bool)));
511 QSignalSpy item1ActiveFocusSpy(item1, SIGNAL(activeFocusChanged(bool)));
512 QSignalSpy scope2ActiveFocusSpy(scope2, SIGNAL(activeFocusChanged(bool)));
513 QSignalSpy item2ActiveFocusSpy(item2, SIGNAL(activeFocusChanged(bool)));
514
515 QCOMPARE(rootItem->hasFocus(), false);
516 QCOMPARE(rootItem->hasActiveFocus(), false);
517 QCOMPARE(scope1->hasFocus(), true);
518 QCOMPARE(scope1->hasActiveFocus(), false);
519 QCOMPARE(item1->hasFocus(), true);
520 QCOMPARE(item1->hasActiveFocus(), false);
521 QCOMPARE(scope2->hasFocus(), false);
522 QCOMPARE(scope2->hasActiveFocus(), false);
523 QCOMPARE(item2->hasFocus(), false);
524 QCOMPARE(item2->hasActiveFocus(), false);
525
526 view->show();
527 view->requestActivate();
528
529 QVERIFY(QTest::qWaitForWindowActive(view));
530 QCOMPARE(view, qGuiApp->focusWindow());
531
532 // Now the window has focus, active focus given to item1
533 QCOMPARE(rootItem->hasFocus(), true);
534 QCOMPARE(rootItem->hasActiveFocus(), true);
535 QCOMPARE(scope1->hasFocus(), true);
536 QCOMPARE(scope1->hasActiveFocus(), true);
537 QCOMPARE(item1->hasFocus(), true);
538 QCOMPARE(item1->hasActiveFocus(), true);
539 QCOMPARE(scope2->hasFocus(), false);
540 QCOMPARE(scope2->hasActiveFocus(), false);
541 QCOMPARE(item2->hasFocus(), false);
542 QCOMPARE(item2->hasActiveFocus(), false);
543
544 QCOMPARE(rootFocusSpy.count(), 1);
545 QCOMPARE(rootActiveFocusSpy.count(), 1);
546 QCOMPARE(scope1FocusSpy.count(), 0);
547 QCOMPARE(scope1ActiveFocusSpy.count(), 1);
548 QCOMPARE(item1FocusSpy.count(), 0);
549 QCOMPARE(item1ActiveFocusSpy.count(), 1);
550
551
552 // view->hide(); // seemingly doesn't remove focus, so have an another view steal it.
553 alternateView.show();
554 alternateView.requestActivate();
555 QVERIFY(QTest::qWaitForWindowActive(&alternateView));
556 QCOMPARE(QGuiApplication::focusWindow(), &alternateView);
557
558 QCOMPARE(rootItem->hasFocus(), false);
559 QCOMPARE(rootItem->hasActiveFocus(), false);
560 QCOMPARE(scope1->hasFocus(), true);
561 QCOMPARE(scope1->hasActiveFocus(), false);
562 QCOMPARE(item1->hasFocus(), true);
563 QCOMPARE(item1->hasActiveFocus(), false);
564
565 QCOMPARE(rootFocusSpy.count(), 2);
566 QCOMPARE(rootActiveFocusSpy.count(), 2);
567 QCOMPARE(scope1FocusSpy.count(), 0);
568 QCOMPARE(scope1ActiveFocusSpy.count(), 2);
569 QCOMPARE(item1FocusSpy.count(), 0);
570 QCOMPARE(item1ActiveFocusSpy.count(), 2);
571
572
573 // window does not have focus, so item2 will not get active focus
574 item2->forceActiveFocus();
575
576 QCOMPARE(rootItem->hasFocus(), false);
577 QCOMPARE(rootItem->hasActiveFocus(), false);
578 QCOMPARE(scope1->hasFocus(), false);
579 QCOMPARE(scope1->hasActiveFocus(), false);
580 QCOMPARE(item1->hasFocus(), true);
581 QCOMPARE(item1->hasActiveFocus(), false);
582 QCOMPARE(scope2->hasFocus(), true);
583 QCOMPARE(scope2->hasActiveFocus(), false);
584 QCOMPARE(item2->hasFocus(), true);
585 QCOMPARE(item2->hasActiveFocus(), false);
586
587 QCOMPARE(rootFocusSpy.count(), 2);
588 QCOMPARE(rootActiveFocusSpy.count(), 2);
589 QCOMPARE(scope1FocusSpy.count(), 1);
590 QCOMPARE(scope1ActiveFocusSpy.count(), 2);
591 QCOMPARE(item1FocusSpy.count(), 0);
592 QCOMPARE(item1ActiveFocusSpy.count(), 2);
593 QCOMPARE(scope2FocusSpy.count(), 1);
594 QCOMPARE(scope2ActiveFocusSpy.count(), 0);
595 QCOMPARE(item2FocusSpy.count(), 1);
596 QCOMPARE(item2ActiveFocusSpy.count(), 0);
597
598 // give the window focus, and item2 will get active focus
599 view->show();
600 view->requestActivate();
601 QVERIFY(QTest::qWaitForWindowActive(view));
602 QCOMPARE(QGuiApplication::focusWindow(), view);
603
604 QCOMPARE(rootItem->hasFocus(), true);
605 QCOMPARE(rootItem->hasActiveFocus(), true);
606 QCOMPARE(scope2->hasFocus(), true);
607 QCOMPARE(scope2->hasActiveFocus(), true);
608 QCOMPARE(item2->hasFocus(), true);
609 QCOMPARE(item2->hasActiveFocus(), true);
610 QCOMPARE(rootFocusSpy.count(), 3);
611 QCOMPARE(rootActiveFocusSpy.count(), 3);
612 QCOMPARE(scope2FocusSpy.count(), 1);
613 QCOMPARE(scope2ActiveFocusSpy.count(), 1);
614 QCOMPARE(item2FocusSpy.count(), 1);
615 QCOMPARE(item2ActiveFocusSpy.count(), 1);
616
617 delete view;
618}
619
620QTEST_MAIN(tst_qquickfocusscope)
621
622#include "tst_qquickfocusscope.moc"
623

source code of qtdeclarative/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp