Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 <michael.brasser@nokia.com>
  • Loading branch information
Andrew den Exter authored and Qt by Nokia committed Feb 1, 2012
1 parent e7224de commit 6a84390
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 12 deletions.
11 changes: 7 additions & 4 deletions src/quick/items/qquickcanvas.cpp
Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions src/quick/items/qquickcanvas_p.h
Expand Up @@ -135,6 +135,7 @@ class QQuickCanvasPrivate : public QWindowPrivate
QList<QQuickItem*> hoverItems;
enum FocusOption {
DontChangeFocusProperty = 0x01,
DontChangeSubFocusItem = 0x02
};
Q_DECLARE_FLAGS(FocusOptions, FocusOption)

Expand Down
27 changes: 20 additions & 7 deletions src/quick/items/qquickitem.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/quick/items/qquickitem_p.h
Expand Up @@ -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 {
Expand Down
139 changes: 139 additions & 0 deletions tests/auto/qtquick2/qquickitem/tst_qquickitem.cpp
Expand Up @@ -136,6 +136,7 @@ private slots:

void visible();
void enabled();
void enabledFocus();

void mouseGrab();
void touchEventAccept();
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 6a84390

Please sign in to comment.