summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp49
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h3
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h15
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp22
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h1
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp123
6 files changed, 204 insertions, 9 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 03014d8..cb0418c 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -650,6 +650,10 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch
// For root items only. This is the item that has either enabled or
// disabled \a childFlag, or has been reparented.
switch (int(childFlag)) {
+ case -2:
+ flag = AncestorFiltersChildEvents;
+ enabled = q->filtersChildEvents();
+ break;
case -1:
flag = AncestorHandlesChildEvents;
enabled = q->handlesChildEvents();
@@ -670,7 +674,8 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch
// Inherit the enabled-state from our parents.
if ((parent && ((parent->d_ptr->ancestorFlags & flag)
|| (int(parent->d_ptr->flags & childFlag) == childFlag)
- || (childFlag == -1 && parent->d_ptr->handlesChildEvents)))) {
+ || (childFlag == -1 && parent->d_ptr->handlesChildEvents)
+ || (childFlag == -2 && parent->d_ptr->filtersDescendantEvents)))) {
enabled = true;
ancestorFlags |= flag;
}
@@ -691,7 +696,9 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch
ancestorFlags &= ~flag;
// Don't process children if the item has the main flag set on itself.
- if ((childFlag != -1 && int(flags & childFlag) == childFlag) || (int(childFlag) == -1 && handlesChildEvents))
+ if ((childFlag != -1 && int(flags & childFlag) == childFlag)
+ || (int(childFlag) == -1 && handlesChildEvents)
+ || (int(childFlag) == -2 && filtersDescendantEvents))
return;
}
@@ -953,6 +960,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
}
// Inherit ancestor flags from the new parent.
+ updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
@@ -969,6 +977,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
} else {
// Inherit ancestor flags from the new parent.
+ updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
@@ -2352,6 +2361,40 @@ void QGraphicsItem::setAcceptTouchEvents(bool enabled)
}
/*!
+ Returns true if this item filters child events (i.e., all events
+ intended for any of its children are instead sent to this item);
+ otherwise, false is returned.
+
+ The default value is false; child events are not filtered.
+
+ \sa setFiltersChildEvents()
+*/
+bool QGraphicsItem::filtersChildEvents() const
+{
+ return d_ptr->filtersDescendantEvents;
+}
+
+/*!
+ If \a enabled is true, this item is set to filter all events for
+ all its children (i.e., all events intented for any of its
+ children are instead sent to this item); otherwise, if \a enabled
+ is false, this item will only handle its own events. The default
+ value is false.
+
+ \sa filtersChildEvents()
+*/
+void QGraphicsItem::setFiltersChildEvents(bool enabled)
+{
+ if (d_ptr->filtersDescendantEvents == enabled)
+ return;
+
+ d_ptr->filtersDescendantEvents = enabled;
+ d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
+}
+
+/*!
+ \obsolete
+
Returns true if this item handles child events (i.e., all events
intended for any of its children are instead sent to this item);
otherwise, false is returned.
@@ -2372,6 +2415,8 @@ bool QGraphicsItem::handlesChildEvents() const
}
/*!
+ \obsolete
+
If \a enabled is true, this item is set to handle all events for
all its children (i.e., all events intented for any of its
children are instead sent to this item); otherwise, if \a enabled
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index 72c4830..a307622 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -216,6 +216,9 @@ public:
bool acceptTouchEvents() const;
void setAcceptTouchEvents(bool enabled);
+ bool filtersChildEvents() const;
+ void setFiltersChildEvents(bool enabled);
+
bool handlesChildEvents() const;
void setHandlesChildEvents(bool enabled);
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 9bdd273..4729634 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -109,7 +109,8 @@ public:
NoFlag = 0,
AncestorHandlesChildEvents = 0x1,
AncestorClipsChildren = 0x2,
- AncestorIgnoresTransformations = 0x4
+ AncestorIgnoresTransformations = 0x4,
+ AncestorFiltersChildEvents = 0x8
};
inline QGraphicsItemPrivate()
@@ -157,6 +158,7 @@ public:
ignoreOpacity(0),
acceptTouchEvents(0),
acceptedTouchBeginEvent(0),
+ filtersDescendantEvents(0),
sceneTransformTranslateOnly(0),
globalStackingOrder(-1),
q_ptr(0)
@@ -421,7 +423,7 @@ public:
quint32 handlesChildEvents : 1;
quint32 itemDiscovered : 1;
quint32 hasCursor : 1;
- quint32 ancestorFlags : 3;
+ quint32 ancestorFlags : 4;
quint32 cacheMode : 2;
quint32 hasBoundingRegionGranularity : 1;
quint32 isWidget : 1;
@@ -433,13 +435,13 @@ public:
quint32 inSetPosHelper : 1;
quint32 needSortChildren : 1;
quint32 allChildrenDirty : 1;
- quint32 fullUpdatePending : 1;
// New 32 bits
- quint32 flags : 13;
+ quint32 fullUpdatePending : 1;
+ quint32 flags : 12;
quint32 dirtyChildrenBoundingRect : 1;
quint32 paintedViewBoundingRectsNeedRepaint : 1;
- quint32 dirtySceneTransform : 1;
+ quint32 dirtySceneTransform : 1;
quint32 geometryChanged : 1;
quint32 inDestructor : 1;
quint32 isObject : 1;
@@ -447,8 +449,9 @@ public:
quint32 ignoreOpacity : 1;
quint32 acceptTouchEvents : 1;
quint32 acceptedTouchBeginEvent : 1;
+ quint32 filtersDescendantEvents : 1;
quint32 sceneTransformTranslateOnly : 1;
- quint32 unused : 8; // feel free to use
+ quint32 unused : 7; // feel free to use
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 48d8788..06333ae 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -851,6 +851,24 @@ void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGrap
}
/*!
+ \internal
+*/
+bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event)
+{
+ if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) {
+ QGraphicsItem *parent = item->parentItem();
+ while (parent) {
+ if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
+ return true;
+ if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents))
+ return false;
+ parent = parent->parentItem();
+ }
+ }
+ return false;
+}
+
+/*!
\internal
*/
bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
@@ -882,7 +900,9 @@ bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
{
if (filterEvent(item, event))
return false;
- return (item && item->isEnabled()) ? item->sceneEvent(event) : false;
+ if (filterDescendantEvent(item, event))
+ return false;
+ return (item && item->isEnabled() ? item->sceneEvent(event) : false);
}
/*!
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index ffd62d5..9a91acc 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -172,6 +172,7 @@ public:
QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters;
void installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter);
void removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter);
+ bool filterDescendantEvent(QGraphicsItem *item, QEvent *event);
bool filterEvent(QGraphicsItem *item, QEvent *event);
bool sendEvent(QGraphicsItem *item, QEvent *event);
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index 96ee070..3f41a90 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -182,6 +182,8 @@ private slots:
void handlesChildEvents();
void handlesChildEvents2();
void handlesChildEvents3();
+ void filtersChildEvents();
+ void filtersChildEvents2();
void ensureVisible();
void cursor();
//void textControlGetterSetter();
@@ -3406,6 +3408,127 @@ void tst_QGraphicsItem::handlesChildEvents3()
QCOMPARE(group2->counter, 3);
}
+
+class ChildEventFilterTester : public ChildEventTester
+{
+public:
+ ChildEventFilterTester(const QRectF &rect, QGraphicsItem *parent = 0)
+ : ChildEventTester(rect, parent), filter(QEvent::None)
+ { }
+
+ QEvent::Type filter;
+
+protected:
+ bool sceneEventFilter(QGraphicsItem *item, QEvent *event)
+ {
+ Q_UNUSED(item);
+ if (event->type() == filter) {
+ ++counter;
+ return true;
+ }
+ return false;
+ }
+};
+
+void tst_QGraphicsItem::filtersChildEvents()
+{
+ QGraphicsScene scene;
+ ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
+ ChildEventFilterTester *filter = new ChildEventFilterTester(QRectF(10, 10, 10, 10), root);
+ ChildEventTester *child = new ChildEventTester(QRectF(20, 20, 10, 10), filter);
+
+ // setup filter
+ filter->setFiltersChildEvents(true);
+ filter->filter = QEvent::GraphicsSceneMousePress;
+
+ scene.addItem(root);
+
+ QGraphicsView view(&scene);
+ view.show();
+
+ QTest::qWait(1000);
+
+ QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+ QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
+
+ // send event to child
+ pressEvent.setButton(Qt::LeftButton);
+ pressEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
+ pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+ releaseEvent.setButton(Qt::LeftButton);
+ releaseEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
+ releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+ QApplication::sendEvent(&scene, &pressEvent);
+ QApplication::sendEvent(&scene, &releaseEvent);
+
+ QCOMPARE(child->counter, 1); // mouse release is not filtered
+ QCOMPARE(filter->counter, 1); // mouse press is filtered
+ QCOMPARE(root->counter, 0);
+
+ // add another filter
+ root->setFiltersChildEvents(true);
+ root->filter = QEvent::GraphicsSceneMouseRelease;
+
+ // send event to child
+ QApplication::sendEvent(&scene, &pressEvent);
+ QApplication::sendEvent(&scene, &releaseEvent);
+
+ QCOMPARE(child->counter, 1);
+ QCOMPARE(filter->counter, 2); // mouse press is filtered
+ QCOMPARE(root->counter, 1); // mouse release is filtered
+
+ // reparent to another sub-graph
+ ChildEventTester *parent = new ChildEventTester(QRectF(10, 10, 10, 10), root);
+ child->setParentItem(parent);
+
+ // send event to child
+ QApplication::sendEvent(&scene, &pressEvent);
+ QApplication::sendEvent(&scene, &releaseEvent);
+
+ QCOMPARE(child->counter, 2); // mouse press is _not_ filtered
+ QCOMPARE(parent->counter, 0);
+ QCOMPARE(filter->counter, 2);
+ QCOMPARE(root->counter, 2); // mouse release is filtered
+}
+
+void tst_QGraphicsItem::filtersChildEvents2()
+{
+ ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
+ root->setFiltersChildEvents(true);
+ root->filter = QEvent::GraphicsSceneMousePress;
+ QVERIFY(root->filtersChildEvents());
+
+ ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
+ QVERIFY(!child->filtersChildEvents());
+
+ ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10));
+ ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2);
+ ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3);
+
+ child2->setParentItem(root);
+ QVERIFY(!child2->filtersChildEvents());
+ QVERIFY(!child3->filtersChildEvents());
+ QVERIFY(!child4->filtersChildEvents());
+
+ QGraphicsScene scene;
+ scene.addItem(root);
+
+ QGraphicsView view(&scene);
+ view.show();
+
+ QTestEventLoop::instance().enterLoop(1);
+
+ QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
+ view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
+ QApplication::sendEvent(view.viewport(), &event);
+
+ QCOMPARE(child->counter, 0);
+ QCOMPARE(child2->counter, 0);
+ QCOMPARE(child3->counter, 0);
+ QCOMPARE(child4->counter, 0);
+ QCOMPARE(root->counter, 1);
+}
+
class CustomItem : public QGraphicsItem
{
public: