summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview/qgraphicsitem.cpp
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@nokia.com>2010-03-03 11:05:15 (GMT)
committerYoann Lopes <yoann.lopes@nokia.com>2010-03-03 11:05:15 (GMT)
commit971f19473a7e9c35f14140235c2be3b68006b5f2 (patch)
tree01f4fb2dae8d61f29f54886528a0ddfed1b027cc /src/gui/graphicsview/qgraphicsitem.cpp
parent6c44ab0f6edebce1e7190b94ac5b74c81812f482 (diff)
downloadQt-971f19473a7e9c35f14140235c2be3b68006b5f2.zip
Qt-971f19473a7e9c35f14140235c2be3b68006b5f2.tar.gz
Qt-971f19473a7e9c35f14140235c2be3b68006b5f2.tar.bz2
Properly fixes crash when destroying a QGraphicsItem.
The focus is now properly cleared when hiding or showing focus scopes or when a child of a focus scope is destroyed. No change of behavior in how focus scope works for QML. Autotest included. Task-number: QT-2649 Reviewed-by: Andreas Aardal Hanssen
Diffstat (limited to 'src/gui/graphicsview/qgraphicsitem.cpp')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp103
1 files changed, 67 insertions, 36 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 368af58..f3c90ca 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -641,10 +641,10 @@
are children of a modal panel are not blocked.
The values are:
-
+
\value NonModal The panel is not modal and does not block input to
other panels. This is the default value for panels.
-
+
\value PanelModal The panel is modal to a single item hierarchy
and blocks input to its parent pane, all grandparent panels, and
all siblings of its parent and grandparent panels.
@@ -2181,6 +2181,7 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
}
// Certain properties are dropped as an item becomes invisible.
+ bool hasFocus = q_ptr->hasFocus();
if (!newVisible) {
if (scene) {
if (scene->d_func()->mouseGrabberItems.contains(q))
@@ -2190,7 +2191,7 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
if (q->isPanel() && panelModality != QGraphicsItem::NonModal)
scene->d_func()->leaveModal(q_ptr);
}
- if (q_ptr->hasFocus() && scene) {
+ if (hasFocus && scene) {
// Hiding the closest non-panel ancestor of the focus item
QGraphicsItem *focusItem = scene->focusItem();
bool clear = true;
@@ -2203,7 +2204,7 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
} while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
}
if (clear)
- q_ptr->clearFocus();
+ clearFocusHelper(/* giveFocusToParent = */ false);
}
if (q_ptr->isSelected())
q_ptr->setSelected(false);
@@ -2241,26 +2242,45 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
}
// Enable subfocus
- if (scene && newVisible) {
- QGraphicsItem *p = parent;
- bool done = false;
- while (p) {
- if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
- QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
- if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
- done = true;
- while (fsi->d_ptr->focusScopeItem && fsi->d_ptr->focusScopeItem->isVisible())
- fsi = fsi->d_ptr->focusScopeItem;
- scene->setFocusItem(fsi);
+ if (scene) {
+ if (newVisible) {
+ // Item is shown
+ QGraphicsItem *p = parent;
+ bool done = false;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
+ if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
+ done = true;
+ while (fsi->d_ptr->focusScopeItem && fsi->d_ptr->focusScopeItem->isVisible())
+ fsi = fsi->d_ptr->focusScopeItem;
+ fsi->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true,
+ /* focusFromShow = */ true);
+ }
+ break;
}
- break;
+ p = p->d_ptr->parent;
}
- p = p->d_ptr->parent;
- }
- if (!done) {
- QGraphicsItem *fi = subFocusItem;
- if (fi && fi != scene->focusItem()) {
- scene->setFocusItem(fi);
+ if (!done) {
+ QGraphicsItem *fi = subFocusItem;
+ if (fi && fi != scene->focusItem()) {
+ scene->setFocusItem(fi);
+ }
+ }
+ } else {
+ // Item is hidden
+ if (hasFocus) {
+ QGraphicsItem *p = parent;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ if (p->d_ptr->visible) {
+ p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true,
+ /* focusFromShow = */ true);
+ }
+ break;
+ }
+ p = p->d_ptr->parent;
+ }
}
}
}
@@ -3111,13 +3131,13 @@ bool QGraphicsItem::hasFocus() const
*/
void QGraphicsItem::setFocus(Qt::FocusReason focusReason)
{
- d_ptr->setFocusHelper(focusReason, /* climb = */ true);
+ d_ptr->setFocusHelper(focusReason, /* climb = */ true, /* focusFromShow = */ false);
}
/*!
\internal
*/
-void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb)
+void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromShow)
{
// Disabled / unfocusable items cannot accept focus.
if (!q_ptr->isEnabled() || !(flags & QGraphicsItem::ItemIsFocusable))
@@ -3137,7 +3157,7 @@ void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool clim
while (p) {
if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
p->d_ptr->focusScopeItem = q_ptr;
- if (!p->focusItem()) {
+ if (!p->focusItem() && !focusFromShow) {
// If you call setFocus on a child of a focus scope that
// doesn't currently have a focus item, then stop.
return;
@@ -3178,24 +3198,35 @@ void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool clim
*/
void QGraphicsItem::clearFocus()
{
- // Pass focus to the closest parent focus scope.
- if (!d_ptr->inDestructor) {
- QGraphicsItem *p = d_ptr->parent;
- while (p) {
- if (p->flags() & ItemIsFocusScope) {
- p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ false);
- return;
+ d_ptr->clearFocusHelper(/* giveFocusToParent = */ true);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::clearFocusHelper(bool giveFocusToParent)
+{
+ if (giveFocusToParent) {
+ // Pass focus to the closest parent focus scope
+ if (!inDestructor) {
+ QGraphicsItem *p = parent;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ false,
+ /* focusFromShow = */ false);
+ return;
+ }
+ p = p->d_ptr->parent;
}
- p = p->d_ptr->parent;
}
}
// Invisible items with focus must explicitly clear subfocus.
- d_ptr->clearSubFocus(this);
+ clearSubFocus(q_ptr);
- if (hasFocus()) {
+ if (q_ptr->hasFocus()) {
// If this item has the scene's input focus, clear it.
- d_ptr->scene->setFocusItem(0);
+ scene->setFocusItem(0);
}
}