Fix assert after giving focus to a disabled item.

If an item has focus stolen by another item remove activeFocus from it even
if the item that gains focus doesn't gain activeFocus.  Otherwise the focus
tree will enter a state where an item that is not the subFocusItem of its
focus scope has activeFocus which is invalid and will trigger an assert
in QQuickWindowPrivate::clearFocusInScope().

Task-number: QTBUG-34779

Change-Id: I72408ec0e4fd9b05ef595147ef1ef95b6aed1c16
Reviewed-by: Alan Alpert <aalpert@blackberry.com>
This commit is contained in:
Andrew den Exter 2013-11-21 11:10:10 +10:00 committed by The Qt Project
parent 9b7dabbe9a
commit 1a76a4926a
2 changed files with 34 additions and 7 deletions

View File

@ -664,14 +664,18 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QVarLengthArray<QQuickItem *, 20> changed;
// Does this change the active focus?
if (item == contentItem || (scopePrivate->activeFocus && item->isEnabled())) {
if (item == contentItem || scopePrivate->activeFocus) {
QQuickItem *oldActiveFocusItem = 0;
oldActiveFocusItem = activeFocusItem;
newActiveFocusItem = item;
while (newActiveFocusItem->isFocusScope()
&& newActiveFocusItem->scopedFocusItem()
&& newActiveFocusItem->scopedFocusItem()->isEnabled()) {
newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
if (item->isEnabled()) {
newActiveFocusItem = item;
while (newActiveFocusItem->isFocusScope()
&& newActiveFocusItem->scopedFocusItem()
&& newActiveFocusItem->scopedFocusItem()->isEnabled()) {
newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
}
} else {
newActiveFocusItem = scope;
}
if (oldActiveFocusItem) {

View File

@ -44,7 +44,6 @@
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickwindow.h>
#include <QtQuick/qquickview.h>
#include <QtWidgets/QGraphicsSceneMouseEvent>
#include "private/qquickfocusscope_p.h"
#include "private/qquickitem_p.h"
#include <qpa/qwindowsysteminterface.h>
@ -1151,6 +1150,30 @@ void tst_qquickitem::enabledFocus()
QCOMPARE(child2.hasFocus(), false);
QCOMPARE(child2.hasActiveFocus(), false);
QCOMPARE(window.activeFocusItem(), static_cast<QQuickItem *>(&child1));
child2.setFocus(true);
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(window.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(window.activeFocusItem(), window.contentItem());
}
static inline QByteArray msgItem(const QQuickItem *item)