From 6a8439070ed0582311053d130500facfd3e9d89d Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 23 Jan 2012 13:30:37 +1000 Subject: [PATCH] Update item focus when the enabled property is changed. 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 --- src/quick/items/qquickcanvas.cpp | 11 +- src/quick/items/qquickcanvas_p.h | 1 + src/quick/items/qquickitem.cpp | 27 +++- src/quick/items/qquickitem_p.h | 2 +- tests/auto/qtquick2/qquickitem/tst_qquickitem.cpp | 139 +++++++++++++++++++++ 5 files changed, 168 insertions(+), 12 deletions(-) diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index cf529c0..5aa244c 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -379,11 +379,14 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F QVarLengthArray 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) { diff --git a/src/quick/items/qquickcanvas_p.h b/src/quick/items/qquickcanvas_p.h index 5da75c7..fe57fd1 100644 --- a/src/quick/items/qquickcanvas_p.h +++ b/src/quick/items/qquickcanvas_p.h @@ -135,6 +135,7 @@ public: QList hoverItems; enum FocusOption { DontChangeFocusProperty = 0x01, + DontChangeSubFocusItem = 0x02 }; Q_DECLARE_FLAGS(FocusOptions, FocusOption) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index c9d81c0..032427d 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -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(); } diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 1d2a97d..08cdd57 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -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 { diff --git a/tests/auto/qtquick2/qquickitem/tst_qquickitem.cpp b/tests/auto/qtquick2/qquickitem/tst_qquickitem.cpp index 3ff5054..099f29d 100644 --- a/tests/auto/qtquick2/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/qtquick2/qquickitem/tst_qquickitem.cpp @@ -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(&root)); + + QQuickItem child1; + child1.setParentItem(&root); + + QCOMPARE(child1.isEnabled(), true); + QCOMPARE(child1.hasFocus(), false); + QCOMPARE(child1.hasActiveFocus(), false); + QCOMPARE(canvas.activeFocusItem(), static_cast(&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(&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(&root)); + + child1.setEnabled(true); + QCOMPARE(child1.isEnabled(), true); + QCOMPARE(child1.hasFocus(), true); + QCOMPARE(child1.hasActiveFocus(), true); + QCOMPARE(canvas.activeFocusItem(), static_cast(&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(&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(&child1)); +} + void tst_qquickitem::mouseGrab() { QQuickCanvas *canvas = new QQuickCanvas; -- 1.7.2.5