diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index cf529c0d71..5aa244c4a8 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 5da75c709a..fe57fd1a47 100644 --- a/src/quick/items/qquickcanvas_p.h +++ b/src/quick/items/qquickcanvas_p.h @@ -135,6 +135,7 @@ class QQuickCanvasPrivate : public QWindowPrivate 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 c9d81c0d11..032427d438 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 1d2a97dbb9..08cdd5700f 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -476,7 +476,7 @@ class Q_QUICK_EXPORT QQuickItemPrivate : public QObjectPrivate 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 3ff5054bd3..099f29d925 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;