summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexis Menard <alexis.menard@nokia.com>2009-12-09 15:07:13 (GMT)
committerAlexis Menard <alexis.menard@nokia.com>2009-12-09 15:55:19 (GMT)
commit293db01f907ad8644e8242055521e6b8e7c4dfec (patch)
tree5c872a9bdcf7dd4742e8fbcfd7c0835cab59a8b5
parent0dfb4c79dd6fb23fea5277c687485d43b0f91e3f (diff)
downloadQt-293db01f907ad8644e8242055521e6b8e7c4dfec.zip
Qt-293db01f907ad8644e8242055521e6b8e7c4dfec.tar.gz
Qt-293db01f907ad8644e8242055521e6b8e7c4dfec.tar.bz2
Fix a crash on the focus chain when removing items from the scene.
The crash was because of the dangling pointer set on the tabFocusFirst attribute in QGraphicsScene. A child which was the tabFocusFirst was removed from the scene and fixFocusChainBeforeReparenting was setting the new tabFocusFirst pointer to the parent (since in that example it was the focusNext) but later on the parent was removed also from the scene (due to the recursion of removeItem if you call it with the parent : first children, then the parent itself) and fixFocusChainBeforeReparenting was not called again so if you delete the parent then the scene has the dangling pointer set. Task-number:QTBUG-6544 Reviewed-by:janarve
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp11
-rw-r--r--src/gui/graphicsview/qgraphicswidget.cpp2
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.cpp4
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.h2
-rw-r--r--tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp32
5 files changed, 42 insertions, 9 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 27ebb79..2af90b8 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -569,14 +569,10 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
item->d_ptr->clearSubFocus();
- if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
- QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
- widget->d_func()->fixFocusChainBeforeReparenting(0, 0);
- }
-
if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
unregisterScenePosItem(item);
+ QGraphicsScene *oldScene = item->d_func()->scene;
item->d_func()->scene = 0;
//We need to remove all children first because they might use their parent
@@ -587,6 +583,11 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
q->removeItem(item->d_ptr->children.at(i));
}
+ if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0);
+ }
+
// Unregister focus proxy.
item->d_ptr->resetFocusProxy();
diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp
index fe569f4..8de81c2 100644
--- a/src/gui/graphicsview/qgraphicswidget.cpp
+++ b/src/gui/graphicsview/qgraphicswidget.cpp
@@ -1054,7 +1054,7 @@ QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &
break;
case ItemParentChange: {
QGraphicsItem *parent = qVariantValue<QGraphicsItem *>(value);
- d->fixFocusChainBeforeReparenting((parent && parent->isWidget()) ? static_cast<QGraphicsWidget *>(parent) : 0);
+ d->fixFocusChainBeforeReparenting((parent && parent->isWidget()) ? static_cast<QGraphicsWidget *>(parent) : 0, scene());
// Deliver ParentAboutToChange.
QEvent event(QEvent::ParentAboutToChange);
diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp
index b747a30..5b6490f 100644
--- a/src/gui/graphicsview/qgraphicswidget_p.cpp
+++ b/src/gui/graphicsview/qgraphicswidget_p.cpp
@@ -743,7 +743,7 @@ bool QGraphicsWidgetPrivate::hasDecoration() const
/**
* is called after a reparent has taken place to fix up the focus chain(s)
*/
-void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *newScene)
+void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene)
{
Q_Q(QGraphicsWidget);
@@ -789,7 +789,7 @@ void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *new
// update tabFocusFirst for oldScene if the item is going to be removed from oldScene
if (newParent)
newScene = newParent->scene();
- QGraphicsScene *oldScene = q->scene();
+
if (oldScene && newScene != oldScene)
oldScene->d_func()->tabFocusFirst = firstOld;
diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h
index eb53649..65e6962 100644
--- a/src/gui/graphicsview/qgraphicswidget_p.h
+++ b/src/gui/graphicsview/qgraphicswidget_p.h
@@ -98,7 +98,7 @@ public:
mutable qreal *margins;
void ensureMargins() const;
- void fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *newScene = 0);
+ void fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene = 0);
void setLayout_helper(QGraphicsLayout *l);
// Layouts
diff --git a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp
index 3303df5..a835259 100644
--- a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp
+++ b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp
@@ -168,6 +168,7 @@ private slots:
void task236127_bspTreeIndexFails();
void task243004_setStyleCrash();
void task250119_shortcutContext();
+ void QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems();
};
@@ -2855,6 +2856,37 @@ void tst_QGraphicsWidget::polishEvent2()
QVERIFY(widget->events.contains(QEvent::Polish));
}
+void tst_QGraphicsWidget::QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems()
+{
+ QGraphicsScene scene;
+ QGraphicsWidget* parent1 = new QGraphicsWidget;
+ QGraphicsWidget* child1_0 = new QGraphicsWidget;
+ QGraphicsWidget* child1_1 = new QGraphicsWidget;
+
+ QGraphicsWidget* parent2 = new QGraphicsWidget;
+
+ // Add the parent and child to the scene.
+ scene.addItem(parent1);
+ child1_0->setParentItem(parent1);
+ child1_1->setParentItem(parent1);
+
+ // Hide and show the child.
+ child1_0->setParentItem(NULL);
+ scene.removeItem(child1_0);
+
+ // Remove parent from the scene.
+ scene.removeItem(parent1);
+
+ delete child1_0;
+ delete child1_1;
+ delete parent1;
+
+ // Add an item into the scene.
+ scene.addItem(parent2);
+
+ //This should not crash
+}
+
QTEST_MAIN(tst_QGraphicsWidget)
#include "tst_qgraphicswidget.moc"