summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Hasselmann <michaelh@openismus.com>2011-02-10 18:14:45 (GMT)
committerJan-Arve Sæther <jan-arve.saether@nokia.com>2011-03-16 08:37:52 (GMT)
commit517290f73be74d1cf08fbd603870d3dacc379ff3 (patch)
tree8354ffe3c15c37544fae1e284bfa6bb0ec18e3f2
parent5949c215bd53582d0c6481f606a9ec015f067b37 (diff)
downloadQt-517290f73be74d1cf08fbd603870d3dacc379ff3.zip
Qt-517290f73be74d1cf08fbd603870d3dacc379ff3.tar.gz
Qt-517290f73be74d1cf08fbd603870d3dacc379ff3.tar.bz2
Introduce QGraphicsItem::ItemStopsFocusHandling flag
When set for an item, QGraphicsScene will skip focus handling for this item and everything underneath it (including focus-out). Allows users to reimplement custom focus handling. Use case: touch devices that implement panning. Here, focus-in has to happen only if no panning was triggered. Analogous, no focus-out should happen when panning was detected. Fixes the alternative proposal ("black holes for focus changes") of QTBUG-16343: QGraphicsView doesn't support focus change on mouse release. The previous test was only testing one scenario, which didn't give a good idea whether the flag was actually working as intended. Task-number: QTBUG-17505 Reviewed-by: Yoann Lopes Reviewed-by: Jan-Arve Sæther
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp8
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h3
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h6
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp17
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp69
5 files changed, 84 insertions, 19 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index f463887..4e2d4e2 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -417,6 +417,11 @@
click focus to items underneath when being clicked on. This flag
allows you create a non-focusable item that can be clicked on without
changing the focus. \endomit
+
+ \omitvalue ItemStopsFocusHandling \omit Same as
+ ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag
+ allows you to completely take over focus handling.
+ This flag was introduced in Qt 4.7.
*/
/*!
@@ -11549,6 +11554,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
case QGraphicsItem::ItemStopsClickFocusPropagation:
str = "ItemStopsClickFocusPropagation";
break;
+ case QGraphicsItem::ItemStopsFocusHandling:
+ str = "ItemStopsFocusHandling";
+ break;
}
debug << str;
return debug;
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index e59a7c9..67c9cd3 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -107,7 +107,8 @@ public:
ItemIsPanel = 0x4000,
ItemIsFocusScope = 0x8000, // internal
ItemSendsScenePositionChanges = 0x10000,
- ItemStopsClickFocusPropagation = 0x20000
+ ItemStopsClickFocusPropagation = 0x20000,
+ ItemStopsFocusHandling = 0x40000
// NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag.
};
Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag)
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 5c82116..90ff43f 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -559,7 +559,7 @@ public:
quint32 dirtyChildrenBoundingRect : 1;
// Packed 32 bits
- quint32 flags : 18;
+ quint32 flags : 19;
quint32 paintedViewBoundingRectsNeedRepaint : 1;
quint32 dirtySceneTransform : 1;
quint32 geometryChanged : 1;
@@ -573,9 +573,9 @@ public:
quint32 sceneTransformTranslateOnly : 1;
quint32 notifyBoundingRectChanged : 1;
quint32 notifyInvalidated : 1;
- quint32 mouseSetsFocus : 1;
// New 32 bits
+ quint32 mouseSetsFocus : 1;
quint32 explicitActivate : 1;
quint32 wantsActive : 1;
quint32 holesInSiblingIndex : 1;
@@ -586,7 +586,7 @@ public:
quint32 mayHaveChildWithGraphicsEffect : 1;
quint32 isDeclarativeItem : 1;
quint32 sendParentChangeNotification : 1;
- quint32 padding : 22;
+ quint32 padding : 21;
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index f997fc2..2d85de6 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -1317,8 +1317,10 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
// Set focus on the topmost enabled item that can take focus.
bool setFocus = false;
+
foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
- if (item->isBlockedByModalPanel()) {
+ if (item->isBlockedByModalPanel()
+ || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) {
// Make sure we don't clear focus.
setFocus = true;
break;
@@ -1331,10 +1333,10 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
break;
}
}
- if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
- break;
if (item->isPanel())
break;
+ if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
+ break;
}
// Check for scene modality.
@@ -5925,6 +5927,7 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
// Set focus on the topmost enabled item that can take focus.
bool setFocus = false;
+
foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
@@ -5938,6 +5941,11 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
break;
if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
break;
+ if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
+ // Make sure we don't clear focus.
+ setFocus = true;
+ break;
+ }
}
// If nobody could take focus, clear it.
@@ -5970,7 +5978,8 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
}
if (item && item->isPanel())
break;
- if (item && (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation))
+ if (item && (item->d_ptr->flags
+ & (QGraphicsItem::ItemStopsClickFocusPropagation | QGraphicsItem::ItemStopsFocusHandling)))
break;
}
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index dacb61e..168f75e 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -447,7 +447,8 @@ private slots:
void updateMicroFocus();
void textItem_shortcuts();
void scroll();
- void stopClickFocusPropagation();
+ void focusHandling_data();
+ void focusHandling();
void deviceCoordinateCache_simpleRotations();
// task specific tests below me
@@ -10537,8 +10538,39 @@ void tst_QGraphicsItem::scroll()
QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
}
-void tst_QGraphicsItem::stopClickFocusPropagation()
+Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlag);
+
+void tst_QGraphicsItem::focusHandling_data()
{
+ QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("focusFlag");
+ QTest::addColumn<bool>("useStickyFocus");
+ QTest::addColumn<int>("expectedFocusItem"); // 0: none, 1: focusableUnder, 2: itemWithFocus
+
+ QTest::newRow("Focus goes through.")
+ << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << false << 1;
+
+ QTest::newRow("Focus goes through, even with sticky scene.")
+ << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << true << 1;
+
+ QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (but can still focus-out).")
+ << QGraphicsItem::ItemStopsClickFocusPropagation << false << 0;
+
+ QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (and cannot focus-out if scene is sticky).")
+ << QGraphicsItem::ItemStopsClickFocusPropagation << true << 2;
+
+ QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses.")
+ << QGraphicsItem::ItemStopsFocusHandling << false << 2;
+
+ QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses (even if scene is sticky).")
+ << QGraphicsItem::ItemStopsFocusHandling << true << 2;
+}
+
+void tst_QGraphicsItem::focusHandling()
+{
+ QFETCH(QGraphicsItem::GraphicsItemFlag, focusFlag);
+ QFETCH(bool, useStickyFocus);
+ QFETCH(int, expectedFocusItem);
+
class MyItem : public QGraphicsRectItem
{
public:
@@ -10549,12 +10581,9 @@ void tst_QGraphicsItem::stopClickFocusPropagation()
}
};
- QGraphicsScene scene(-50, -50, 400, 400);
- scene.setStickyFocus(true);
-
QGraphicsRectItem *noFocusOnTop = new MyItem;
+ noFocusOnTop->setFlag(QGraphicsItem::ItemIsFocusable, false);
noFocusOnTop->setBrush(Qt::yellow);
- noFocusOnTop->setFlag(QGraphicsItem::ItemStopsClickFocusPropagation);
QGraphicsRectItem *focusableUnder = new MyItem;
focusableUnder->setBrush(Qt::blue);
@@ -10566,9 +10595,13 @@ void tst_QGraphicsItem::stopClickFocusPropagation()
itemWithFocus->setFlag(QGraphicsItem::ItemIsFocusable);
itemWithFocus->setPos(250, 10);
+ QGraphicsScene scene(-50, -50, 400, 400);
scene.addItem(noFocusOnTop);
scene.addItem(focusableUnder);
scene.addItem(itemWithFocus);
+ scene.setStickyFocus(useStickyFocus);
+
+ noFocusOnTop->setFlag(focusFlag);
focusableUnder->stackBefore(noFocusOnTop);
itemWithFocus->setFocus();
@@ -10580,14 +10613,28 @@ void tst_QGraphicsItem::stopClickFocusPropagation()
QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
QVERIFY(itemWithFocus->hasFocus());
- QPointF mousePressPoint = noFocusOnTop->mapToScene(QPointF());
- mousePressPoint.rx() += 60;
- mousePressPoint.ry() += 60;
+ const QPointF mousePressPoint = noFocusOnTop->mapToScene(noFocusOnTop->boundingRect().center());
const QList<QGraphicsItem *> itemsAtMousePressPosition = scene.items(mousePressPoint);
- QVERIFY(itemsAtMousePressPosition.contains(focusableUnder));
+ QVERIFY(itemsAtMousePressPosition.contains(noFocusOnTop));
sendMousePress(&scene, mousePressPoint);
- QVERIFY(itemWithFocus->hasFocus());
+
+ switch (expectedFocusItem) {
+ case 0:
+ QCOMPARE(scene.focusItem(), static_cast<QGraphicsRectItem *>(0));
+ break;
+ case 1:
+ QCOMPARE(scene.focusItem(), focusableUnder);
+ break;
+ case 2:
+ QCOMPARE(scene.focusItem(), itemWithFocus);
+ break;
+ }
+
+ // Sanity check - manually setting the focus must work regardless of our
+ // focus handling flags:
+ focusableUnder->setFocus();
+ QCOMPARE(scene.focusItem(), focusableUnder);
}
void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations()