Fix item focus following canvas focus.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Mon, 24 Oct 2011 03:57:12 +0000 (13:57 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 24 Oct 2011 07:11:14 +0000 (09:11 +0200)
Restore canvas focus handling so that active item focus is added and
removed as  the canvas focus changes.

Task-number: QTBUG-17320
Change-Id: Ief60f35da2f3a563f397ce026ca6fea289a200c4
Reviewed-by: Martin Jones <martin.jones@nokia.com>

src/declarative/items/qquickcanvas.cpp
src/declarative/items/qquickcanvas.h
tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp
tests/auto/declarative/qquickitem/tst_qquickitem.cpp
tests/auto/declarative/qquickitem2/tst_qquickitem.cpp
tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp
tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp

index 8f87ce7..52ef421 100644 (file)
@@ -348,6 +348,17 @@ void QQuickCanvas::hideEvent(QHideEvent *)
     d->thread->stopRendering();
 }
 
+void QQuickCanvas::focusOutEvent(QFocusEvent *)
+{
+    Q_D(QQuickCanvas);
+    d->rootItem->setFocus(false);
+}
+
+void QQuickCanvas::focusInEvent(QFocusEvent *)
+{
+    Q_D(QQuickCanvas);
+    d->rootItem->setFocus(true);
+}
 
 
 /*!
@@ -484,10 +495,6 @@ void QQuickCanvasPrivate::init(QQuickCanvas *c)
     rootItemPrivate->canvas = q;
     rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
 
-    // QML always has focus. It is important that this call happens after the rootItem
-    // has a canvas..
-    rootItem->setFocus(true);
-
     bool threaded = !qmlNoThreadedRenderer();
 
     if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)) {
@@ -626,13 +633,13 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F
     }
 
     if (!(options & DontChangeFocusProperty)) {
-        // if (item != rootItem || q->hasFocus()) { // ### refactor: focus handling...
+        if (item != rootItem || QGuiApplication::focusWindow() == q) {
             itemPrivate->focus = true;
             changed << item;
-        // }
+        }
     }
 
-    if (newActiveFocusItem) { // ### refactor:  && q->hasFocus()) {
+    if (newActiveFocusItem && QGuiApplication::focusWindow() == q) {
         activeFocusItem = newActiveFocusItem;
 
         QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
index 8b69744..e9b1b60 100644 (file)
@@ -101,6 +101,9 @@ protected:
     virtual void showEvent(QShowEvent *);
     virtual void hideEvent(QHideEvent *);
 
+    virtual void focusInEvent(QFocusEvent *);
+    virtual void focusOutEvent(QFocusEvent *);
+
     virtual bool event(QEvent *);
     virtual void keyPressEvent(QKeyEvent *);
     virtual void keyReleaseEvent(QKeyEvent *);
index 6e7dd98..ffb9660 100644 (file)
@@ -121,6 +121,7 @@ void tst_qquickfocusscope::basic()
     view->requestActivateWindow();
 
     QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     QVERIFY(view->isTopLevel());
     QVERIFY(item0->hasActiveFocus() == true);
@@ -165,6 +166,7 @@ void tst_qquickfocusscope::nested()
     view->requestActivateWindow();
 
     QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     QVERIFY(item1->hasActiveFocus() == true);
     QVERIFY(item2->hasActiveFocus() == true);
@@ -191,6 +193,7 @@ void tst_qquickfocusscope::noFocus()
     view->show();
     view->requestActivateWindow();
     QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     QVERIFY(item0->hasActiveFocus() == false);
     QVERIFY(item1->hasActiveFocus() == false);
@@ -283,6 +286,7 @@ void tst_qquickfocusscope::forceFocus()
     view->show();
     view->requestActivateWindow();
     QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     QVERIFY(item0->hasActiveFocus() == true);
     QVERIFY(item1->hasActiveFocus() == true);
@@ -318,12 +322,8 @@ void tst_qquickfocusscope::noParentFocus()
 
     view->show();
     view->requestActivateWindow();
-    qApp->processEvents();
-
-#ifdef Q_WS_X11
-    // to be safe and avoid failing setFocus with window managers
-    qt_x11_wait_for_window_manager(view);
-#endif
+    QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     QVERIFY(view->rootObject()->property("focus1") == false);
     QVERIFY(view->rootObject()->property("focus2") == false);
@@ -352,6 +352,7 @@ void tst_qquickfocusscope::signalEmission()
     view->requestActivateWindow();
 
     QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     QVariant blue(QColor("blue"));
     QVariant red(QColor("red"));
@@ -417,12 +418,8 @@ void tst_qquickfocusscope::forceActiveFocus()
 
     view->show();
     view->requestActivateWindow();
-    qApp->processEvents();
-
-#ifdef Q_WS_X11
-    // to be safe and avoid failing setFocus with window managers
-    qt_x11_wait_for_window_manager(view);
-#endif
+    QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     QQuickItem *rootObject = view->rootObject();
     QVERIFY(rootObject);
@@ -533,6 +530,8 @@ void tst_qquickfocusscope::canvasFocus()
     QQuickView *view = new QQuickView;
     view->setSource(QUrl::fromLocalFile(TESTDATA("canvasFocus.qml")));
 
+    QQuickView alternateView;
+
     QQuickItem *rootObject = view->rootObject();
     QVERIFY(rootObject);
 
@@ -558,8 +557,6 @@ void tst_qquickfocusscope::canvasFocus()
     QSignalSpy scope2ActiveFocusSpy(scope2, SIGNAL(activeFocusChanged(bool)));
     QSignalSpy item2ActiveFocusSpy(item2, SIGNAL(activeFocusChanged(bool)));
 
-    QEXPECT_FAIL("", "QTBUG-21054 - Root item hasFocus returns true already", Abort);
-
     QCOMPARE(rootItem->hasFocus(), false);
     QCOMPARE(rootItem->hasActiveFocus(), false);
     QCOMPARE(scope1->hasFocus(), true);
@@ -575,6 +572,7 @@ void tst_qquickfocusscope::canvasFocus()
     view->requestActivateWindow();
 
     QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(view == qGuiApp->focusWindow());
 
     // Now the canvas has focus, active focus given to item1
     QCOMPARE(rootItem->hasFocus(), true);
@@ -595,7 +593,12 @@ void tst_qquickfocusscope::canvasFocus()
     QCOMPARE(item1ActiveFocusSpy.count(), 1);
 
 
-    view->hide();
+    //    view->hide(); // seemingly doesn't remove focus, so have an another view steal it.
+    alternateView.show();
+    alternateView.requestActivateWindow();
+    QTest::qWaitForWindowShown(&alternateView);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &alternateView);
+
     QCOMPARE(rootItem->hasFocus(), false);
     QCOMPARE(rootItem->hasActiveFocus(), false);
     QCOMPARE(scope1->hasFocus(), true);
@@ -636,6 +639,9 @@ void tst_qquickfocusscope::canvasFocus()
 
     // give the canvas focus, and item2 will get active focus
     view->show();
+    view->requestActivateWindow();
+    QTest::qWaitForWindowShown(view);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == view);
 
     QCOMPARE(rootItem->hasFocus(), true);
     QCOMPARE(rootItem->hasActiveFocus(), true);
index 694fdc0..35346c8 100644 (file)
@@ -239,6 +239,7 @@ void tst_qquickitem::simpleFocus()
 {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
 
     QQuickItem *l1c1 = new TestItem(canvas.rootItem());
     QQuickItem *l1c2 = new TestItem(canvas.rootItem());
@@ -289,6 +290,7 @@ void tst_qquickitem::scopedFocus()
 {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
 
     QQuickItem *l1c1 = new TestItem(canvas.rootItem());
     QQuickItem *l1c2 = new TestItem(canvas.rootItem());
@@ -368,6 +370,7 @@ void tst_qquickitem::addedToCanvas()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
 
     QQuickItem *item = new TestItem;
 
@@ -387,6 +390,7 @@ void tst_qquickitem::addedToCanvas()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
 
     QQuickItem *item = new TestItem(canvas.rootItem());
 
@@ -415,6 +419,7 @@ void tst_qquickitem::addedToCanvas()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
 
     QQuickItem *tree = new TestItem;
     QQuickItem *c1 = new TestItem(tree);
@@ -438,6 +443,7 @@ void tst_qquickitem::addedToCanvas()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *tree = new TestFocusScope;
     QQuickItem *c1 = new TestItem(tree);
     QQuickItem *c2 = new TestItem(tree);
@@ -465,6 +471,7 @@ void tst_qquickitem::addedToCanvas()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *tree = new TestFocusScope;
     QQuickItem *c1 = new TestItem(tree);
     QQuickItem *c2 = new TestItem(tree);
@@ -490,6 +497,7 @@ void tst_qquickitem::addedToCanvas()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *child = new TestItem(canvas.rootItem());
     QQuickItem *tree = new TestFocusScope;
     QQuickItem *c1 = new TestItem(tree);
@@ -529,6 +537,7 @@ void tst_qquickitem::changeParent()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *child = new TestItem(canvas.rootItem());
 
     FocusState focusState;
@@ -550,6 +559,7 @@ void tst_qquickitem::changeParent()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *child = new TestItem(canvas.rootItem());
     QQuickItem *child2 = new TestItem(canvas.rootItem());
 
@@ -570,6 +580,7 @@ void tst_qquickitem::changeParent()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *child = new TestItem(canvas.rootItem());
     QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
     QQuickItem *item = new TestItem(child);
@@ -591,6 +602,7 @@ void tst_qquickitem::changeParent()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *child = new TestItem(canvas.rootItem());
     QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
     QQuickItem *item = new TestItem(child2);
@@ -612,6 +624,7 @@ void tst_qquickitem::changeParent()
     {
     QQuickCanvas canvas;
     ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
     QQuickItem *child = new TestItem(canvas.rootItem());
     QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
     QQuickItem *item = new TestItem(child2);
index 711ca17..648dbe2 100644 (file)
@@ -213,12 +213,9 @@ void tst_QQuickItem::keys()
 
     canvas->setSource(QUrl::fromLocalFile(TESTDATA("keystest.qml")));
     canvas->show();
-    qApp->processEvents();
-
-    QEvent wa(QEvent::WindowActivate);
-    QApplication::sendEvent(canvas, &wa);
-    QFocusEvent fe(QEvent::FocusIn);
-    QApplication::sendEvent(canvas, &fe);
+    canvas->requestActivateWindow();
+    QTest::qWaitForWindowShown(canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
 
     QVERIFY(canvas->rootObject());
     QCOMPARE(canvas->rootObject()->property("isEnabled").toBool(), true);
@@ -334,16 +331,13 @@ void tst_QQuickItem::keysProcessingOrder()
 
     canvas->setSource(QUrl::fromLocalFile(TESTDATA("keyspriority.qml")));
     canvas->show();
-    qApp->processEvents();
+    canvas->requestActivateWindow();
+    QTest::qWaitForWindowShown(canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
 
     KeyTestItem *testItem = qobject_cast<KeyTestItem*>(canvas->rootObject());
     QVERIFY(testItem);
 
-    QEvent wa(QEvent::WindowActivate);
-    QApplication::sendEvent(canvas, &wa);
-    QFocusEvent fe(QEvent::FocusIn);
-    QApplication::sendEvent(canvas, &fe);
-
     QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
     QApplication::sendEvent(canvas, &key);
     QCOMPARE(testObject->mKey, int(Qt::Key_A));
@@ -546,12 +540,9 @@ void tst_QQuickItem::keyNavigation()
 
     canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest.qml")));
     canvas->show();
-    qApp->processEvents();
-
-    QEvent wa(QEvent::WindowActivate);
-    QApplication::sendEvent(canvas, &wa);
-    QFocusEvent fe(QEvent::FocusIn);
-    QApplication::sendEvent(canvas, &fe);
+    canvas->requestActivateWindow();
+    QTest::qWaitForWindowShown(canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
 
     QQuickItem *item = findItem<QQuickItem>(canvas->rootObject(), "item1");
     QVERIFY(item);
@@ -626,7 +617,9 @@ void tst_QQuickItem::keyNavigation_RightToLeft()
 
     canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest.qml")));
     canvas->show();
-    qApp->processEvents();
+    canvas->requestActivateWindow();
+    QTest::qWaitForWindowShown(canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
 
     QQuickItem *rootItem = qobject_cast<QQuickItem*>(canvas->rootObject());
     QVERIFY(rootItem);
@@ -679,12 +672,9 @@ void tst_QQuickItem::keyNavigation_skipNotVisible()
 
     canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest.qml")));
     canvas->show();
-    qApp->processEvents();
-
-    QEvent wa(QEvent::WindowActivate);
-    QApplication::sendEvent(canvas, &wa);
-    QFocusEvent fe(QEvent::FocusIn);
-    QApplication::sendEvent(canvas, &fe);
+    canvas->requestActivateWindow();
+    QTest::qWaitForWindowShown(canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
 
     QQuickItem *item = findItem<QQuickItem>(canvas->rootObject(), "item1");
     QVERIFY(item);
@@ -757,7 +747,9 @@ void tst_QQuickItem::keyNavigation_implicitSetting()
 
     canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest_implicit.qml")));
     canvas->show();
-    qApp->processEvents();
+    canvas->requestActivateWindow();
+    QTest::qWaitForWindowShown(canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
 
     QEvent wa(QEvent::WindowActivate);
     QApplication::sendEvent(canvas, &wa);
@@ -1056,8 +1048,9 @@ void tst_QQuickItem::propertyChanges()
     canvas->setBaseSize(QSize(300, 300));
     canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
     canvas->show();
-
+    canvas->requestActivateWindow();
     QTest::qWaitForWindowShown(canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
 
     QQuickItem *item = findItem<QQuickItem>(canvas->rootObject(), "item");
     QQuickItem *parentItem = findItem<QQuickItem>(canvas->rootObject(), "parentItem");
index a0d36d6..86c33a6 100644 (file)
@@ -1683,31 +1683,18 @@ void tst_qquicktextedit::cursorVisible()
     QCOMPARE(edit.isCursorVisible(), true);
     QCOMPARE(spy.count(), 5);
 
-    QEXPECT_FAIL("", "Most likely a side-effect of QTBUG-21489", Abort);
-    view.setWindowState(Qt::WindowNoState);
+    QQuickView alternateView;
+    alternateView.show();
+    alternateView.requestActivateWindow();
+    QTest::qWaitForWindowShown(&alternateView);
+
     QCOMPARE(edit.isCursorVisible(), false);
     QCOMPARE(spy.count(), 6);
 
     view.requestActivateWindow();
+    QTest::qWaitForWindowShown(&view);
     QCOMPARE(edit.isCursorVisible(), true);
     QCOMPARE(spy.count(), 7);
-
-    // on mac, setActiveWindow(0) on mac does not deactivate the current application
-    // (you have to switch to a different app or hide the current app to trigger this)
-#if !defined(Q_WS_MAC)
-    // on mac, setActiveWindow(0) on mac does not deactivate the current application
-    // (you have to switch to a different app or hide the current app to trigger this)
-//    QApplication::setActiveWindow(0);
-//    QTRY_COMPARE(QApplication::focusWindow(), static_cast<QWidget *>(0));
-//    QCOMPARE(edit.isCursorVisible(), false);
-//    QCOMPARE(spy.count(), 8);
-
-//    view.requestActivateWindow();
-//    QTest::qWaitForWindowShown(&view);
-//    QTRY_COMPARE(view.windowState(), Qt::WindowActive);
-//    QCOMPARE(edit.isCursorVisible(), true);
-//    QCOMPARE(spy.count(), 9);
-#endif
 }
 
 void tst_qquicktextedit::delegateLoading_data()
index 8c8166b..23224d0 100644 (file)
@@ -1798,30 +1798,18 @@ void tst_qquicktextinput::cursorVisible()
     QCOMPARE(input.isCursorVisible(), true);
     QCOMPARE(spy.count(), 5);
 
-    view.setWindowState(Qt::WindowNoState);
-    QEXPECT_FAIL("", "Most likely a side-effect of QTBUG-21489", Abort);
+    QQuickView alternateView;
+    alternateView.show();
+    alternateView.requestActivateWindow();
+    QTest::qWaitForWindowShown(&alternateView);
+
     QCOMPARE(input.isCursorVisible(), false);
     QCOMPARE(spy.count(), 6);
 
     view.requestActivateWindow();
+    QTest::qWaitForWindowShown(&view);
     QCOMPARE(input.isCursorVisible(), true);
     QCOMPARE(spy.count(), 7);
-
-    // on mac, setActiveWindow(0) on mac does not deactivate the current application
-    // (you have to switch to a different app or hide the current app to trigger this)
-#if !defined(Q_WS_MAC)
-    // QGuiApplication has no equivalent of setActiveWindow(0).  Is this different to clearing the
-    // active state of the window or can it be removed?
-//    QApplication::setActiveWindow(0);
-//    QTRY_COMPARE(QApplication::focusWindow(), static_cast<QWidget *>(0));
-//    QCOMPARE(input.isCursorVisible(), false);
-//    QCOMPARE(spy.count(), 8);
-
-//    view.requestActivateWindow();
-//    QTRY_COMPARE(view.windowState(), Qt::WindowActive);
-//    QCOMPARE(input.isCursorVisible(), true);
-//    QCOMPARE(spy.count(), 9);
-#endif
 }
 
 void tst_qquicktextinput::cursorRectangle()