From a1e81f7353196490284e272e8e440d0c7944bd8f Mon Sep 17 00:00:00 2001
From: Michael Hasselmann <michaelh@openismus.com>
Date: Thu, 10 Feb 2011 19:14:45 +0100
Subject: [PATCH 1/2] 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.
---
 src/gui/graphicsview/qgraphicsitem.cpp  |    8 ++++++++
 src/gui/graphicsview/qgraphicsitem.h    |    3 ++-
 src/gui/graphicsview/qgraphicsitem_p.h  |    6 +++---
 src/gui/graphicsview/qgraphicsscene.cpp |   17 +++++++++++++----
 4 files changed, 26 insertions(+), 8 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;
     }
 
-- 
1.7.4.1

