Update item focus when the enabled property is changed.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Mon, 23 Jan 2012 03:30:37 +0000 (13:30 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 1 Feb 2012 07:37:49 +0000 (08:37 +0100)
Remove active focus from an item when it is disabled, and give active
focus to an enabled item if it has focus within a scope with active
focus.

Task-number: QTBUG-22404
Change-Id: Iff2b774a9ff784e6107a4ed6524c93e749ae0182
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>

src/quick/items/qquickcanvas.cpp
src/quick/items/qquickcanvas_p.h
src/quick/items/qquickitem.cpp
src/quick/items/qquickitem_p.h
tests/auto/qtquick2/qquickitem/tst_qquickitem.cpp

index cf529c0..5aa244c 100644 (file)
@@ -379,11 +379,14 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F
     QVarLengthArray<QQuickItem *, 20> changed;
 
     // Does this change the active focus?
-    if (item == rootItem || scopePrivate->activeFocus) {
+    if (item == rootItem || scopePrivate->activeFocus && item->isEnabled()) {
         oldActiveFocusItem = activeFocusItem;
         newActiveFocusItem = item;
-        while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
+        while (newActiveFocusItem->isFocusScope()
+               && newActiveFocusItem->scopedFocusItem()
+               && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
             newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+        }
 
         if (oldActiveFocusItem) {
 #ifndef QT_NO_IM
@@ -405,7 +408,7 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F
         }
     }
 
-    if (item != rootItem) {
+    if (item != rootItem && !(options & DontChangeSubFocusItem)) {
         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
         // Correct focus chain in scope
         if (oldSubFocusItem) {
@@ -513,7 +516,7 @@ void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
         }
     }
 
-    if (item != rootItem) {
+    if (item != rootItem && !(options & DontChangeSubFocusItem)) {
         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
         // Correct focus chain in scope
         if (oldSubFocusItem) {
index 5da75c7..fe57fd1 100644 (file)
@@ -135,6 +135,7 @@ public:
     QList<QQuickItem*> hoverItems;
     enum FocusOption {
         DontChangeFocusProperty = 0x01,
+        DontChangeSubFocusItem  = 0x02
     };
     Q_DECLARE_FLAGS(FocusOptions, FocusOption)
 
index c9d81c0..032427d 100644 (file)
@@ -1913,7 +1913,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
         QQuickItemPrivate::get(d->parentItem)->addChild(this);
 
     d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
-    d->setEffectiveEnableRecur(d->calcEffectiveEnable());
+    d->setEffectiveEnableRecur(0, d->calcEffectiveEnable());
 
     if (scopeFocusedItem && d->parentItem && d->canvas) {
         // We need to test whether this item becomes scope focused
@@ -3901,7 +3901,11 @@ void QQuickItem::setEnabled(bool e)
 
     d->explicitEnable = e;
 
-    d->setEffectiveEnableRecur(d->calcEffectiveEnable());
+    QQuickItem *scope = parentItem();
+    while (scope && !scope->isFocusScope())
+        scope = scope->parentItem();
+
+    d->setEffectiveEnableRecur(scope, d->calcEffectiveEnable());
 }
 
 bool QQuickItemPrivate::calcEffectiveVisible() const
@@ -3959,12 +3963,10 @@ bool QQuickItemPrivate::calcEffectiveEnable() const
     return explicitEnable && (!parentItem || QQuickItemPrivate::get(parentItem)->effectiveEnable);
 }
 
-void QQuickItemPrivate::setEffectiveEnableRecur(bool newEffectiveEnable)
+void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffectiveEnable)
 {
     Q_Q(QQuickItem);
 
-    // XXX todo - need to fixup focus
-
     if (newEffectiveEnable && !explicitEnable) {
         // This item locally overrides enable
         return;
@@ -3981,10 +3983,21 @@ void QQuickItemPrivate::setEffectiveEnableRecur(bool newEffectiveEnable)
         QQuickCanvasPrivate *canvasPriv = QQuickCanvasPrivate::get(canvas);
         if (canvasPriv->mouseGrabberItem == q)
             q->ungrabMouse();
+        if (scope && !effectiveEnable && activeFocus) {
+            canvasPriv->clearFocusInScope(
+                    scope, q,  QQuickCanvasPrivate::DontChangeFocusProperty | QQuickCanvasPrivate::DontChangeSubFocusItem);
+        }
     }
 
-    for (int ii = 0; ii < childItems.count(); ++ii)
-        QQuickItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(newEffectiveEnable);
+    for (int ii = 0; ii < childItems.count(); ++ii) {
+        QQuickItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(
+                flags & QQuickItem::ItemIsFocusScope ? q : scope, newEffectiveEnable);
+    }
+
+    if (canvas && scope && effectiveEnable && focus) {
+        QQuickCanvasPrivate::get(canvas)->setFocusInScope(
+                scope, q, QQuickCanvasPrivate::DontChangeFocusProperty | QQuickCanvasPrivate::DontChangeSubFocusItem);
+    }
 
     emit q->enabledChanged();
 }
index 1d2a97d..08cdd57 100644 (file)
@@ -476,7 +476,7 @@ public:
     bool calcEffectiveVisible() const;
     void setEffectiveVisibleRecur(bool);
     bool calcEffectiveEnable() const;
-    void setEffectiveEnableRecur(bool);
+    void setEffectiveEnableRecur(QQuickItem *scope, bool);
 
     // XXX todo
     enum DirtyType {
index 3ff5054..099f29d 100644 (file)
@@ -136,6 +136,7 @@ private slots:
 
     void visible();
     void enabled();
+    void enabledFocus();
 
     void mouseGrab();
     void touchEventAccept();
@@ -801,6 +802,144 @@ void tst_qquickitem::enabled()
     delete child2;
 }
 
+void tst_qquickitem::enabledFocus()
+{
+    QQuickCanvas canvas;
+    ensureFocus(&canvas);
+
+    QQuickFocusScope root;
+
+    root.setFocus(true);
+    root.setEnabled(false);
+
+    QCOMPARE(root.isEnabled(), false);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), false);
+
+    root.setParentItem(canvas.rootItem());
+
+    QCOMPARE(root.isEnabled(), false);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
+
+    root.setEnabled(true);
+    QCOMPARE(root.isEnabled(), true);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), true);
+    QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+    QQuickItem child1;
+    child1.setParentItem(&root);
+
+    QCOMPARE(child1.isEnabled(), true);
+    QCOMPARE(child1.hasFocus(), false);
+    QCOMPARE(child1.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+    QQuickItem child2;
+    child2.setFocus(true);
+    child2.setParentItem(&root);
+
+    QCOMPARE(root.isEnabled(), true);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), true);
+    QCOMPARE(child2.isEnabled(), true);
+    QCOMPARE(child2.hasFocus(), true);
+    QCOMPARE(child2.hasActiveFocus(), true);
+    QCOMPARE(canvas.activeFocusItem(), &child2);
+
+    child2.setEnabled(false);
+
+    QCOMPARE(root.isEnabled(), true);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), true);
+    QCOMPARE(child1.isEnabled(), true);
+    QCOMPARE(child1.hasFocus(), false);
+    QCOMPARE(child1.hasActiveFocus(), false);
+    QCOMPARE(child2.isEnabled(), false);
+    QCOMPARE(child2.hasFocus(), true);
+    QCOMPARE(child2.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+    child1.setEnabled(false);
+    QCOMPARE(child1.isEnabled(), false);
+    QCOMPARE(child1.hasFocus(), false);
+    QCOMPARE(child1.hasActiveFocus(), false);
+
+    child1.setFocus(true);
+    QCOMPARE(child1.isEnabled(), false);
+    QCOMPARE(child1.hasFocus(), true);
+    QCOMPARE(child1.hasActiveFocus(), false);
+    QCOMPARE(child2.isEnabled(), false);
+    QCOMPARE(child2.hasFocus(), false);
+    QCOMPARE(child2.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+    child1.setEnabled(true);
+    QCOMPARE(child1.isEnabled(), true);
+    QCOMPARE(child1.hasFocus(), true);
+    QCOMPARE(child1.hasActiveFocus(), true);
+    QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
+
+    root.setFocus(false);
+    QCOMPARE(root.isEnabled(), true);
+    QCOMPARE(root.hasFocus(), false);
+    QCOMPARE(root.hasActiveFocus(), false);
+    QCOMPARE(child1.isEnabled(), true);
+    QCOMPARE(child1.hasFocus(), true);
+    QCOMPARE(child1.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
+
+    child2.forceActiveFocus();
+    QCOMPARE(root.isEnabled(), true);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), true);
+    QCOMPARE(child1.isEnabled(), true);
+    QCOMPARE(child1.hasFocus(), false);
+    QCOMPARE(child1.hasActiveFocus(), false);
+    QCOMPARE(child2.isEnabled(), false);
+    QCOMPARE(child2.hasFocus(), true);
+    QCOMPARE(child2.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+    root.setEnabled(false);
+    QCOMPARE(root.isEnabled(), false);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), false);
+    QCOMPARE(child1.isEnabled(), false);
+    QCOMPARE(child1.hasFocus(), false);
+    QCOMPARE(child1.hasActiveFocus(), false);
+    QCOMPARE(child2.isEnabled(), false);
+    QCOMPARE(child2.hasFocus(), true);
+    QCOMPARE(child2.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
+
+    child1.forceActiveFocus();
+    QCOMPARE(root.isEnabled(), false);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), false);
+    QCOMPARE(child1.isEnabled(), false);
+    QCOMPARE(child1.hasFocus(), true);
+    QCOMPARE(child1.hasActiveFocus(), false);
+    QCOMPARE(child2.isEnabled(), false);
+    QCOMPARE(child2.hasFocus(), false);
+    QCOMPARE(child2.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
+
+    root.setEnabled(true);
+    QCOMPARE(root.isEnabled(), true);
+    QCOMPARE(root.hasFocus(), true);
+    QCOMPARE(root.hasActiveFocus(), true);
+    QCOMPARE(child1.isEnabled(), true);
+    QCOMPARE(child1.hasFocus(), true);
+    QCOMPARE(child1.hasActiveFocus(), true);
+    QCOMPARE(child2.isEnabled(), false);
+    QCOMPARE(child2.hasFocus(), false);
+    QCOMPARE(child2.hasActiveFocus(), false);
+    QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
+}
+
 void tst_qquickitem::mouseGrab()
 {
     QQuickCanvas *canvas = new QQuickCanvas;