Fix crash when changing the grandparent of an item with focus.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Fri, 30 Mar 2012 07:36:40 +0000 (17:36 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 2 Apr 2012 06:03:23 +0000 (08:03 +0200)
When an item was reparented it's sub focus item was cleared and those
of it's children were cleared along with those in the tree the item was
removed from.  Since we now rely on the focus state of an unparented
tree to be correct we need to restore the sub focus items of the
unparented tree.

Change-Id: I236c512751b99092c7e9a39194f4680304bfacc5
Reviewed-by: Martin Jones <martin.jones@nokia.com>
src/quick/items/qquickcanvas.cpp
src/quick/items/qquickitem.cpp
tests/auto/quick/qquickitem/tst_qquickitem.cpp

index 5d4293a..29733e9 100644 (file)
@@ -155,6 +155,10 @@ have a scope focused item), and the other items will have their focus cleared.
 // #define TOUCH_DEBUG
 // #define DIRTY_DEBUG
 
+#ifdef FOCUS_DEBUG
+void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
+#endif
+
 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
 : transformNode(0)
 {
index 117667d..782ae10 100644 (file)
@@ -76,6 +76,7 @@
 QT_BEGIN_NAMESPACE
 
 #ifdef FOCUS_DEBUG
+void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
 void printFocusTree(QQuickItem *item, QQuickItem *scope, int depth)
 {
     qWarning()
@@ -1958,6 +1959,8 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
             if (d->canvas) {
                 QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
                                                                 QQuickCanvasPrivate::DontChangeFocusProperty);
+                if (scopeFocusedItem != this)
+                    QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(this, true);
             } else {
                 QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, false);
             }
@@ -4160,7 +4163,7 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
 
     for (int ii = 0; ii < childItems.count(); ++ii) {
         QQuickItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(
-                flags & QQuickItem::ItemIsFocusScope ? q : scope, newEffectiveEnable);
+                (flags & QQuickItem::ItemIsFocusScope) && scope ? q : scope, newEffectiveEnable);
     }
 
     if (canvas && scope && effectiveEnable && focus) {
@@ -4808,6 +4811,7 @@ void QQuickItem::setFocus(bool focus)
             QVarLengthArray<QQuickItem *, 20> changed;
             QQuickItem *oldSubFocusItem = QQuickItemPrivate::get(scope)->subFocusItem;
             if (oldSubFocusItem) {
+                QQuickItemPrivate::get(oldSubFocusItem)->updateSubFocusItem(scope, false);
                 QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
                 changed << oldSubFocusItem;
             }
index afb5c01..a137769 100644 (file)
@@ -141,6 +141,7 @@ private slots:
     void multipleFocusClears();
     void focusSubItemInNonFocusScope();
     void parentItemWithFocus();
+    void reparentFocusedItem();
 
     void constructor();
     void setParentItem();
@@ -822,6 +823,34 @@ void tst_qquickitem::parentItemWithFocus()
     }
 }
 
+void tst_qquickitem::reparentFocusedItem()
+{
+    QQuickCanvas canvas;
+    ensureFocus(&canvas);
+    QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
+
+    QQuickItem parent(canvas.rootItem());
+    QQuickItem child(&parent);
+    QQuickItem sibling(&parent);
+    QQuickItem grandchild(&child);
+
+    FocusState focusState;
+    focusState << &parent << &child << &sibling << &grandchild;
+    FVERIFY();
+
+    grandchild.setFocus(true);
+    focusState[&parent].set(false, false);
+    focusState[&child].set(false, false);
+    focusState[&sibling].set(false, false);
+    focusState[&grandchild].set(true, true);
+    focusState.active(&grandchild);
+    FVERIFY();
+
+    // Parenting the item to another item within the same focus scope shouldn't change it's focus.
+    child.setParentItem(&sibling);
+    FVERIFY();
+}
+
 void tst_qquickitem::constructor()
 {
     QQuickItem *root = new QQuickItem;