diff options
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 103 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 68 |
3 files changed, 137 insertions, 37 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); } } diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index b3ca3b5..ea04e0b 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -414,7 +414,8 @@ public: inline void markParentDirty(bool updateBoundingRect = false); - void setFocusHelper(Qt::FocusReason focusReason, bool climb); + void setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromShow); + void clearFocusHelper(bool giveFocusToParent); void setSubFocus(QGraphicsItem *rootItem = 0); void clearSubFocus(QGraphicsItem *rootItem = 0); void resetFocusProxy(); diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 7c1b97e..4d9f23f 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -438,6 +438,7 @@ private slots: void QTBUG_6738_missingUpdateWithSetParent(); void QTBUG_7714_fullUpdateDiscardingOpacityUpdate2(); void QT_2653_fullUpdateDiscardingOpacityUpdate(); + void QT_2649_focusScope(); private: QList<QGraphicsItem *> paintedItems; @@ -10002,5 +10003,72 @@ void tst_QGraphicsItem::QTBUG_7714_fullUpdateDiscardingOpacityUpdate2() QTRY_COMPARE(view.repaints, 1); } +void tst_QGraphicsItem::QT_2649_focusScope() +{ + QGraphicsScene *scene = new QGraphicsScene; + + QGraphicsRectItem *subFocusItem = new QGraphicsRectItem; + subFocusItem->setFlags(QGraphicsItem::ItemIsFocusable); + subFocusItem->setFocus(); + QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); + + QGraphicsRectItem *scope = new QGraphicsRectItem; + scope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); + scope->setFocus(); + subFocusItem->setParentItem(scope); + QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); + QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); + + QGraphicsRectItem *rootItem = new QGraphicsRectItem; + rootItem->setFlags(QGraphicsItem::ItemIsFocusable); + scope->setParentItem(rootItem); + QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); + QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); + QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); + + scene->addItem(rootItem); + + QEvent windowActivate(QEvent::WindowActivate); + qApp->sendEvent(scene, &windowActivate); + scene->setFocus(); + + QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); + QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); + QVERIFY(subFocusItem->hasFocus()); + + scope->hide(); + + QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)0); + QCOMPARE(scope->focusItem(), (QGraphicsItem *)0); + QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)0); + QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); + QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); + QVERIFY(!subFocusItem->hasFocus()); + + scope->show(); + + QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); + QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); + QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); + QVERIFY(subFocusItem->hasFocus()); + + // This should not crash + scope->hide(); + delete scene; +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" |