tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,9588 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <private/qtextcontrol_p.h>
+#include <private/qgraphicsitem_p.h>
+#include <private/qgraphicsview_p.h>
+#include <QStyleOptionGraphicsItem>
+#include <QAbstractTextDocumentLayout>
+#include <QBitmap>
+#include <QCursor>
+#include <QLabel>
+#include <QDial>
+#include <QGraphicsItem>
+#include <QGraphicsScene>
+#include <QGraphicsSceneEvent>
+#include <QGraphicsView>
+#include <QGraphicsWidget>
+#include <QGraphicsProxyWidget>
+#include <QPainter>
+#include <QScrollBar>
+#include <QVBoxLayout>
+#include <QGraphicsEffect>
+
+#include "../../shared/util.h"
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<QRectF>)
+Q_DECLARE_METATYPE(QPainterPath)
+Q_DECLARE_METATYPE(QPointF)
+Q_DECLARE_METATYPE(QRectF)
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+#include <windows.h>
+#define Q_CHECK_PAINTEVENTS \
+    if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \
+        QSKIP("The Graphics View doesn't get the paint events", SkipSingle);
+#else
+#define Q_CHECK_PAINTEVENTS
+#endif
+
+#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
+// On mac (cocoa) we always get full update.
+// So check that the expected region is contained inside the actual
+#define COMPARE_REGIONS(ACTUAL, EXPECTED) QVERIFY((EXPECTED).subtracted(ACTUAL).isEmpty())
+#else
+#define COMPARE_REGIONS QTRY_COMPARE
+#endif
+
+static void sendMousePress(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
+{
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+    event.setScenePos(point);
+    event.setButton(button);
+    event.setButtons(button);
+    QApplication::sendEvent(scene, &event);
+}
+
+static void sendMouseMove(QGraphicsScene *scene, const QPointF &point,
+                          Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons buttons = 0)
+{
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+    event.setScenePos(point);
+    event.setButton(button);
+    event.setButtons(button);
+    QApplication::sendEvent(scene, &event);
+}
+
+static void sendMouseRelease(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
+{
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
+    event.setScenePos(point);
+    event.setButton(button);
+    QApplication::sendEvent(scene, &event);
+}
+
+static void sendMouseClick(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
+{
+    sendMousePress(scene, point, button);
+    sendMouseRelease(scene, point, button);
+}
+
+static void sendKeyPress(QGraphicsScene *scene, Qt::Key key)
+{
+    QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier);
+    QApplication::sendEvent(scene, &keyEvent);
+}
+
+static void sendKeyRelease(QGraphicsScene *scene, Qt::Key key)
+{
+    QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier);
+    QApplication::sendEvent(scene, &keyEvent);
+}
+
+static void sendKeyClick(QGraphicsScene *scene, Qt::Key key)
+{
+    sendKeyPress(scene, key);
+    sendKeyRelease(scene, key);
+}
+
+class EventSpy : public QGraphicsWidget
+{
+    Q_OBJECT
+public:
+    EventSpy(QObject *watched, QEvent::Type type)
+        : _count(0), spied(type)
+    {
+        watched->installEventFilter(this);
+    }
+
+    EventSpy(QGraphicsScene *scene, QGraphicsItem *watched, QEvent::Type type)
+        : _count(0), spied(type)
+    {
+        scene->addItem(this);
+        watched->installSceneEventFilter(this);
+    }
+
+    int count() const { return _count; }
+
+protected:
+    bool eventFilter(QObject *watched, QEvent *event)
+    {
+        Q_UNUSED(watched);
+        if (event->type() == spied)
+            ++_count;
+        return false;
+    }
+
+    bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+    {
+        Q_UNUSED(watched);
+        if (event->type() == spied)
+            ++_count;
+        return false;
+    }
+
+    int _count;
+    QEvent::Type spied;
+};
+
+class EventSpy2 : public QGraphicsWidget
+{
+    Q_OBJECT
+public:
+    EventSpy2(QObject *watched)
+    {
+        watched->installEventFilter(this);
+    }
+
+    EventSpy2(QGraphicsScene *scene, QGraphicsItem *watched)
+    {
+        scene->addItem(this);
+        watched->installSceneEventFilter(this);
+    }
+
+    QMap<QEvent::Type, int> counts;
+
+protected:
+    bool eventFilter(QObject *watched, QEvent *event)
+    {
+        Q_UNUSED(watched);
+        ++counts[event->type()];
+        return false;
+    }
+
+    bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+    {
+        Q_UNUSED(watched);
+        ++counts[event->type()];
+        return false;
+    }
+};
+
+class EventTester : public QGraphicsItem
+{
+public:
+    EventTester(QGraphicsItem *parent = 0) : QGraphicsItem(parent), repaints(0)
+    { br = QRectF(-10, -10, 20, 20); }
+
+    void setGeometry(const QRectF &rect)
+    {
+        prepareGeometryChange();
+        br = rect;
+        update();
+    }
+
+    QRectF boundingRect() const
+    { return br; }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+    {
+        hints = painter->renderHints();
+        painter->drawRect(boundingRect());
+        ++repaints;
+    }
+
+    bool sceneEvent(QEvent *event)
+    {
+        events << event->type();
+        return QGraphicsItem::sceneEvent(event);
+    }
+
+    QList<QEvent::Type> events;
+    QPainter::RenderHints hints;
+    int repaints;
+    QRectF br;
+};
+
+class tst_QGraphicsItem : public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void init();
+
+private slots:
+    void construction();
+    void constructionWithParent();
+    void destruction();
+    void deleteChildItem();
+    void scene();
+    void parentItem();
+    void setParentItem();
+    void children();
+    void flags();
+    void inputMethodHints();
+    void toolTip();
+    void visible();
+    void explicitlyVisible();
+    void enabled();
+    void explicitlyEnabled();
+    void selected();
+    void selected2();
+    void selected_group();
+    void selected_textItem();
+    void selected_multi();
+    void acceptedMouseButtons();
+    void acceptsHoverEvents();
+    void childAcceptsHoverEvents();
+    void hasFocus();
+    void pos();
+    void scenePos();
+    void matrix();
+    void sceneMatrix();
+    void setMatrix();
+    void zValue();
+    void shape();
+    void contains();
+    void collidesWith_item();
+    void collidesWith_path_data();
+    void collidesWith_path();
+    void collidesWithItemWithClip();
+    void isObscuredBy();
+    void isObscured();
+    void mapFromToParent();
+    void mapFromToScene();
+    void mapFromToItem();
+    void mapRectFromToParent_data();
+    void mapRectFromToParent();
+    void isAncestorOf();
+    void commonAncestorItem();
+    void data();
+    void type();
+    void graphicsitem_cast();
+    void hoverEventsGenerateRepaints();
+    void boundingRects_data();
+    void boundingRects();
+    void boundingRects2();
+    void sceneBoundingRect();
+    void childrenBoundingRect();
+    void childrenBoundingRectTransformed();
+    void childrenBoundingRect2();
+    void childrenBoundingRect3();
+    void group();
+    void setGroup();
+    void nestedGroups();
+    void warpChildrenIntoGroup();
+    void removeFromGroup();
+    void handlesChildEvents();
+    void handlesChildEvents2();
+    void handlesChildEvents3();
+    void filtersChildEvents();
+    void filtersChildEvents2();
+    void ensureVisible();
+    void cursor();
+    //void textControlGetterSetter();
+    void defaultItemTest_QGraphicsLineItem();
+    void defaultItemTest_QGraphicsPixmapItem();
+    void defaultItemTest_QGraphicsTextItem();
+    void defaultItemTest_QGraphicsEllipseItem();
+    void itemChange();
+    void sceneEventFilter();
+    void prepareGeometryChange();
+    void paint();
+    void deleteItemInEventHandlers();
+    void itemClipsToShape();
+    void itemClipsChildrenToShape();
+    void itemClipsChildrenToShape2();
+    void itemClipsChildrenToShape3();
+    void itemClipsChildrenToShape4();
+    void itemClipsTextChildToShape();
+    void itemClippingDiscovery();
+    void ancestorFlags();
+    void untransformable();
+    void contextMenuEventPropagation();
+    void itemIsMovable();
+    void boundingRegion_data();
+    void boundingRegion();
+    void itemTransform_parentChild();
+    void itemTransform_siblings();
+    void itemTransform_unrelated();
+    void opacity_data();
+    void opacity();
+    void opacity2();
+    void opacityZeroUpdates();
+    void itemStacksBehindParent();
+    void nestedClipping();
+    void nestedClippingTransforms();
+    void sceneTransformCache();
+    void tabChangesFocus();
+    void tabChangesFocus_data();
+    void cacheMode();
+    void updateCachedItemAfterMove();
+    void deviceTransform_data();
+    void deviceTransform();
+    void update();
+    void setTransformProperties_data();
+    void setTransformProperties();
+    void itemUsesExtendedStyleOption();
+    void itemSendsGeometryChanges();
+    void moveItem();
+    void sorting_data();
+    void sorting();
+    void itemHasNoContents();
+    void hitTestUntransformableItem();
+    void hitTestGraphicsEffectItem();
+    void focusProxy();
+    void subFocus();
+    void focusProxyDeletion();
+    void negativeZStacksBehindParent();
+    void setGraphicsEffect();
+    void panel();
+    void addPanelToActiveScene();
+    void activate();
+    void setActivePanelOnInactiveScene();
+    void activationOnShowHide();
+    void moveWhileDeleting();
+    void ensureDirtySceneTransform();
+    void focusScope();
+    void stackBefore();
+    void sceneModality();
+    void panelModality();
+    void mixedModality();
+    void modality_hover();
+    void modality_mouseGrabber();
+    void modality_clickFocus();
+    void modality_keyEvents();
+    void itemIsInFront();
+
+    // task specific tests below me
+    void task141694_textItemEnsureVisible();
+    void task128696_textItemEnsureMovable();
+    void ensureUpdateOnTextItem();
+    void task177918_lineItemUndetected();
+    void task240400_clickOnTextItem_data();
+    void task240400_clickOnTextItem();
+    void task243707_addChildBeforeParent();
+    void task197802_childrenVisibility();
+    void QTBUG_4233_updateCachedWithSceneRect();
+
+private:
+    QList<QGraphicsItem *> paintedItems;
+};
+
+void tst_QGraphicsItem::init()
+{
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+    qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+void tst_QGraphicsItem::construction()
+{
+    for (int i = 0; i < 7; ++i) {
+        QGraphicsItem *item;
+        switch (i) {
+        case 0:
+            item = new QGraphicsEllipseItem;
+            QCOMPARE(int(item->type()), int(QGraphicsEllipseItem::Type));
+            QCOMPARE(qgraphicsitem_cast<QGraphicsEllipseItem *>(item), (QGraphicsEllipseItem *)item);
+            QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
+            QCOMPARE(item->flags(), 0);
+            break;
+        case 1:
+            item = new QGraphicsLineItem;
+            QCOMPARE(int(item->type()), int(QGraphicsLineItem::Type));
+            QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)item);
+            QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
+            QCOMPARE(item->flags(), 0);
+            break;
+        case 2:
+            item = new QGraphicsPathItem;
+            QCOMPARE(int(item->type()), int(QGraphicsPathItem::Type));
+            QCOMPARE(qgraphicsitem_cast<QGraphicsPathItem *>(item), (QGraphicsPathItem *)item);
+            QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
+            QCOMPARE(item->flags(), 0);
+            break;
+        case 3:
+            item = new QGraphicsPixmapItem;
+            QCOMPARE(int(item->type()), int(QGraphicsPixmapItem::Type));
+            QCOMPARE(qgraphicsitem_cast<QGraphicsPixmapItem *>(item), (QGraphicsPixmapItem *)item);
+            QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
+            QCOMPARE(item->flags(), 0);
+            break;
+        case 4:
+            item = new QGraphicsPolygonItem;
+            QCOMPARE(int(item->type()), int(QGraphicsPolygonItem::Type));
+            QCOMPARE(qgraphicsitem_cast<QGraphicsPolygonItem *>(item), (QGraphicsPolygonItem *)item);
+            QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
+            QCOMPARE(item->flags(), 0);
+            break;
+        case 5:
+            item = new QGraphicsRectItem;
+            QCOMPARE(int(item->type()), int(QGraphicsRectItem::Type));
+            QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)item);
+            QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)0);
+            QCOMPARE(item->flags(), 0);
+            break;
+        case 6:
+            item = new QGraphicsTextItem;
+            QCOMPARE(int(item->type()), int(QGraphicsTextItem::Type));
+            QCOMPARE(qgraphicsitem_cast<QGraphicsTextItem *>(item), (QGraphicsTextItem *)item);
+            QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
+            // This is the only item that uses an extended style option.
+            QCOMPARE(item->flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
+            break;
+        default:
+            qFatal("You broke the logic, please fix!");
+            break;
+        }
+
+        QCOMPARE(item->scene(), (QGraphicsScene *)0);
+        QCOMPARE(item->parentItem(), (QGraphicsItem *)0);
+        QVERIFY(item->children().isEmpty());
+        QVERIFY(item->isVisible());
+        QVERIFY(item->isEnabled());
+        QVERIFY(!item->isSelected());
+        QCOMPARE(item->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
+        if (item->type() == QGraphicsTextItem::Type)
+            QVERIFY(item->acceptsHoverEvents());
+        else
+            QVERIFY(!item->acceptsHoverEvents());
+        QVERIFY(!item->hasFocus());
+        QCOMPARE(item->pos(), QPointF());
+        QCOMPARE(item->matrix(), QMatrix());
+        QCOMPARE(item->sceneMatrix(), QMatrix());
+        QCOMPARE(item->zValue(), qreal(0));
+        QCOMPARE(item->sceneBoundingRect(), QRectF());
+        QCOMPARE(item->shape(), QPainterPath());
+        QVERIFY(!item->contains(QPointF(0, 0)));
+        QVERIFY(!item->collidesWithItem(0));
+        QVERIFY(item->collidesWithItem(item));
+        QVERIFY(!item->collidesWithPath(QPainterPath()));
+        QVERIFY(!item->isAncestorOf(0));
+        QVERIFY(!item->isAncestorOf(item));
+        QCOMPARE(item->data(0), QVariant());
+        delete item;
+    }
+}
+
+class BoundingRectItem : public QGraphicsRectItem
+{
+public:
+    BoundingRectItem(QGraphicsItem *parent = 0)
+        : QGraphicsRectItem(0, 0, parent ? 200 : 100, parent ? 200 : 100,
+                            parent)
+    {}
+
+    QRectF boundingRect() const
+    {
+        QRectF tmp = QGraphicsRectItem::boundingRect();
+        foreach (QGraphicsItem *child, children())
+            tmp |= child->boundingRect(); // <- might be pure virtual
+        return tmp;
+    }
+};
+
+void tst_QGraphicsItem::constructionWithParent()
+{
+    // This test causes a crash if item1 calls item2's pure virtuals before the
+    // object has been constructed.
+    QGraphicsItem *item0 = new BoundingRectItem;
+    QGraphicsItem *item1 = new BoundingRectItem;
+    QGraphicsScene scene;
+    scene.addItem(item0);
+    scene.addItem(item1);
+    QGraphicsItem *item2 = new BoundingRectItem(item1);
+    QCOMPARE(item1->children(), QList<QGraphicsItem *>() << item2);
+    QCOMPARE(item1->boundingRect(), QRectF(0, 0, 200, 200));
+
+    item2->setParentItem(item0);
+    QCOMPARE(item0->children(), QList<QGraphicsItem *>() << item2);
+    QCOMPARE(item0->boundingRect(), QRectF(0, 0, 200, 200));
+}
+
+static int itemDeleted = 0;
+class Item : public QGraphicsRectItem
+{
+public:
+    ~Item()
+    { ++itemDeleted; }
+};
+
+void tst_QGraphicsItem::destruction()
+{
+    QCOMPARE(itemDeleted, 0);
+    {
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        QCOMPARE(child->parentItem(), parent);
+        delete parent;
+        QCOMPARE(itemDeleted, 1);
+    }
+    {
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        QCOMPARE(parent->children().size(), 1);
+        delete child;
+        QCOMPARE(parent->children().size(), 0);
+        delete parent;
+        QCOMPARE(itemDeleted, 2);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
+        child->setParentItem(parent);
+        QCOMPARE(child->parentItem(), parent);
+        scene.addItem(parent);
+        QCOMPARE(child->parentItem(), parent);
+        delete parent;
+        QCOMPARE(itemDeleted, 3);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        scene.addItem(parent);
+        QCOMPARE(child->scene(), &scene);
+        QCOMPARE(parent->children().size(), 1);
+        delete child;
+        QCOMPARE(parent->children().size(), 0);
+        delete parent;
+        QCOMPARE(itemDeleted, 4);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        scene.addItem(parent);
+        QCOMPARE(child->scene(), &scene);
+        scene.removeItem(parent);
+        QCOMPARE(child->scene(), (QGraphicsScene *)0);
+        delete parent;
+        QCOMPARE(itemDeleted, 5);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        QCOMPARE(child->scene(), (QGraphicsScene *)0);
+        QCOMPARE(parent->scene(), (QGraphicsScene *)0);
+        scene.addItem(parent);
+        QCOMPARE(child->scene(), &scene);
+        scene.removeItem(child);
+        QCOMPARE(child->scene(), (QGraphicsScene *)0);
+        QCOMPARE(parent->scene(), &scene);
+        QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
+        QVERIFY(parent->children().isEmpty());
+        delete parent;
+        QCOMPARE(itemDeleted, 5);
+        delete child;
+        QCOMPARE(itemDeleted, 6);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        scene.addItem(parent);
+        scene.removeItem(child);
+        scene.removeItem(parent);
+        delete child;
+        delete parent;
+        QCOMPARE(itemDeleted, 7);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        scene.addItem(parent);
+        QGraphicsScene scene2;
+        scene2.addItem(parent);
+        delete parent;
+        QCOMPARE(itemDeleted, 8);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        scene.addItem(parent);
+        QCOMPARE(child->scene(), &scene);
+        QGraphicsScene scene2;
+        scene2.addItem(parent);
+        QCOMPARE(child->scene(), &scene2);
+        scene.addItem(parent);
+        QCOMPARE(child->scene(), &scene);
+        scene2.addItem(parent);
+        QCOMPARE(child->scene(), &scene2);
+        delete parent;
+        QCOMPARE(itemDeleted, 9);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        scene.addItem(parent);
+        QCOMPARE(child->scene(), &scene);
+        QGraphicsScene scene2;
+        scene2.addItem(child);
+        QCOMPARE(child->scene(), &scene2);
+        delete parent;
+        QCOMPARE(itemDeleted, 9);
+        delete child;
+        QCOMPARE(itemDeleted, 10);
+    }
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *root = new QGraphicsRectItem;
+        QGraphicsItem *parent = root;
+        QGraphicsItem *middleItem = 0;
+        for (int i = 0; i < 99; ++i) {
+            Item *child = new Item;
+            child->setParentItem(parent);
+            parent = child;
+            if (i == 50)
+                middleItem = parent;
+        }
+        scene.addItem(root);
+
+        QCOMPARE(scene.items().size(), 100);
+
+        QGraphicsScene scene2;
+        scene2.addItem(middleItem);
+
+        delete middleItem;
+        QCOMPARE(itemDeleted, 59);
+    }
+    QCOMPARE(itemDeleted, 109);
+    {
+        QGraphicsScene *scene = new QGraphicsScene;
+        QGraphicsRectItem *parent = new QGraphicsRectItem;
+        Item *child = new Item;
+        child->setParentItem(parent);
+        parent->setVisible(false);
+        scene->addItem(parent);
+        QCOMPARE(child->parentItem(), static_cast<QGraphicsItem*>(parent));
+        delete scene;
+        QCOMPARE(itemDeleted, 110);
+    }
+}
+
+void tst_QGraphicsItem::deleteChildItem()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *rect = scene.addRect(QRectF());
+    QGraphicsItem *child1 = new QGraphicsRectItem(rect);
+    QGraphicsItem *child2 = new QGraphicsRectItem(rect);
+    QGraphicsItem *child3 = new QGraphicsRectItem(rect);
+    delete child1;
+    child2->setParentItem(0);
+    delete child2;
+}
+
+void tst_QGraphicsItem::scene()
+{
+    QGraphicsRectItem *item = new QGraphicsRectItem;
+    QCOMPARE(item->scene(), (QGraphicsScene *)0);
+
+    QGraphicsScene scene;
+    scene.addItem(item);
+    QCOMPARE(item->scene(), (QGraphicsScene *)&scene);
+
+    QGraphicsScene scene2;
+    scene2.addItem(item);
+    QCOMPARE(item->scene(), (QGraphicsScene *)&scene2);
+
+    scene2.removeItem(item);
+    QCOMPARE(item->scene(), (QGraphicsScene *)0);
+
+    delete item;
+}
+
+void tst_QGraphicsItem::parentItem()
+{
+    QGraphicsRectItem item;
+    QCOMPARE(item.parentItem(), (QGraphicsItem *)0);
+
+    QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
+    QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
+    item2->setParentItem(&item);
+    QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
+    item2->setParentItem(0);
+    QCOMPARE(item2->parentItem(), (QGraphicsItem *)0);
+
+    delete item2;
+}
+
+void tst_QGraphicsItem::setParentItem()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10));
+    QCOMPARE(item->scene(), &scene);
+
+    QGraphicsRectItem *child = new QGraphicsRectItem;
+    QCOMPARE(child->scene(), (QGraphicsScene *)0);
+
+    // This implicitly adds the item to the parent's scene
+    child->setParentItem(item);
+    QCOMPARE(child->scene(), &scene);
+
+    // This just makes it a toplevel
+    child->setParentItem(0);
+    QCOMPARE(child->scene(), &scene);
+
+    // Add the child back to the parent, then remove the parent from the scene
+    child->setParentItem(item);
+    scene.removeItem(item);
+    QCOMPARE(child->scene(), (QGraphicsScene *)0);
+}
+
+void tst_QGraphicsItem::children()
+{
+    QGraphicsRectItem item;
+    QVERIFY(item.children().isEmpty());
+
+    QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
+    QCOMPARE(item.children().size(), 1);
+    QCOMPARE(item.children().first(), (QGraphicsItem *)item2);
+    QVERIFY(item2->children().isEmpty());
+
+    delete item2;
+    QVERIFY(item.children().isEmpty());
+}
+
+void tst_QGraphicsItem::flags()
+{
+    QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
+    QCOMPARE(item->flags(), 0);
+
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    scene.addItem(item);
+
+    {
+        // Focus
+        item->setFlag(QGraphicsItem::ItemIsFocusable, false);
+        QVERIFY(!item->hasFocus());
+        item->setFocus();
+        QVERIFY(!item->hasFocus());
+
+        item->setFlag(QGraphicsItem::ItemIsFocusable, true);
+        QVERIFY(!item->hasFocus());
+        item->setFocus();
+        QVERIFY(item->hasFocus());
+        QVERIFY(scene.hasFocus());
+
+        item->setFlag(QGraphicsItem::ItemIsFocusable, false);
+        QVERIFY(!item->hasFocus());
+        QVERIFY(scene.hasFocus());
+    }
+    {
+        // Selectable
+        item->setFlag(QGraphicsItem::ItemIsSelectable, false);
+        QVERIFY(!item->isSelected());
+        item->setSelected(true);
+        QVERIFY(!item->isSelected());
+
+        item->setFlag(QGraphicsItem::ItemIsSelectable, true);
+        QVERIFY(!item->isSelected());
+        item->setSelected(true);
+        QVERIFY(item->isSelected());
+        item->setFlag(QGraphicsItem::ItemIsSelectable, false);
+        QVERIFY(!item->isSelected());
+    }
+    {
+        // Movable
+        item->setFlag(QGraphicsItem::ItemIsMovable, false);
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+        event.setScenePos(QPointF(0, 0));
+        event.setButton(Qt::LeftButton);
+        event.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); // mouse grabber is reset
+
+        QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
+        event2.setScenePos(QPointF(10, 10));
+        event2.setButton(Qt::LeftButton);
+        event2.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event2);
+        QCOMPARE(item->pos(), QPointF());
+
+        QGraphicsSceneMouseEvent event3(QEvent::GraphicsSceneMouseRelease);
+        event3.setScenePos(QPointF(10, 10));
+        event3.setButtons(0);
+        QApplication::sendEvent(&scene, &event3);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+
+        item->setFlag(QGraphicsItem::ItemIsMovable, true);
+        QGraphicsSceneMouseEvent event4(QEvent::GraphicsSceneMousePress);
+        event4.setScenePos(QPointF(0, 0));
+        event4.setButton(Qt::LeftButton);
+        event4.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event4);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
+        QGraphicsSceneMouseEvent event5(QEvent::GraphicsSceneMouseMove);
+        event5.setScenePos(QPointF(10, 10));
+        event5.setButton(Qt::LeftButton);
+        event5.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event5);
+        QCOMPARE(item->pos(), QPointF(10, 10));
+    }
+    {
+        QGraphicsItem* clippingParent = new QGraphicsRectItem;
+        clippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
+
+        QGraphicsItem* nonClippingParent = new QGraphicsRectItem;
+        nonClippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
+
+        QGraphicsItem* child = new QGraphicsRectItem(nonClippingParent);
+        QVERIFY(!child->isClipped());
+
+        child->setParentItem(clippingParent);
+        QVERIFY(child->isClipped());
+
+        child->setParentItem(nonClippingParent);
+        QVERIFY(!child->isClipped());
+    }
+}
+
+class ImhTester : public QGraphicsItem
+{
+    QRectF boundingRect() const { return QRectF(); }
+    void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
+};
+
+void tst_QGraphicsItem::inputMethodHints()
+{
+    ImhTester item;
+    QCOMPARE(item.inputMethodHints(), Qt::ImhNone);
+}
+
+void tst_QGraphicsItem::toolTip()
+{
+    QString toolTip = "Qt rocks!";
+
+    QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
+    item->setPen(QPen(Qt::red, 1));
+    item->setBrush(QBrush(Qt::blue));
+    QVERIFY(item->toolTip().isEmpty());
+    item->setToolTip(toolTip);
+    QCOMPARE(item->toolTip(), toolTip);
+
+    QGraphicsScene scene;
+    scene.addItem(item);
+
+    QGraphicsView view(&scene);
+    view.setFixedSize(200, 200);
+    view.show();
+    QTest::qWait(250);
+    {
+        QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
+                             view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
+        QApplication::sendEvent(view.viewport(), &helpEvent);
+        QTest::qWait(250);
+
+        bool foundView = false;
+        bool foundTipLabel = false;
+        foreach (QWidget *widget, QApplication::topLevelWidgets()) {
+            if (widget == &view)
+                foundView = true;
+            if (widget->inherits("QTipLabel"))
+                foundTipLabel = true;
+        }
+        QVERIFY(foundView);
+        QVERIFY(!foundTipLabel);
+    }
+
+    {
+        QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().center(),
+                             view.viewport()->mapToGlobal(view.viewport()->rect().center()));
+        QApplication::sendEvent(view.viewport(), &helpEvent);
+        QTest::qWait(250);
+
+        bool foundView = false;
+        bool foundTipLabel = false;
+        foreach (QWidget *widget, QApplication::topLevelWidgets()) {
+            if (widget == &view)
+                foundView = true;
+            if (widget->inherits("QTipLabel"))
+                foundTipLabel = true;
+        }
+        QVERIFY(foundView);
+        QVERIFY(foundTipLabel);
+    }
+
+    {
+        QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
+                             view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
+        QApplication::sendEvent(view.viewport(), &helpEvent);
+        QTest::qWait(1000);
+
+        bool foundView = false;
+        bool foundTipLabel = false;
+        foreach (QWidget *widget, QApplication::topLevelWidgets()) {
+            if (widget == &view)
+                foundView = true;
+            if (widget->inherits("QTipLabel") && widget->isVisible())
+                foundTipLabel = true;
+        }
+        QVERIFY(foundView);
+        QVERIFY(!foundTipLabel);
+    }
+}
+
+void tst_QGraphicsItem::visible()
+{
+    QGraphicsItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
+    item->setFlag(QGraphicsItem::ItemIsMovable);
+    QVERIFY(item->isVisible());
+    item->setVisible(false);
+    QVERIFY(!item->isVisible());
+    item->setVisible(true);
+    QVERIFY(item->isVisible());
+
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    scene.addItem(item);
+    QVERIFY(item->isVisible());
+    QCOMPARE(scene.itemAt(0, 0), item);
+    item->setVisible(false);
+    QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)0);
+    item->setVisible(true);
+    QCOMPARE(scene.itemAt(0, 0), item);
+
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+    event.setButton(Qt::LeftButton);
+    event.setScenePos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &event);
+    QCOMPARE(scene.mouseGrabberItem(), item);
+    item->setVisible(false);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+    item->setVisible(true);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+
+    item->setFlag(QGraphicsItem::ItemIsFocusable);
+    item->setFocus();
+    QVERIFY(item->hasFocus());
+    item->setVisible(false);
+    QVERIFY(!item->hasFocus());
+    item->setVisible(true);
+    QVERIFY(!item->hasFocus());
+}
+
+void tst_QGraphicsItem::explicitlyVisible()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
+    child->setParentItem(parent);
+
+    QVERIFY(parent->isVisible());
+    QVERIFY(child->isVisible());
+
+    parent->hide();
+
+    QVERIFY(!parent->isVisible());
+    QVERIFY(!child->isVisible());
+
+    parent->show();
+    child->hide();
+
+    QVERIFY(parent->isVisible());
+    QVERIFY(!child->isVisible());
+
+    parent->hide();
+
+    QVERIFY(!parent->isVisible());
+    QVERIFY(!child->isVisible());
+
+    parent->show();
+
+    QVERIFY(parent->isVisible());
+    QVERIFY(!child->isVisible()); // <- explicitly hidden
+
+    child->show();
+
+    QVERIFY(child->isVisible());
+
+    parent->hide();
+
+    QVERIFY(!parent->isVisible());
+    QVERIFY(!child->isVisible()); // <- explicit show doesn't work
+
+    parent->show();
+
+    QVERIFY(parent->isVisible());
+    QVERIFY(child->isVisible()); // <- no longer explicitly hidden
+
+    // ------------------- Reparenting ------------------------------
+
+    QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
+    QVERIFY(parent2->isVisible());
+
+    // Reparent implicitly hidden item to a visible parent.
+    parent->hide();
+    QVERIFY(!parent->isVisible());
+    QVERIFY(!child->isVisible());
+    child->setParentItem(parent2);
+    QVERIFY(parent2->isVisible());
+    QVERIFY(child->isVisible());
+
+    // Reparent implicitly hidden item to a hidden parent.
+    child->setParentItem(parent);
+    parent2->hide();
+    child->setParentItem(parent2);
+    QVERIFY(!parent2->isVisible());
+    QVERIFY(!child->isVisible());
+
+    // Reparent explicitly hidden item to a visible parent.
+    child->hide();
+    parent->show();
+    child->setParentItem(parent);
+    QVERIFY(parent->isVisible());
+    QVERIFY(!child->isVisible());
+
+    // Reparent explicitly hidden item to a hidden parent.
+    child->setParentItem(parent2);
+    QVERIFY(!parent2->isVisible());
+    QVERIFY(!child->isVisible());
+
+    // Reparent explicitly hidden item to a visible parent.
+    parent->show();
+    child->setParentItem(parent);
+    QVERIFY(parent->isVisible());
+    QVERIFY(!child->isVisible());
+
+    // Reparent visible item to a hidden parent.
+    child->show();
+    parent2->hide();
+    child->setParentItem(parent2);
+    QVERIFY(!parent2->isVisible());
+    QVERIFY(!child->isVisible());
+    parent2->show();
+    QVERIFY(parent2->isVisible());
+    QVERIFY(child->isVisible());
+
+    // Reparent implicitly hidden child to root.
+    parent2->hide();
+    QVERIFY(!child->isVisible());
+    child->setParentItem(0);
+    QVERIFY(child->isVisible());
+
+    // Reparent an explicitly hidden child to root.
+    child->hide();
+    child->setParentItem(parent2);
+    parent2->show();
+    QVERIFY(!child->isVisible());
+    child->setParentItem(0);
+    QVERIFY(!child->isVisible());
+}
+
+void tst_QGraphicsItem::enabled()
+{
+    QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
+    item->setFlag(QGraphicsItem::ItemIsMovable);
+    QVERIFY(item->isEnabled());
+    item->setEnabled(false);
+    QVERIFY(!item->isEnabled());
+    item->setEnabled(true);
+    QVERIFY(item->isEnabled());
+    item->setEnabled(false);
+    item->setFlag(QGraphicsItem::ItemIsFocusable);
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    scene.addItem(item);
+    item->setFocus();
+    QVERIFY(!item->hasFocus());
+    item->setEnabled(true);
+    item->setFocus();
+    QVERIFY(item->hasFocus());
+    item->setEnabled(false);
+    QVERIFY(!item->hasFocus());
+
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+    event.setButton(Qt::LeftButton);
+    event.setScenePos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &event);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+    item->setEnabled(true);
+    QApplication::sendEvent(&scene, &event);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
+    item->setEnabled(false);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsItem::explicitlyEnabled()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
+    child->setParentItem(parent);
+
+    QVERIFY(parent->isEnabled());
+    QVERIFY(child->isEnabled());
+
+    parent->setEnabled(false);
+
+    QVERIFY(!parent->isEnabled());
+    QVERIFY(!child->isEnabled());
+
+    parent->setEnabled(true);
+    child->setEnabled(false);
+
+    QVERIFY(parent->isEnabled());
+    QVERIFY(!child->isEnabled());
+
+    parent->setEnabled(false);
+
+    QVERIFY(!parent->isEnabled());
+    QVERIFY(!child->isEnabled());
+
+    parent->setEnabled(true);
+
+    QVERIFY(parent->isEnabled());
+    QVERIFY(!child->isEnabled()); // <- explicitly disabled
+
+    child->setEnabled(true);
+
+    QVERIFY(child->isEnabled());
+
+    parent->setEnabled(false);
+
+    QVERIFY(!parent->isEnabled());
+    QVERIFY(!child->isEnabled()); // <- explicit enabled doesn't work
+
+    parent->setEnabled(true);
+
+    QVERIFY(parent->isEnabled());
+    QVERIFY(child->isEnabled()); // <- no longer explicitly disabled
+
+    // ------------------- Reparenting ------------------------------
+
+    QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
+    QVERIFY(parent2->isEnabled());
+
+    // Reparent implicitly hidden item to a enabled parent.
+    parent->setEnabled(false);
+    QVERIFY(!parent->isEnabled());
+    QVERIFY(!child->isEnabled());
+    child->setParentItem(parent2);
+    QVERIFY(parent2->isEnabled());
+    QVERIFY(child->isEnabled());
+
+    // Reparent implicitly hidden item to a hidden parent.
+    child->setParentItem(parent);
+    parent2->setEnabled(false);
+    child->setParentItem(parent2);
+    QVERIFY(!parent2->isEnabled());
+    QVERIFY(!child->isEnabled());
+
+    // Reparent explicitly hidden item to a enabled parent.
+    child->setEnabled(false);
+    parent->setEnabled(true);
+    child->setParentItem(parent);
+    QVERIFY(parent->isEnabled());
+    QVERIFY(!child->isEnabled());
+
+    // Reparent explicitly hidden item to a hidden parent.
+    child->setParentItem(parent2);
+    QVERIFY(!parent2->isEnabled());
+    QVERIFY(!child->isEnabled());
+
+    // Reparent explicitly hidden item to a enabled parent.
+    parent->setEnabled(true);
+    child->setParentItem(parent);
+    QVERIFY(parent->isEnabled());
+    QVERIFY(!child->isEnabled());
+
+    // Reparent enabled item to a hidden parent.
+    child->setEnabled(true);
+    parent2->setEnabled(false);
+    child->setParentItem(parent2);
+    QVERIFY(!parent2->isEnabled());
+    QVERIFY(!child->isEnabled());
+    parent2->setEnabled(true);
+    QVERIFY(parent2->isEnabled());
+    QVERIFY(child->isEnabled());
+
+    // Reparent implicitly hidden child to root.
+    parent2->setEnabled(false);
+    QVERIFY(!child->isEnabled());
+    child->setParentItem(0);
+    QVERIFY(child->isEnabled());
+
+    // Reparent an explicitly hidden child to root.
+    child->setEnabled(false);
+    child->setParentItem(parent2);
+    parent2->setEnabled(true);
+    QVERIFY(!child->isEnabled());
+    child->setParentItem(0);
+    QVERIFY(!child->isEnabled());
+}
+
+class SelectChangeItem : public QGraphicsRectItem
+{
+public:
+    SelectChangeItem() : QGraphicsRectItem(-50, -50, 100, 100) { setBrush(Qt::blue); }
+    QList<bool> values;
+
+protected:
+    QVariant itemChange(GraphicsItemChange change, const QVariant &value)
+    {
+        if (change == ItemSelectedChange)
+            values << value.toBool();
+        return QGraphicsRectItem::itemChange(change, value);
+    }
+};
+
+void tst_QGraphicsItem::selected()
+{
+    SelectChangeItem *item = new SelectChangeItem;
+    item->setFlag(QGraphicsItem::ItemIsSelectable);
+    QVERIFY(!item->isSelected());
+    QVERIFY(item->values.isEmpty());
+    item->setSelected(true);
+    QCOMPARE(item->values.size(), 1);
+    QCOMPARE(item->values.last(), true);
+    QVERIFY(item->isSelected());
+    item->setSelected(false);
+    QCOMPARE(item->values.size(), 2);
+    QCOMPARE(item->values.last(), false);
+    QVERIFY(!item->isSelected());
+    item->setSelected(true);
+    QCOMPARE(item->values.size(), 3);
+    item->setEnabled(false);
+    QCOMPARE(item->values.size(), 4);
+    QCOMPARE(item->values.last(), false);
+    QVERIFY(!item->isSelected());
+    item->setEnabled(true);
+    QCOMPARE(item->values.size(), 4);
+    item->setSelected(true);
+    QCOMPARE(item->values.size(), 5);
+    QCOMPARE(item->values.last(), true);
+    QVERIFY(item->isSelected());
+    item->setVisible(false);
+    QCOMPARE(item->values.size(), 6);
+    QCOMPARE(item->values.last(), false);
+    QVERIFY(!item->isSelected());
+    item->setVisible(true);
+    QCOMPARE(item->values.size(), 6);
+    item->setSelected(true);
+    QCOMPARE(item->values.size(), 7);
+    QCOMPARE(item->values.last(), true);
+    QVERIFY(item->isSelected());
+
+    QGraphicsScene scene(-100, -100, 200, 200);
+    scene.addItem(item);
+    QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
+    item->setSelected(false);
+    QVERIFY(scene.selectedItems().isEmpty());
+    item->setSelected(true);
+    QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
+    item->setSelected(false);
+    QVERIFY(scene.selectedItems().isEmpty());
+
+    // Interactive selection
+    QGraphicsView view(&scene);
+    view.setFixedSize(250, 250);
+    view.show();
+
+    qApp->processEvents();
+    qApp->processEvents();
+
+    scene.clearSelection();
+    QCOMPARE(item->values.size(), 10);
+    QCOMPARE(item->values.last(), false);
+    QVERIFY(!item->isSelected());
+
+    // Click inside and check that it's selected
+    QTest::mouseMove(view.viewport());
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
+    QCOMPARE(item->values.size(), 11);
+    QCOMPARE(item->values.last(), true);
+    QVERIFY(item->isSelected());
+
+    // Click outside and check that it's not selected
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos() + QPointF(item->boundingRect().width(), item->boundingRect().height())));
+    QCOMPARE(item->values.size(), 12);
+    QCOMPARE(item->values.last(), false);
+    QVERIFY(!item->isSelected());
+
+    SelectChangeItem *item2 = new SelectChangeItem;
+    item2->setFlag(QGraphicsItem::ItemIsSelectable);
+    item2->setPos(100, 0);
+    scene.addItem(item2);
+
+    // Click inside and check that it's selected
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
+    QCOMPARE(item->values.size(), 13);
+    QCOMPARE(item->values.last(), true);
+    QVERIFY(item->isSelected());
+
+    // Click inside item2 and check that it's selected, and item is not
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
+    QCOMPARE(item->values.size(), 14);
+    QCOMPARE(item->values.last(), false);
+    QVERIFY(!item->isSelected());
+    QCOMPARE(item2->values.size(), 1);
+    QCOMPARE(item2->values.last(), true);
+    QVERIFY(item2->isSelected());
+}
+
+void tst_QGraphicsItem::selected2()
+{
+    // Selecting an item, then moving another previously caused a crash.
+    QGraphicsScene scene;
+    QGraphicsItem *line1 = scene.addRect(QRectF(0, 0, 100, 100));
+    line1->setPos(-105, 0);
+    line1->setFlag(QGraphicsItem::ItemIsSelectable);
+
+    QGraphicsItem *line2 = scene.addRect(QRectF(0, 0, 100, 100));
+    line2->setFlag(QGraphicsItem::ItemIsMovable);
+
+    line1->setSelected(true);
+
+    {
+        QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
+        mousePress.setScenePos(QPointF(50, 50));
+        mousePress.setButton(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &mousePress);
+        QVERIFY(mousePress.isAccepted());
+    }
+    {
+        QGraphicsSceneMouseEvent mouseMove(QEvent::GraphicsSceneMouseMove);
+        mouseMove.setScenePos(QPointF(60, 60));
+        mouseMove.setButton(Qt::LeftButton);
+        mouseMove.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &mouseMove);
+        QVERIFY(mouseMove.isAccepted());
+    }
+}
+
+void tst_QGraphicsItem::selected_group()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *item1 = scene.addRect(QRectF());
+    QGraphicsItem *item2 = scene.addRect(QRectF());
+    item1->setFlag(QGraphicsItem::ItemIsSelectable);
+    item2->setFlag(QGraphicsItem::ItemIsSelectable);
+    scene.addRect(QRectF())->setParentItem(item1);
+    QGraphicsItem *leaf = scene.addRect(QRectF());
+    leaf->setFlag(QGraphicsItem::ItemIsSelectable);
+    leaf->setParentItem(item2);
+
+    QGraphicsItemGroup *group = scene.createItemGroup(QList<QGraphicsItem *>() << item1 << item2);
+    QCOMPARE(group->scene(), &scene);
+    group->setFlag(QGraphicsItem::ItemIsSelectable);
+    foreach (QGraphicsItem *item, scene.items()) {
+        if (item == group)
+            QVERIFY(!item->group());
+        else
+            QCOMPARE(item->group(), group);
+    }
+
+    QVERIFY(group->handlesChildEvents());
+    QVERIFY(!group->isSelected());
+    group->setSelected(false);
+    QVERIFY(!group->isSelected());
+    group->setSelected(true);
+    QVERIFY(group->isSelected());
+    foreach (QGraphicsItem *item, scene.items())
+        QVERIFY(item->isSelected());
+    group->setSelected(false);
+    QVERIFY(!group->isSelected());
+    foreach (QGraphicsItem *item, scene.items())
+        QVERIFY(!item->isSelected());
+    leaf->setSelected(true);
+    foreach (QGraphicsItem *item, scene.items())
+        QVERIFY(item->isSelected());
+    leaf->setSelected(false);
+    foreach (QGraphicsItem *item, scene.items())
+        QVERIFY(!item->isSelected());
+
+    leaf->setSelected(true);
+    QGraphicsScene scene2;
+    scene2.addItem(item1);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(item2->isSelected());
+}
+
+void tst_QGraphicsItem::selected_textItem()
+{
+    QGraphicsScene scene;
+    QGraphicsTextItem *text = scene.addText(QLatin1String("Text"));
+    text->setFlag(QGraphicsItem::ItemIsSelectable);
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(20);
+
+    QTRY_VERIFY(!text->isSelected());
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
+                      view.mapFromScene(text->mapToScene(0, 0)));
+    QTRY_VERIFY(text->isSelected());
+
+    text->setSelected(false);
+    text->setTextInteractionFlags(Qt::TextEditorInteraction);
+
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
+                      view.mapFromScene(text->mapToScene(0, 0)));
+    QTRY_VERIFY(text->isSelected());
+}
+
+void tst_QGraphicsItem::selected_multi()
+{
+    // Test multiselection behavior
+    QGraphicsScene scene;
+
+    // Create two disjoint items
+    QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
+    QGraphicsItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
+    item1->setPos(-15, 0);
+    item2->setPos(15, 20);
+
+    // Make both items selectable
+    item1->setFlag(QGraphicsItem::ItemIsSelectable);
+    item2->setFlag(QGraphicsItem::ItemIsSelectable);
+
+    // Create and show a view
+    QGraphicsView view(&scene);
+    view.show();
+    view.fitInView(scene.sceneRect());
+    qApp->processEvents();
+
+    QVERIFY(!item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Start clicking
+    QTest::qWait(200);
+
+    // Click on item1
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Click on item2
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item2->isSelected());
+    QVERIFY(!item1->isSelected());
+
+    // Ctrl-click on item1
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item2->isSelected());
+    QVERIFY(item1->isSelected());
+
+    // Ctrl-click on item1 again
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item2->isSelected());
+    QVERIFY(!item1->isSelected());
+
+    // Ctrl-click on item2
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item2->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(!item2->isSelected());
+    QVERIFY(!item1->isSelected());
+
+    // Click on item1
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Click on scene
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(0, 0));
+    QTest::qWait(20);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Click on item1
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Ctrl-click on scene
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(0, 0));
+    QTest::qWait(20);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Click on item1
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Press on item2
+    QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(item2->isSelected());
+
+    // Release on item2
+    QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(item2->isSelected());
+
+    // Click on item1
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Ctrl-click on item1
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    // Ctrl-press on item1
+    QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    {
+        // Ctrl-move on item1
+        QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
+        QApplication::sendEvent(view.viewport(), &event);
+        QTest::qWait(20);
+        QVERIFY(!item1->isSelected());
+        QVERIFY(!item2->isSelected());
+    }
+
+    // Release on item1
+    QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    item1->setFlag(QGraphicsItem::ItemIsMovable);
+    item1->setSelected(false);
+
+    // Ctrl-press on item1
+    QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(!item1->isSelected());
+    QVERIFY(!item2->isSelected());
+
+    {
+        // Ctrl-move on item1
+        QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
+        QApplication::sendEvent(view.viewport(), &event);
+        QTest::qWait(20);
+        QVERIFY(item1->isSelected());
+        QVERIFY(!item2->isSelected());
+    }
+
+    // Release on item1
+    QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
+    QTest::qWait(20);
+    QVERIFY(item1->isSelected());
+    QVERIFY(!item2->isSelected());
+}
+
+void tst_QGraphicsItem::acceptedMouseButtons()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
+    QGraphicsRectItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
+    item2->setZValue(1);
+
+    item1->setFlag(QGraphicsItem::ItemIsMovable);
+    item2->setFlag(QGraphicsItem::ItemIsMovable);
+
+    QCOMPARE(item1->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
+    QCOMPARE(item2->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
+
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+    event.setButton(Qt::LeftButton);
+    event.setScenePos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &event);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item2);
+    item2->setAcceptedMouseButtons(0);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+    QApplication::sendEvent(&scene, &event);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item1);
+}
+
+class HoverItem : public QGraphicsRectItem
+{
+public:
+    HoverItem(const QRectF &rect)
+        : QGraphicsRectItem(rect), hoverInCount(0),
+          hoverMoveCount(0), hoverOutCount(0)
+    { }
+
+    int hoverInCount;
+    int hoverMoveCount;
+    int hoverOutCount;
+protected:
+    void hoverEnterEvent(QGraphicsSceneHoverEvent *)
+    { ++hoverInCount; }
+
+    void hoverMoveEvent(QGraphicsSceneHoverEvent *)
+    { ++hoverMoveCount; }
+
+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
+    { ++hoverOutCount; }
+};
+
+void tst_QGraphicsItem::acceptsHoverEvents()
+{
+    QGraphicsScene scene;
+    HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
+    HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
+    scene.addItem(item1);
+    scene.addItem(item2);
+    item2->setZValue(1);
+
+    QVERIFY(!item1->acceptsHoverEvents());
+    QVERIFY(!item2->acceptsHoverEvents());
+    item1->setAcceptsHoverEvents(true);
+    item2->setAcceptsHoverEvents(true);
+
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+    event.setScenePos(QPointF(-100, -100));
+    QApplication::sendEvent(&scene, &event);
+    event.setScenePos(QPointF(-2.5, -2.5));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item2->hoverInCount, 1);
+
+    item1->setAcceptsHoverEvents(false);
+    item2->setAcceptsHoverEvents(false);
+
+    event.setScenePos(QPointF(-100, -100));
+    QApplication::sendEvent(&scene, &event);
+    event.setScenePos(QPointF(-2.5, -2.5));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item2->hoverInCount, 1);
+
+    item1->setAcceptsHoverEvents(true);
+    item2->setAcceptsHoverEvents(false);
+
+    event.setScenePos(QPointF(-100, -100));
+    QApplication::sendEvent(&scene, &event);
+    event.setScenePos(QPointF(-2.5, -2.5));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item1->hoverInCount, 1);
+    QCOMPARE(item2->hoverInCount, 1);
+}
+
+void tst_QGraphicsItem::childAcceptsHoverEvents()
+{
+    QGraphicsScene scene;
+    HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
+    HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
+
+    scene.addItem(item1);
+    scene.addItem(item2);
+    item2->setParentItem(item1);
+    item2->setAcceptHoverEvents(true);
+
+    QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+    event.setScenePos(QPointF(-100, -100));
+    QApplication::sendEvent(&scene, &event);
+    QCOMPARE(item2->hoverInCount, 0);
+    QCOMPARE(item2->hoverMoveCount, 0);
+    QCOMPARE(item2->hoverOutCount, 0);
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item1->hoverMoveCount, 0);
+    QCOMPARE(item1->hoverOutCount, 0);
+
+    event.setScenePos(QPointF(-2.5, -2.5));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item2->hoverInCount, 1);
+    QCOMPARE(item2->hoverMoveCount, 1);
+    QCOMPARE(item2->hoverOutCount, 0);
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item1->hoverMoveCount, 0);
+    QCOMPARE(item1->hoverOutCount, 0);
+
+    event.setScenePos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item2->hoverInCount, 1);
+    QCOMPARE(item2->hoverMoveCount, 2);
+    QCOMPARE(item2->hoverOutCount, 0);
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item1->hoverMoveCount, 0);
+    QCOMPARE(item1->hoverOutCount, 0);
+
+    event.setScenePos(QPointF(-7, -7));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item2->hoverInCount, 1);
+    QCOMPARE(item2->hoverMoveCount, 2);
+    QCOMPARE(item2->hoverOutCount, 1);
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item1->hoverMoveCount, 0);
+    QCOMPARE(item1->hoverOutCount, 0);
+
+    event.setScenePos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item2->hoverInCount, 2);
+    QCOMPARE(item2->hoverMoveCount, 3);
+    QCOMPARE(item2->hoverOutCount, 1);
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item1->hoverMoveCount, 0);
+    QCOMPARE(item1->hoverOutCount, 0);
+
+    HoverItem *item0 = new HoverItem(QRectF(-20, -20, 20, 20));
+    scene.addItem(item0);
+    item1->setParentItem(item0);
+    item0->setAcceptHoverEvents(true);
+
+    event.setScenePos(QPointF(-100, -100));
+    QApplication::sendEvent(&scene, &event);
+
+    event.setScenePos(QPointF(-15, -15));
+    QApplication::sendEvent(&scene, &event);
+
+    QCOMPARE(item2->hoverInCount, 2);
+    QCOMPARE(item2->hoverMoveCount, 3);
+    QCOMPARE(item2->hoverOutCount, 2);
+    QCOMPARE(item1->hoverInCount, 0);
+    QCOMPARE(item1->hoverMoveCount, 0);
+    QCOMPARE(item1->hoverOutCount, 0);
+    QCOMPARE(item0->hoverInCount, 1);
+    QCOMPARE(item0->hoverMoveCount, 1);
+    QCOMPARE(item0->hoverOutCount, 0);
+}
+
+void tst_QGraphicsItem::hasFocus()
+{
+    QGraphicsLineItem *line = new QGraphicsLineItem;
+    QVERIFY(!line->hasFocus());
+    line->setFocus();
+    QVERIFY(!line->hasFocus());
+
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    scene.addItem(line);
+
+    line->setFocus();
+    QVERIFY(!line->hasFocus());
+    line->setFlag(QGraphicsItem::ItemIsFocusable);
+    line->setFocus();
+    QVERIFY(line->hasFocus());
+
+    QGraphicsScene scene2;
+    QApplication::sendEvent(&scene2, &activate);
+
+    scene2.addItem(line);
+    QVERIFY(!line->hasFocus());
+
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *)0);
+    QCOMPARE(scene2.focusItem(), (QGraphicsItem *)0);
+
+    line->setFocus();
+    QVERIFY(line->hasFocus());
+    line->clearFocus();
+    QVERIFY(!line->hasFocus());
+
+    QGraphicsLineItem *line2 = new QGraphicsLineItem;
+    line2->setFlag(QGraphicsItem::ItemIsFocusable);
+    scene2.addItem(line2);
+
+    line2->setFocus();
+    QVERIFY(!line->hasFocus());
+    QVERIFY(line2->hasFocus());
+    line->setFocus();
+    QVERIFY(line->hasFocus());
+    QVERIFY(!line2->hasFocus());
+}
+
+void tst_QGraphicsItem::pos()
+{
+    QGraphicsItem *child = new QGraphicsLineItem;
+    QGraphicsItem *parent = new QGraphicsLineItem;
+
+    QCOMPARE(child->pos(), QPointF());
+    QCOMPARE(parent->pos(), QPointF());
+
+    child->setParentItem(parent);
+    child->setPos(10, 10);
+
+    QCOMPARE(child->pos(), QPointF(10, 10));
+
+    parent->setPos(10, 10);
+
+    QCOMPARE(parent->pos(), QPointF(10, 10));
+    QCOMPARE(child->pos(), QPointF(10, 10));
+
+    delete child;
+    delete parent;
+}
+
+void tst_QGraphicsItem::scenePos()
+{
+    QGraphicsItem *child = new QGraphicsLineItem;
+    QGraphicsItem *parent = new QGraphicsLineItem;
+
+    QCOMPARE(child->scenePos(), QPointF());
+    QCOMPARE(parent->scenePos(), QPointF());
+
+    child->setParentItem(parent);
+    child->setPos(10, 10);
+
+    QCOMPARE(child->scenePos(), QPointF(10, 10));
+
+    parent->setPos(10, 10);
+
+    QCOMPARE(parent->scenePos(), QPointF(10, 10));
+    QCOMPARE(child->scenePos(), QPointF(20, 20));
+
+    parent->setPos(20, 20);
+
+    QCOMPARE(parent->scenePos(), QPointF(20, 20));
+    QCOMPARE(child->scenePos(), QPointF(30, 30));
+
+    delete child;
+    delete parent;
+}
+
+void tst_QGraphicsItem::matrix()
+{
+    QGraphicsLineItem line;
+    QCOMPARE(line.matrix(), QMatrix());
+    line.setMatrix(QMatrix().rotate(90));
+    QCOMPARE(line.matrix(), QMatrix().rotate(90));
+    line.setMatrix(QMatrix().rotate(90));
+    QCOMPARE(line.matrix(), QMatrix().rotate(90));
+    line.setMatrix(QMatrix().rotate(90), true);
+    QCOMPARE(line.matrix(), QMatrix().rotate(180));
+    line.setMatrix(QMatrix().rotate(-90), true);
+    QCOMPARE(line.matrix(), QMatrix().rotate(90));
+    line.resetMatrix();
+    QCOMPARE(line.matrix(), QMatrix());
+
+    line.rotate(90);
+    QCOMPARE(line.matrix(), QMatrix().rotate(90));
+    line.rotate(90);
+    QCOMPARE(line.matrix(), QMatrix().rotate(90).rotate(90));
+    line.resetMatrix();
+
+    line.scale(2, 4);
+    QCOMPARE(line.matrix(), QMatrix().scale(2, 4));
+    line.scale(2, 4);
+    QCOMPARE(line.matrix(), QMatrix().scale(2, 4).scale(2, 4));
+    line.resetMatrix();
+
+    line.shear(2, 4);
+    QCOMPARE(line.matrix(), QMatrix().shear(2, 4));
+    line.shear(2, 4);
+    QCOMPARE(line.matrix(), QMatrix().shear(2, 4).shear(2, 4));
+    line.resetMatrix();
+
+    line.translate(10, 10);
+    QCOMPARE(line.matrix(), QMatrix().translate(10, 10));
+    line.translate(10, 10);
+    QCOMPARE(line.matrix(), QMatrix().translate(10, 10).translate(10, 10));
+    line.resetMatrix();
+}
+
+void tst_QGraphicsItem::sceneMatrix()
+{
+    QGraphicsLineItem *parent = new QGraphicsLineItem;
+    QGraphicsLineItem *child = new QGraphicsLineItem(QLineF(), parent);
+
+    QCOMPARE(parent->sceneMatrix(), QMatrix());
+    QCOMPARE(child->sceneMatrix(), QMatrix());
+
+    parent->translate(10, 10);
+    QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
+    QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10));
+
+    child->translate(10, 10);
+    QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
+    QCOMPARE(child->sceneMatrix(), QMatrix().translate(20, 20));
+
+    parent->rotate(90);
+    QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10).rotate(90));
+    QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10).rotate(90).translate(10, 10));
+
+    delete child;
+    delete parent;
+}
+
+void tst_QGraphicsItem::setMatrix()
+{
+    QGraphicsScene scene;
+    qRegisterMetaType<QList<QRectF> >("QList<QRectF>");
+    QSignalSpy spy(&scene, SIGNAL(changed(QList<QRectF>)));
+    QRectF unrotatedRect(-12, -34, 56, 78);
+    QGraphicsRectItem item(unrotatedRect, 0, &scene);
+    scene.update(scene.sceneRect());
+    QApplication::instance()->processEvents();
+
+    QCOMPARE(spy.count(), 1);
+
+    item.setMatrix(QMatrix().rotate(qreal(12.34)));
+    QRectF rotatedRect = scene.sceneRect();
+    QVERIFY(unrotatedRect != rotatedRect);
+    scene.update(scene.sceneRect());
+    QApplication::instance()->processEvents();
+
+    QCOMPARE(spy.count(), 2);
+
+    item.setMatrix(QMatrix());
+
+    scene.update(scene.sceneRect());
+    QApplication::instance()->processEvents();
+
+    QCOMPARE(spy.count(), 3);
+    QList<QRectF> rlist = qVariantValue<QList<QRectF> >(spy.last().at(0));
+
+    QCOMPARE(rlist.size(), 3);
+    QCOMPARE(rlist.at(0), rotatedRect);   // From item.setMatrix() (clearing rotated rect)
+    QCOMPARE(rlist.at(1), rotatedRect);   // From scene.update()   (updating scene rect)
+    QCOMPARE(rlist.at(2), unrotatedRect); // From post-update      (update current state)
+}
+
+static QList<QGraphicsItem *> _paintedItems;
+class PainterItem : public QGraphicsItem
+{
+protected:
+    QRectF boundingRect() const
+    { return QRectF(-10, -10, 20, 20); }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+    { _paintedItems << this; painter->fillRect(boundingRect(), Qt::red); }
+};
+
+void tst_QGraphicsItem::zValue()
+{
+    Q_CHECK_PAINTEVENTS
+
+    QGraphicsScene scene;
+
+    QGraphicsItem *item1 = new PainterItem;
+    QGraphicsItem *item2 = new PainterItem;
+    QGraphicsItem *item3 = new PainterItem;
+    QGraphicsItem *item4 = new PainterItem;
+    scene.addItem(item1);
+    scene.addItem(item2);
+    scene.addItem(item3);
+    scene.addItem(item4);
+    item2->setZValue(-3);
+    item4->setZValue(-2);
+    item1->setZValue(-1);
+    item3->setZValue(0);
+
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QApplication::processEvents();
+#ifdef Q_WS_QWS
+    QApplication::sendPostedEvents(); //glib workaround
+#endif
+
+    QTRY_VERIFY(!_paintedItems.isEmpty());
+    QVERIFY((_paintedItems.size() % 4) == 0);
+    for (int i = 0; i < 3; ++i)
+        QVERIFY(_paintedItems.at(i)->zValue() < _paintedItems.at(i + 1)->zValue());
+}
+
+void tst_QGraphicsItem::shape()
+{
+    QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
+
+    // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
+    // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
+    const qreal penWidthZero = qreal(0.00000001);
+
+    QPainterPathStroker ps;
+    ps.setWidth(penWidthZero);
+
+    QPainterPath path(line.line().p1());
+    path.lineTo(line.line().p2());
+    QPainterPath p = ps.createStroke(path);
+    p.addPath(path);
+    QCOMPARE(line.shape(), p);
+
+    QPen linePen;
+    linePen.setWidthF(5.0);
+    linePen.setCapStyle(Qt::RoundCap);
+    line.setPen(linePen);
+
+    ps.setCapStyle(line.pen().capStyle());
+    ps.setWidth(line.pen().widthF());
+    p = ps.createStroke(path);
+    p.addPath(path);
+    QCOMPARE(line.shape(), p);
+
+    linePen.setCapStyle(Qt::FlatCap);
+    line.setPen(linePen);
+    ps.setCapStyle(line.pen().capStyle());
+    p = ps.createStroke(path);
+    p.addPath(path);
+    QCOMPARE(line.shape(), p);
+
+    linePen.setCapStyle(Qt::SquareCap);
+    line.setPen(linePen);
+    ps.setCapStyle(line.pen().capStyle());
+    p = ps.createStroke(path);
+    p.addPath(path);
+    QCOMPARE(line.shape(), p);
+
+    QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
+    QPainterPathStroker ps1;
+    ps1.setWidth(penWidthZero);
+    path = QPainterPath();
+    path.addRect(rect.rect());
+    p = ps1.createStroke(path);
+    p.addPath(path);
+    QCOMPARE(rect.shape(), p);
+
+    QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
+    QPainterPathStroker ps2;
+    ps2.setWidth(ellipse.pen().widthF() <= 0.0 ? penWidthZero : ellipse.pen().widthF());
+    path = QPainterPath();
+    path.addEllipse(ellipse.rect());
+    p = ps2.createStroke(path);
+    p.addPath(path);
+    QCOMPARE(ellipse.shape(), p);
+
+    QPainterPathStroker ps3;
+    ps3.setWidth(penWidthZero);
+    p = ps3.createStroke(path);
+    p.addPath(path);
+    QGraphicsPathItem pathItem(path);
+    QCOMPARE(pathItem.shape(), p);
+
+    QRegion region(QRect(0, 0, 300, 200));
+    region = region.subtracted(QRect(50, 50, 200, 100));
+
+    QImage image(300, 200, QImage::Format_ARGB32_Premultiplied);
+    image.fill(0);
+    QPainter painter(&image);
+    painter.setClipRegion(region);
+    painter.fillRect(0, 0, 300, 200, Qt::green);
+    painter.end();
+    QPixmap pixmap = QPixmap::fromImage(image);
+
+    QGraphicsPixmapItem pixmapItem(pixmap);
+    path = QPainterPath();
+    path.addRegion(region);
+
+    {
+        QBitmap bitmap(300, 200);
+        bitmap.clear();
+        QPainter painter(&bitmap);
+        painter.setClipRegion(region);
+        painter.fillRect(0, 0, 300, 200, Qt::color1);
+        painter.end();
+
+        QBitmap bitmap2(300, 200);
+        bitmap2.clear();
+        painter.begin(&bitmap2);
+        painter.setClipPath(pixmapItem.shape());
+        painter.fillRect(0, 0, 300, 200, Qt::color1);
+        painter.end();
+
+        QCOMPARE(bitmap.toImage(), bitmap2.toImage());
+    }
+
+    QPolygonF poly;
+    poly << QPointF(0, 0) << QPointF(10, 0) << QPointF(0, 10);
+    QGraphicsPolygonItem polygon(poly);
+    path = QPainterPath();
+    path.addPolygon(poly);
+
+    QPainterPathStroker ps4;
+    ps4.setWidth(penWidthZero);
+    p = ps4.createStroke(path);
+    p.addPath(path);
+    QCOMPARE(polygon.shape(), p);
+}
+
+void tst_QGraphicsItem::contains()
+{
+    if (sizeof(qreal) != sizeof(double)) {
+        QSKIP("Skipped due to rounding errors", SkipAll);
+    }
+
+    // Rect
+    QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
+    QVERIFY(!rect.contains(QPointF(-11, -10)));
+    QVERIFY(rect.contains(QPointF(-10, -10)));
+    QVERIFY(!rect.contains(QPointF(-11, 0)));
+    QVERIFY(rect.contains(QPointF(-10, 0)));
+    QVERIFY(rect.contains(QPointF(0, -10)));
+    QVERIFY(rect.contains(QPointF(0, 0)));
+    QVERIFY(rect.contains(QPointF(9, 9)));
+
+    // Ellipse
+    QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
+    QVERIFY(!ellipse.contains(QPointF(-10, -10)));
+    QVERIFY(ellipse.contains(QPointF(-9, 0)));
+    QVERIFY(ellipse.contains(QPointF(0, -9)));
+    QVERIFY(ellipse.contains(QPointF(0, 0)));
+    QVERIFY(!ellipse.contains(QPointF(9, 9)));
+
+    // Line
+    QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
+    QVERIFY(!line.contains(QPointF(-10, 0)));
+    QVERIFY(!line.contains(QPointF(0, -10)));
+    QVERIFY(!line.contains(QPointF(10, 0)));
+    QVERIFY(!line.contains(QPointF(0, 10)));
+    QVERIFY(line.contains(QPointF(0, 0)));
+    QVERIFY(line.contains(QPointF(-9, -9)));
+    QVERIFY(line.contains(QPointF(9, 9)));
+
+    // Polygon
+    QGraphicsPolygonItem polygon(QPolygonF()
+                                 << QPointF(0, 0)
+                                 << QPointF(10, 0)
+                                 << QPointF(0, 10));
+    QVERIFY(polygon.contains(QPointF(1, 1)));
+    QVERIFY(polygon.contains(QPointF(4, 4)));
+    QVERIFY(polygon.contains(QPointF(1, 4)));
+    QVERIFY(polygon.contains(QPointF(4, 1)));
+    QVERIFY(!polygon.contains(QPointF(8, 8)));
+    QVERIFY(polygon.contains(QPointF(1, 8)));
+    QVERIFY(polygon.contains(QPointF(8, 1)));
+}
+
+void tst_QGraphicsItem::collidesWith_item()
+{
+    // Rectangle
+    QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
+    QGraphicsRectItem rect2(QRectF(-10, -10, 20, 20));
+    QVERIFY(rect.collidesWithItem(&rect2));
+    QVERIFY(rect2.collidesWithItem(&rect));
+    rect2.setPos(21, 21);
+    QVERIFY(!rect.collidesWithItem(&rect2));
+    QVERIFY(!rect2.collidesWithItem(&rect));
+    rect2.setPos(-21, -21);
+    QVERIFY(!rect.collidesWithItem(&rect2));
+    QVERIFY(!rect2.collidesWithItem(&rect));
+    rect2.setPos(-17, -17);
+    QVERIFY(rect.collidesWithItem(&rect2));
+    QVERIFY(rect2.collidesWithItem(&rect));
+
+    QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
+    QGraphicsEllipseItem ellipse2(QRectF(-10, -10, 20, 20));
+    QVERIFY(ellipse.collidesWithItem(&ellipse2));
+    QVERIFY(ellipse2.collidesWithItem(&ellipse));
+    ellipse2.setPos(21, 21);
+    QVERIFY(!ellipse.collidesWithItem(&ellipse2));
+    QVERIFY(!ellipse2.collidesWithItem(&ellipse));
+    ellipse2.setPos(-21, -21);
+    QVERIFY(!ellipse.collidesWithItem(&ellipse2));
+    QVERIFY(!ellipse2.collidesWithItem(&ellipse));
+
+    ellipse2.setPos(-17, -17);
+    QVERIFY(!ellipse.collidesWithItem(&ellipse2));
+    QVERIFY(!ellipse2.collidesWithItem(&ellipse));
+
+    {
+        QGraphicsScene scene;
+        QGraphicsRectItem rect(20, 20, 100, 100, 0, &scene);
+        QGraphicsRectItem rect2(40, 40, 50, 50, 0, &scene);
+        rect2.setZValue(1);
+        QGraphicsLineItem line(0, 0, 200, 200, 0, &scene);
+        line.setZValue(2);
+
+        QCOMPARE(scene.items().size(), 3);
+
+        QList<QGraphicsItem *> col1 = rect.collidingItems();
+        QCOMPARE(col1.size(), 2);
+        QCOMPARE(col1.first(), static_cast<QGraphicsItem *>(&line));
+        QCOMPARE(col1.last(), static_cast<QGraphicsItem *>(&rect2));
+
+        QList<QGraphicsItem *> col2 = rect2.collidingItems();
+        QCOMPARE(col2.size(), 2);
+        QCOMPARE(col2.first(), static_cast<QGraphicsItem *>(&line));
+        QCOMPARE(col2.last(), static_cast<QGraphicsItem *>(&rect));
+
+        QList<QGraphicsItem *> col3 = line.collidingItems();
+        QCOMPARE(col3.size(), 2);
+        QCOMPARE(col3.first(), static_cast<QGraphicsItem *>(&rect2));
+        QCOMPARE(col3.last(), static_cast<QGraphicsItem *>(&rect));
+    }
+}
+
+void tst_QGraphicsItem::collidesWith_path_data()
+{
+    QTest::addColumn<QPointF>("pos");
+    QTest::addColumn<QMatrix>("matrix");
+    QTest::addColumn<QPainterPath>("shape");
+    QTest::addColumn<bool>("rectCollides");
+    QTest::addColumn<bool>("ellipseCollides");
+
+    QTest::newRow("nothing") << QPointF(0, 0) << QMatrix() << QPainterPath() << false << false;
+
+    QPainterPath rect;
+    rect.addRect(0, 0, 20, 20);
+
+    QTest::newRow("rect1") << QPointF(0, 0) << QMatrix() << rect << true << true;
+    QTest::newRow("rect2") << QPointF(0, 0) << QMatrix().translate(21, 21) << rect << false << false;
+    QTest::newRow("rect3") << QPointF(21, 21) << QMatrix() << rect << false << false;
+}
+
+void tst_QGraphicsItem::collidesWith_path()
+{
+    QFETCH(QPointF, pos);
+    QFETCH(QMatrix, matrix);
+    QFETCH(QPainterPath, shape);
+    QFETCH(bool, rectCollides);
+    QFETCH(bool, ellipseCollides);
+
+    QGraphicsRectItem rect(QRectF(0, 0, 20, 20));
+    QGraphicsEllipseItem ellipse(QRectF(0, 0, 20, 20));
+
+    rect.setPos(pos);
+    rect.setMatrix(matrix);
+
+    ellipse.setPos(pos);
+    ellipse.setMatrix(matrix);
+
+    QPainterPath mappedShape = rect.sceneMatrix().inverted().map(shape);
+
+    if (rectCollides)
+        QVERIFY(rect.collidesWithPath(mappedShape));
+    else
+        QVERIFY(!rect.collidesWithPath(mappedShape));
+
+    if (ellipseCollides)
+        QVERIFY(ellipse.collidesWithPath(mappedShape));
+    else
+        QVERIFY(!ellipse.collidesWithPath(mappedShape));
+}
+
+void tst_QGraphicsItem::collidesWithItemWithClip()
+{
+    QGraphicsScene scene;
+
+    QGraphicsEllipseItem *ellipse = scene.addEllipse(0, 0, 100, 100);
+    ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    QGraphicsEllipseItem *ellipse2 = scene.addEllipse(0, 0, 10, 10);
+    ellipse2->setParentItem(ellipse);
+    QGraphicsEllipseItem *ellipse3 = scene.addEllipse(0, 0, 10, 10);
+    ellipse3->setParentItem(ellipse);
+    QGraphicsEllipseItem *ellipse5 = scene.addEllipse(50, 50, 10, 10);
+    ellipse5->setParentItem(ellipse);
+    QGraphicsEllipseItem *ellipse4 = scene.addEllipse(0, 0, 10, 10);
+
+    QVERIFY(ellipse2->collidesWithItem(ellipse3));
+    QVERIFY(ellipse3->collidesWithItem(ellipse2));
+    QVERIFY(!ellipse2->collidesWithItem(ellipse));
+    QVERIFY(!ellipse->collidesWithItem(ellipse2));
+    QVERIFY(!ellipse4->collidesWithItem(ellipse));
+    QVERIFY(!ellipse4->collidesWithItem(ellipse2));
+    QVERIFY(!ellipse4->collidesWithItem(ellipse3));
+    QVERIFY(!ellipse->collidesWithItem(ellipse4));
+    QVERIFY(!ellipse2->collidesWithItem(ellipse4));
+    QVERIFY(!ellipse3->collidesWithItem(ellipse4));
+    QVERIFY(ellipse->collidesWithItem(ellipse5));
+    QVERIFY(ellipse5->collidesWithItem(ellipse));
+}
+
+class MyItem : public QGraphicsEllipseItem
+{
+public:
+    bool isObscuredBy(const QGraphicsItem *item) const
+    {
+        const MyItem *myItem = qgraphicsitem_cast<const MyItem *>(item);
+        if (myItem) {
+            if (item->zValue() > zValue()) {
+                QRectF r = rect();
+                QPointF topMid = (r.topRight()+r.topLeft())/2;
+                QPointF botMid = (r.bottomRight()+r.bottomLeft())/2;
+                QPointF leftMid = (r.topLeft()+r.bottomLeft())/2;
+                QPointF rightMid = (r.topRight()+r.bottomRight())/2;
+
+                QPainterPath mappedShape = item->mapToItem(this, item->opaqueArea());
+
+                if (mappedShape.contains(topMid) &&
+                    mappedShape.contains(botMid) &&
+                    mappedShape.contains(leftMid) &&
+                    mappedShape.contains(rightMid))
+                    return true;
+                else
+                    return false;
+            }
+            else return false;
+        }
+        else
+            return QGraphicsItem::isObscuredBy(item);
+    }
+
+    QPainterPath opaqueArea() const
+    {
+        return shape();
+    }
+
+    enum {
+        Type = UserType+1
+    };
+    int type() const { return Type; }
+};
+
+void tst_QGraphicsItem::isObscuredBy()
+{
+    QGraphicsScene scene;
+
+    MyItem myitem1, myitem2;
+
+    myitem1.setRect(QRectF(50, 50, 40, 200));
+    myitem1.rotate(67);
+
+    myitem2.setRect(QRectF(25, 25, 20, 20));
+    myitem2.setZValue(-1.0);
+    scene.addItem(&myitem1);
+    scene.addItem(&myitem2);
+
+    QVERIFY(!myitem2.isObscuredBy(&myitem1));
+    QVERIFY(!myitem1.isObscuredBy(&myitem2));
+
+    myitem2.setRect(QRectF(-50, 85, 20, 20));
+    QVERIFY(myitem2.isObscuredBy(&myitem1));
+    QVERIFY(!myitem1.isObscuredBy(&myitem2));
+
+    myitem2.setRect(QRectF(-30, 70, 20, 20));
+    QVERIFY(!myitem2.isObscuredBy(&myitem1));
+    QVERIFY(!myitem1.isObscuredBy(&myitem2));
+
+    QGraphicsRectItem rect1, rect2;
+
+    rect1.setRect(QRectF(-40, -40, 50, 50));
+    rect1.setBrush(QBrush(Qt::red));
+    rect2.setRect(QRectF(-30, -20, 20, 20));
+    rect2.setZValue(-1.0);
+    rect2.setBrush(QBrush(Qt::blue));
+
+    QVERIFY(rect2.isObscuredBy(&rect1));
+    QVERIFY(!rect1.isObscuredBy(&rect2));
+
+    rect2.setPos(QPointF(-20, -25));
+
+    QVERIFY(!rect2.isObscuredBy(&rect1));
+    QVERIFY(!rect1.isObscuredBy(&rect2));
+
+    rect2.setPos(QPointF(-100, -100));
+
+    QVERIFY(!rect2.isObscuredBy(&rect1));
+    QVERIFY(!rect1.isObscuredBy(&rect2));
+}
+
+class OpaqueItem : public QGraphicsRectItem
+{
+protected:
+    QPainterPath opaqueArea() const
+    {
+        return shape();
+    }
+};
+
+void tst_QGraphicsItem::isObscured()
+{
+    if (sizeof(qreal) != sizeof(double)) {
+        QSKIP("Skipped due to rounding errors", SkipAll);
+    }
+
+    OpaqueItem *item1 = new OpaqueItem;
+    item1->setRect(0, 0, 100, 100);
+    item1->setZValue(0);
+
+    OpaqueItem *item2 = new OpaqueItem;
+    item2->setZValue(1);
+    item2->setRect(0, 0, 100, 100);
+
+    QGraphicsScene scene;
+    scene.addItem(item1);
+    scene.addItem(item2);
+
+    QVERIFY(item1->isObscured());
+    QVERIFY(item1->isObscuredBy(item2));
+    QVERIFY(item1->isObscured(QRectF(0, 0, 50, 50)));
+    QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
+    QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
+    QVERIFY(item1->isObscured(QRectF(0, 50, 50, 50)));
+    QVERIFY(item1->isObscured(0, 0, 50, 50));
+    QVERIFY(item1->isObscured(50, 0, 50, 50));
+    QVERIFY(item1->isObscured(50, 50, 50, 50));
+    QVERIFY(item1->isObscured(0, 50, 50, 50));
+    QVERIFY(!item2->isObscured());
+    QVERIFY(!item2->isObscuredBy(item1));
+    QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
+    QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
+    QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
+    QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
+    QVERIFY(!item2->isObscured(0, 0, 50, 50));
+    QVERIFY(!item2->isObscured(50, 0, 50, 50));
+    QVERIFY(!item2->isObscured(50, 50, 50, 50));
+    QVERIFY(!item2->isObscured(0, 50, 50, 50));
+
+    item2->moveBy(50, 0);
+
+    QVERIFY(!item1->isObscured());
+    QVERIFY(!item1->isObscuredBy(item2));
+    QVERIFY(!item1->isObscured(QRectF(0, 0, 50, 50)));
+    QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
+    QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
+    QVERIFY(!item1->isObscured(QRectF(0, 50, 50, 50)));
+    QVERIFY(!item1->isObscured(0, 0, 50, 50));
+    QVERIFY(item1->isObscured(50, 0, 50, 50));
+    QVERIFY(item1->isObscured(50, 50, 50, 50));
+    QVERIFY(!item1->isObscured(0, 50, 50, 50));
+    QVERIFY(!item2->isObscured());
+    QVERIFY(!item2->isObscuredBy(item1));
+    QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
+    QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
+    QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
+    QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
+    QVERIFY(!item2->isObscured(0, 0, 50, 50));
+    QVERIFY(!item2->isObscured(50, 0, 50, 50));
+    QVERIFY(!item2->isObscured(50, 50, 50, 50));
+    QVERIFY(!item2->isObscured(0, 50, 50, 50));
+}
+
+void tst_QGraphicsItem::mapFromToParent()
+{
+    QPainterPath path1;
+    path1.addRect(0, 0, 200, 200);
+
+    QPainterPath path2;
+    path2.addRect(0, 0, 100, 100);
+
+    QPainterPath path3;
+    path3.addRect(0, 0, 50, 50);
+
+    QPainterPath path4;
+    path4.addRect(0, 0, 25, 25);
+
+    QGraphicsItem *item1 = new QGraphicsPathItem(path1);
+    QGraphicsItem *item2 = new QGraphicsPathItem(path2, item1);
+    QGraphicsItem *item3 = new QGraphicsPathItem(path3, item2);
+    QGraphicsItem *item4 = new QGraphicsPathItem(path4, item3);
+
+    item1->setPos(10, 10);
+    item2->setPos(10, 10);
+    item3->setPos(10, 10);
+    item4->setPos(10, 10);
+
+    for (int i = 0; i < 4; ++i) {
+        QMatrix matrix;
+        matrix.rotate(i * 90);
+        matrix.translate(i * 100, -i * 100);
+        matrix.scale(2, 4);
+        item1->setMatrix(matrix);
+
+        QCOMPARE(item1->mapToParent(QPointF(0, 0)), item1->pos() + matrix.map(QPointF(0, 0)));
+        QCOMPARE(item2->mapToParent(QPointF(0, 0)), item2->pos());
+        QCOMPARE(item3->mapToParent(QPointF(0, 0)), item3->pos());
+        QCOMPARE(item4->mapToParent(QPointF(0, 0)), item4->pos());
+        QCOMPARE(item1->mapToParent(QPointF(10, -10)), item1->pos() + matrix.map(QPointF(10, -10)));
+        QCOMPARE(item2->mapToParent(QPointF(10, -10)), item2->pos() + QPointF(10, -10));
+        QCOMPARE(item3->mapToParent(QPointF(10, -10)), item3->pos() + QPointF(10, -10));
+        QCOMPARE(item4->mapToParent(QPointF(10, -10)), item4->pos() + QPointF(10, -10));
+        QCOMPARE(item1->mapToParent(QPointF(-10, 10)), item1->pos() + matrix.map(QPointF(-10, 10)));
+        QCOMPARE(item2->mapToParent(QPointF(-10, 10)), item2->pos() + QPointF(-10, 10));
+        QCOMPARE(item3->mapToParent(QPointF(-10, 10)), item3->pos() + QPointF(-10, 10));
+        QCOMPARE(item4->mapToParent(QPointF(-10, 10)), item4->pos() + QPointF(-10, 10));
+        QCOMPARE(item1->mapFromParent(item1->pos()), matrix.inverted().map(QPointF(0, 0)));
+        QCOMPARE(item2->mapFromParent(item2->pos()), QPointF(0, 0));
+        QCOMPARE(item3->mapFromParent(item3->pos()), QPointF(0, 0));
+        QCOMPARE(item4->mapFromParent(item4->pos()), QPointF(0, 0));
+        QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(10, -10)),
+                 matrix.inverted().map(QPointF(10, -10)));
+        QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(10, -10)), QPointF(10, -10));
+        QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(10, -10)), QPointF(10, -10));
+        QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(10, -10)), QPointF(10, -10));
+        QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(-10, 10)),
+                 matrix.inverted().map(QPointF(-10, 10)));
+        QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(-10, 10)), QPointF(-10, 10));
+        QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(-10, 10)), QPointF(-10, 10));
+        QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(-10, 10)), QPointF(-10, 10));
+    }
+
+    delete item1;
+}
+
+void tst_QGraphicsItem::mapFromToScene()
+{
+    QGraphicsItem *item1 = new QGraphicsPathItem(QPainterPath());
+    QGraphicsItem *item2 = new QGraphicsPathItem(QPainterPath(), item1);
+    QGraphicsItem *item3 = new QGraphicsPathItem(QPainterPath(), item2);
+    QGraphicsItem *item4 = new QGraphicsPathItem(QPainterPath(), item3);
+
+    item1->setPos(100, 100);
+    item2->setPos(100, 100);
+    item3->setPos(100, 100);
+    item4->setPos(100, 100);
+    QCOMPARE(item1->pos(), QPointF(100, 100));
+    QCOMPARE(item2->pos(), QPointF(100, 100));
+    QCOMPARE(item3->pos(), QPointF(100, 100));
+    QCOMPARE(item4->pos(), QPointF(100, 100));
+    QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
+    QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
+    QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
+    QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
+    QCOMPARE(item1->mapToParent(10, 10), QPointF(110, 110));
+    QCOMPARE(item2->mapToParent(10, 10), QPointF(110, 110));
+    QCOMPARE(item3->mapToParent(10, 10), QPointF(110, 110));
+    QCOMPARE(item4->mapToParent(10, 10), QPointF(110, 110));
+    QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
+    QCOMPARE(item2->mapToScene(0, 0), QPointF(200, 200));
+    QCOMPARE(item3->mapToScene(0, 0), QPointF(300, 300));
+    QCOMPARE(item4->mapToScene(0, 0), QPointF(400, 400));
+    QCOMPARE(item1->mapToScene(10, 0), QPointF(110, 100));
+    QCOMPARE(item2->mapToScene(10, 0), QPointF(210, 200));
+    QCOMPARE(item3->mapToScene(10, 0), QPointF(310, 300));
+    QCOMPARE(item4->mapToScene(10, 0), QPointF(410, 400));
+    QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
+    QCOMPARE(item2->mapFromScene(200, 200), QPointF(0, 0));
+    QCOMPARE(item3->mapFromScene(300, 300), QPointF(0, 0));
+    QCOMPARE(item4->mapFromScene(400, 400), QPointF(0, 0));
+    QCOMPARE(item1->mapFromScene(110, 100), QPointF(10, 0));
+    QCOMPARE(item2->mapFromScene(210, 200), QPointF(10, 0));
+    QCOMPARE(item3->mapFromScene(310, 300), QPointF(10, 0));
+    QCOMPARE(item4->mapFromScene(410, 400), QPointF(10, 0));
+
+    // Rotate item1 90 degrees clockwise
+    QMatrix matrix; matrix.rotate(90);
+    item1->setMatrix(matrix);
+    QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
+    QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
+    QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
+    QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
+    QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
+    QCOMPARE(item2->mapToParent(10, 0), QPointF(110, 100));
+    QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
+    QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
+    QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
+    QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
+    QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 300));
+    QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 400));
+    QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
+    QCOMPARE(item2->mapToScene(10, 0), QPointF(0, 210));
+    QCOMPARE(item3->mapToScene(10, 0), QPointF(-100, 310));
+    QCOMPARE(item4->mapToScene(10, 0), QPointF(-200, 410));
+    QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
+    QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
+    QCOMPARE(item3->mapFromScene(-100, 300), QPointF(0, 0));
+    QCOMPARE(item4->mapFromScene(-200, 400), QPointF(0, 0));
+    QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
+    QCOMPARE(item2->mapFromScene(0, 210), QPointF(10, 0));
+    QCOMPARE(item3->mapFromScene(-100, 310), QPointF(10, 0));
+    QCOMPARE(item4->mapFromScene(-200, 410), QPointF(10, 0));
+
+    // Rotate item2 90 degrees clockwise
+    item2->setMatrix(matrix);
+    QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
+    QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
+    QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
+    QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
+    QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
+    QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
+    QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
+    QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
+    QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
+    QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
+    QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 100));
+    QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 0));
+    QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
+    QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
+    QCOMPARE(item3->mapToScene(10, 0), QPointF(-110, 100));
+    QCOMPARE(item4->mapToScene(10, 0), QPointF(-210, 0));
+    QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
+    QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
+    QCOMPARE(item3->mapFromScene(-100, 100), QPointF(0, 0));
+    QCOMPARE(item4->mapFromScene(-200, 0), QPointF(0, 0));
+    QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
+    QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
+    QCOMPARE(item3->mapFromScene(-110, 100), QPointF(10, 0));
+    QCOMPARE(item4->mapFromScene(-210, 0), QPointF(10, 0));
+
+    // Translate item3 50 points, then rotate 90 degrees counterclockwise
+    QMatrix matrix2;
+    matrix2.translate(50, 0);
+    matrix2.rotate(-90);
+    item3->setMatrix(matrix2);
+    QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
+    QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
+    QCOMPARE(item3->pos(), item3->mapToParent(0, 0) - QPointF(50, 0));
+    QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
+    QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
+    QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
+    QCOMPARE(item3->mapToParent(10, 0), QPointF(150, 90));
+    QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
+    QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
+    QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
+    QCOMPARE(item3->mapToScene(0, 0), QPointF(-150, 100));
+    QCOMPARE(item4->mapToScene(0, 0), QPointF(-250, 200));
+    QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
+    QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
+    QCOMPARE(item3->mapToScene(10, 0), QPointF(-150, 110));
+    QCOMPARE(item4->mapToScene(10, 0), QPointF(-250, 210));
+    QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
+    QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
+    QCOMPARE(item3->mapFromScene(-150, 100), QPointF(0, 0));
+    QCOMPARE(item4->mapFromScene(-250, 200), QPointF(0, 0));
+    QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
+    QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
+    QCOMPARE(item3->mapFromScene(-150, 110), QPointF(10, 0));
+    QCOMPARE(item4->mapFromScene(-250, 210), QPointF(10, 0));
+
+    delete item1;
+}
+
+void tst_QGraphicsItem::mapFromToItem()
+{
+    QGraphicsItem *item1 = new QGraphicsPathItem;
+    QGraphicsItem *item2 = new QGraphicsPathItem;
+    QGraphicsItem *item3 = new QGraphicsPathItem;
+    QGraphicsItem *item4 = new QGraphicsPathItem;
+
+    item1->setPos(-100, -100);
+    item2->setPos(100, -100);
+    item3->setPos(100, 100);
+    item4->setPos(-100, 100);
+
+    QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(200, 0));
+    QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200));
+    QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0));
+    QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(0, -200));
+    QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(0, 200));
+    QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-200, 0));
+    QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
+    QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
+
+    QMatrix matrix;
+    matrix.translate(100, 100);
+    item1->setMatrix(matrix);
+
+    QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(100, -100));
+    QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200));
+    QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0));
+    QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(100, -100));
+    QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(-100, 100));
+    QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-100, 100));
+    QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
+    QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
+
+    matrix.rotate(90);
+    item1->setMatrix(matrix);
+    item2->setMatrix(matrix);
+    item3->setMatrix(matrix);
+    item4->setMatrix(matrix);
+
+    QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(0, -200));
+    QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(200, 0));
+    QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(0, 200));
+    QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(-200, 0));
+    QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(200, 0));
+    QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(0, 200));
+    QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(-200, 0));
+    QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(0, -200));
+    QCOMPARE(item1->mapFromItem(item2, 10, -5), QPointF(10, -205));
+    QCOMPARE(item2->mapFromItem(item3, 10, -5), QPointF(210, -5));
+    QCOMPARE(item3->mapFromItem(item4, 10, -5), QPointF(10, 195));
+    QCOMPARE(item4->mapFromItem(item1, 10, -5), QPointF(-190, -5));
+    QCOMPARE(item1->mapFromItem(item4, 10, -5), QPointF(210, -5));
+    QCOMPARE(item2->mapFromItem(item1, 10, -5), QPointF(10, 195));
+    QCOMPARE(item3->mapFromItem(item2, 10, -5), QPointF(-190, -5));
+    QCOMPARE(item4->mapFromItem(item3, 10, -5), QPointF(10, -205));
+
+    QCOMPARE(item1->mapFromItem(0, 10, -5), item1->mapFromScene(10, -5));
+    QCOMPARE(item2->mapFromItem(0, 10, -5), item2->mapFromScene(10, -5));
+    QCOMPARE(item3->mapFromItem(0, 10, -5), item3->mapFromScene(10, -5));
+    QCOMPARE(item4->mapFromItem(0, 10, -5), item4->mapFromScene(10, -5));
+    QCOMPARE(item1->mapToItem(0, 10, -5), item1->mapToScene(10, -5));
+    QCOMPARE(item2->mapToItem(0, 10, -5), item2->mapToScene(10, -5));
+    QCOMPARE(item3->mapToItem(0, 10, -5), item3->mapToScene(10, -5));
+    QCOMPARE(item4->mapToItem(0, 10, -5), item4->mapToScene(10, -5));
+
+    delete item1;
+    delete item2;
+    delete item3;
+    delete item4;
+}
+
+void tst_QGraphicsItem::mapRectFromToParent_data()
+{
+    QTest::addColumn<bool>("parent");
+    QTest::addColumn<QPointF>("parentPos");
+    QTest::addColumn<QTransform>("parentTransform");
+    QTest::addColumn<QPointF>("pos");
+    QTest::addColumn<QTransform>("transform");
+    QTest::addColumn<QRectF>("inputRect");
+    QTest::addColumn<QRectF>("outputRect");
+
+    QTest::newRow("nil") << false << QPointF() << QTransform() << QPointF() << QTransform() << QRectF() << QRectF();
+    QTest::newRow("simple") << false << QPointF() << QTransform() << QPointF() << QTransform()
+                            << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
+    QTest::newRow("simple w/parent") << true
+                                     << QPointF() << QTransform()
+                                     << QPointF() << QTransform()
+                                     << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
+    QTest::newRow("simple w/parent parentPos") << true
+                                               << QPointF(50, 50) << QTransform()
+                                               << QPointF() << QTransform()
+                                               << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
+    QTest::newRow("simple w/parent parentPos parentRotation") << true
+                                                              << QPointF(50, 50) << QTransform().rotate(45)
+                                                              << QPointF() << QTransform()
+                                                              << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
+    QTest::newRow("pos w/parent") << true
+                                  << QPointF() << QTransform()
+                                  << QPointF(50, 50) << QTransform()
+                                  << QRectF(0, 0, 10, 10) << QRectF(50, 50, 10, 10);
+    QTest::newRow("rotation w/parent") << true
+                                       << QPointF() << QTransform()
+                                       << QPointF() << QTransform().rotate(90)
+                                       << QRectF(0, 0, 10, 10) << QRectF(-10, 0, 10, 10);
+    QTest::newRow("pos rotation w/parent") << true
+                                           << QPointF() << QTransform()
+                                           << QPointF(50, 50) << QTransform().rotate(90)
+                                           << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
+    QTest::newRow("pos rotation w/parent parentPos parentRotation") << true
+                                                                    << QPointF(-170, -190) << QTransform().rotate(90)
+                                                                    << QPointF(50, 50) << QTransform().rotate(90)
+                                                                    << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
+}
+
+void tst_QGraphicsItem::mapRectFromToParent()
+{
+    QFETCH(bool, parent);
+    QFETCH(QPointF, parentPos);
+    QFETCH(QTransform, parentTransform);
+    QFETCH(QPointF, pos);
+    QFETCH(QTransform, transform);
+    QFETCH(QRectF, inputRect);
+    QFETCH(QRectF, outputRect);
+
+    QGraphicsRectItem *rect = new QGraphicsRectItem;
+    rect->setPos(pos);
+    rect->setTransform(transform);
+
+    if (parent) {
+        QGraphicsRectItem *rectParent = new QGraphicsRectItem;
+        rect->setParentItem(rectParent);
+        rectParent->setPos(parentPos);
+        rectParent->setTransform(parentTransform);
+    }
+
+    // Make sure we use non-destructive transform operations (e.g., 90 degree
+    // rotations).
+    QCOMPARE(rect->mapRectToParent(inputRect), outputRect);
+    QCOMPARE(rect->mapRectFromParent(outputRect), inputRect);
+    QCOMPARE(rect->itemTransform(rect->parentItem()).mapRect(inputRect), outputRect);
+    QCOMPARE(rect->mapToParent(inputRect).boundingRect(), outputRect);
+    QCOMPARE(rect->mapToParent(QPolygonF(inputRect)).boundingRect(), outputRect);
+    QCOMPARE(rect->mapFromParent(outputRect).boundingRect(), inputRect);
+    QCOMPARE(rect->mapFromParent(QPolygonF(outputRect)).boundingRect(), inputRect);
+    QPainterPath inputPath;
+    inputPath.addRect(inputRect);
+    QPainterPath outputPath;
+    outputPath.addRect(outputRect);
+    QCOMPARE(rect->mapToParent(inputPath).boundingRect(), outputPath.boundingRect());
+    QCOMPARE(rect->mapFromParent(outputPath).boundingRect(), inputPath.boundingRect());
+}
+
+void tst_QGraphicsItem::isAncestorOf()
+{
+    QGraphicsItem *grandPa = new QGraphicsRectItem;
+    QGraphicsItem *parent = new QGraphicsRectItem;
+    QGraphicsItem *child = new QGraphicsRectItem;
+
+    QVERIFY(!parent->isAncestorOf(0));
+    QVERIFY(!child->isAncestorOf(0));
+    QVERIFY(!parent->isAncestorOf(child));
+    QVERIFY(!child->isAncestorOf(parent));
+    QVERIFY(!parent->isAncestorOf(parent));
+
+    child->setParentItem(parent);
+    parent->setParentItem(grandPa);
+
+    QVERIFY(parent->isAncestorOf(child));
+    QVERIFY(grandPa->isAncestorOf(parent));
+    QVERIFY(grandPa->isAncestorOf(child));
+    QVERIFY(!child->isAncestorOf(parent));
+    QVERIFY(!parent->isAncestorOf(grandPa));
+    QVERIFY(!child->isAncestorOf(grandPa));
+    QVERIFY(!child->isAncestorOf(child));
+    QVERIFY(!parent->isAncestorOf(parent));
+    QVERIFY(!grandPa->isAncestorOf(grandPa));
+
+    parent->setParentItem(0);
+
+    delete child;
+    delete parent;
+    delete grandPa;
+}
+
+void tst_QGraphicsItem::commonAncestorItem()
+{
+    QGraphicsItem *ancestor = new QGraphicsRectItem;
+    QGraphicsItem *grandMa = new QGraphicsRectItem;
+    QGraphicsItem *grandPa = new QGraphicsRectItem;
+    QGraphicsItem *brotherInLaw = new QGraphicsRectItem;
+    QGraphicsItem *cousin = new QGraphicsRectItem;
+    QGraphicsItem *husband = new QGraphicsRectItem;
+    QGraphicsItem *child = new QGraphicsRectItem;
+    QGraphicsItem *wife = new QGraphicsRectItem;
+
+    child->setParentItem(husband);
+    husband->setParentItem(grandPa);
+    brotherInLaw->setParentItem(grandPa);
+    cousin->setParentItem(brotherInLaw);
+    wife->setParentItem(grandMa);
+    grandMa->setParentItem(ancestor);
+    grandPa->setParentItem(ancestor);
+
+    QCOMPARE(grandMa->commonAncestorItem(grandMa), grandMa);
+    QCOMPARE(grandMa->commonAncestorItem(0), (QGraphicsItem *)0);
+    QCOMPARE(grandMa->commonAncestorItem(grandPa), ancestor);
+    QCOMPARE(grandPa->commonAncestorItem(grandMa), ancestor);
+    QCOMPARE(grandPa->commonAncestorItem(husband), grandPa);
+    QCOMPARE(grandPa->commonAncestorItem(wife), ancestor);
+    QCOMPARE(grandMa->commonAncestorItem(husband), ancestor);
+    QCOMPARE(grandMa->commonAncestorItem(wife), grandMa);
+    QCOMPARE(wife->commonAncestorItem(grandMa), grandMa);
+    QCOMPARE(child->commonAncestorItem(cousin), grandPa);
+    QCOMPARE(cousin->commonAncestorItem(child), grandPa);
+    QCOMPARE(wife->commonAncestorItem(child), ancestor);
+    QCOMPARE(child->commonAncestorItem(wife), ancestor);
+}
+
+void tst_QGraphicsItem::data()
+{
+    QGraphicsTextItem text;
+
+    QCOMPARE(text.data(0), QVariant());
+    text.setData(0, "TextItem");
+    QCOMPARE(text.data(0), QVariant(QString("TextItem")));
+    text.setData(0, QVariant());
+    QCOMPARE(text.data(0), QVariant());
+}
+
+void tst_QGraphicsItem::type()
+{
+    QCOMPARE(int(QGraphicsItem::Type), 1);
+    QCOMPARE(int(QGraphicsPathItem::Type), 2);
+    QCOMPARE(int(QGraphicsRectItem::Type), 3);
+    QCOMPARE(int(QGraphicsEllipseItem::Type), 4);
+    QCOMPARE(int(QGraphicsPolygonItem::Type), 5);
+    QCOMPARE(int(QGraphicsLineItem::Type), 6);
+    QCOMPARE(int(QGraphicsPixmapItem::Type), 7);
+    QCOMPARE(int(QGraphicsTextItem::Type), 8);
+
+    QCOMPARE(QGraphicsPathItem().type(), 2);
+    QCOMPARE(QGraphicsRectItem().type(), 3);
+    QCOMPARE(QGraphicsEllipseItem().type(), 4);
+    QCOMPARE(QGraphicsPolygonItem().type(), 5);
+    QCOMPARE(QGraphicsLineItem().type(), 6);
+    QCOMPARE(QGraphicsPixmapItem().type(), 7);
+    QCOMPARE(QGraphicsTextItem().type(), 8);
+}
+
+void tst_QGraphicsItem::graphicsitem_cast()
+{
+    QGraphicsPathItem pathItem;
+    const QGraphicsPathItem *pPathItem = &pathItem;
+    QGraphicsRectItem rectItem;
+    const QGraphicsRectItem *pRectItem = &rectItem;
+    QGraphicsEllipseItem ellipseItem;
+    const QGraphicsEllipseItem *pEllipseItem = &ellipseItem;
+    QGraphicsPolygonItem polygonItem;
+    const QGraphicsPolygonItem *pPolygonItem = &polygonItem;
+    QGraphicsLineItem lineItem;
+    const QGraphicsLineItem *pLineItem = &lineItem;
+    QGraphicsPixmapItem pixmapItem;
+    const QGraphicsPixmapItem *pPixmapItem = &pixmapItem;
+    QGraphicsTextItem textItem;
+    const QGraphicsTextItem *pTextItem = &textItem;
+
+    QVERIFY(qgraphicsitem_cast<QGraphicsPathItem *>(&pathItem));
+    //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&pathItem));
+    QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pathItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPathItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsPathItem *>(pPathItem));
+
+    QVERIFY(qgraphicsitem_cast<QGraphicsRectItem *>(&rectItem));
+    QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&rectItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pRectItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsRectItem *>(pRectItem));
+
+    QVERIFY(qgraphicsitem_cast<QGraphicsEllipseItem *>(&ellipseItem));
+    QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&ellipseItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pEllipseItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsEllipseItem *>(pEllipseItem));
+
+    QVERIFY(qgraphicsitem_cast<QGraphicsPolygonItem *>(&polygonItem));
+    //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&polygonItem));
+    QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&polygonItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPolygonItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsPolygonItem *>(pPolygonItem));
+
+    QVERIFY(qgraphicsitem_cast<QGraphicsLineItem *>(&lineItem));
+    QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&lineItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pLineItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsLineItem *>(pLineItem));
+
+    QVERIFY(qgraphicsitem_cast<QGraphicsPixmapItem *>(&pixmapItem));
+    QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pixmapItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPixmapItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsPixmapItem *>(pPixmapItem));
+
+    QVERIFY(qgraphicsitem_cast<QGraphicsTextItem *>(&textItem));
+    QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&textItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pTextItem));
+    QVERIFY(qgraphicsitem_cast<const QGraphicsTextItem *>(pTextItem));
+
+    // and some casts that _should_ fail:
+    QVERIFY(!qgraphicsitem_cast<QGraphicsEllipseItem *>(&pathItem));
+    QVERIFY(!qgraphicsitem_cast<const QGraphicsTextItem *>(pPolygonItem));
+
+    // and this shouldn't crash
+    QGraphicsItem *ptr = 0;
+    QVERIFY(!qgraphicsitem_cast<QGraphicsTextItem *>(ptr));
+    QVERIFY(!qgraphicsitem_cast<QGraphicsItem *>(ptr));
+}
+
+void tst_QGraphicsItem::hoverEventsGenerateRepaints()
+{
+    Q_CHECK_PAINTEVENTS
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(150);
+
+    EventTester *tester = new EventTester;
+    scene.addItem(tester);
+    tester->setAcceptsHoverEvents(true);
+
+    QTRY_COMPARE(tester->repaints, 1);
+
+    // Send a hover enter event
+    QGraphicsSceneHoverEvent hoverEnterEvent(QEvent::GraphicsSceneHoverEnter);
+    hoverEnterEvent.setScenePos(QPointF(0, 0));
+    hoverEnterEvent.setPos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &hoverEnterEvent);
+
+    // Check that we get a repaint
+    int npaints = tester->repaints;
+    qApp->processEvents();
+    qApp->processEvents();
+    QCOMPARE(tester->events.size(), 2); //  enter + move
+    QCOMPARE(tester->repaints, npaints + 1);
+    QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
+
+    // Send a hover move event
+    QGraphicsSceneHoverEvent hoverMoveEvent(QEvent::GraphicsSceneHoverMove);
+    hoverMoveEvent.setScenePos(QPointF(0, 0));
+    hoverMoveEvent.setPos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &hoverMoveEvent);
+
+    // Check that we don't get a repaint
+    qApp->processEvents();
+    qApp->processEvents();
+
+    QCOMPARE(tester->events.size(), 3);
+    QCOMPARE(tester->repaints, npaints + 1);
+    QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
+
+    // Send a hover leave event
+    QGraphicsSceneHoverEvent hoverLeaveEvent(QEvent::GraphicsSceneHoverLeave);
+    hoverLeaveEvent.setScenePos(QPointF(-100, -100));
+    hoverLeaveEvent.setPos(QPointF(0, 0));
+    QApplication::sendEvent(&scene, &hoverLeaveEvent);
+
+    // Check that we get a repaint
+    qApp->processEvents();
+    qApp->processEvents();
+
+    QCOMPARE(tester->events.size(), 4);
+    QCOMPARE(tester->repaints, npaints + 2);
+    QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverLeave);
+}
+
+void tst_QGraphicsItem::boundingRects_data()
+{
+    QTest::addColumn<QGraphicsItem *>("item");
+    QTest::addColumn<QRectF>("boundingRect");
+
+    QRectF rect(0, 0, 100, 100);
+    QPainterPath path;
+    path.addRect(rect);
+
+    QRectF adjustedRect(-0.5, -0.5, 101, 101);
+
+    QTest::newRow("path") << (QGraphicsItem *)new QGraphicsPathItem(path) << adjustedRect;
+    QTest::newRow("rect") << (QGraphicsItem *)new QGraphicsRectItem(rect) << adjustedRect;
+    QTest::newRow("ellipse") << (QGraphicsItem *)new QGraphicsEllipseItem(rect) << adjustedRect;
+    QTest::newRow("polygon") << (QGraphicsItem *)new QGraphicsPolygonItem(rect) << adjustedRect;
+}
+
+void tst_QGraphicsItem::boundingRects()
+{
+    QFETCH(QGraphicsItem *, item);
+    QFETCH(QRectF, boundingRect);
+
+    ((QAbstractGraphicsShapeItem *)item)->setPen(QPen(Qt::black, 1));
+    QCOMPARE(item->boundingRect(), boundingRect);
+}
+
+void tst_QGraphicsItem::boundingRects2()
+{
+    QGraphicsPixmapItem pixmap(QPixmap::fromImage(QImage(100, 100, QImage::Format_ARGB32_Premultiplied)));
+    QCOMPARE(pixmap.boundingRect(), QRectF(-0.5, -0.5, 101, 101));
+
+    QGraphicsLineItem line(0, 0, 100, 0);
+    line.setPen(QPen(Qt::black, 1));
+    QCOMPARE(line.boundingRect(), QRectF(-0.5, -0.5, 101, 1));
+}
+
+void tst_QGraphicsItem::sceneBoundingRect()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
+    item->setPos(100, 100);
+
+    QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
+    QCOMPARE(item->sceneBoundingRect(), QRectF(100, 100, 100, 100));
+
+    item->rotate(90);
+
+    QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
+    QCOMPARE(item->sceneBoundingRect(), QRectF(0, 100, 100, 100));
+}
+
+void tst_QGraphicsItem::childrenBoundingRect()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
+    QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
+    child->setParentItem(parent);
+    parent->setPos(100, 100);
+    child->setPos(100, 100);
+
+    QCOMPARE(parent->boundingRect(), QRectF(0, 0, 100, 100));
+    QCOMPARE(child->boundingRect(), QRectF(0, 0, 100, 100));
+    QCOMPARE(child->childrenBoundingRect(), QRectF());
+    QCOMPARE(parent->childrenBoundingRect(), QRectF(100, 100, 100, 100));
+
+    QGraphicsRectItem *child2 = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
+    child2->setParentItem(parent);
+    child2->setPos(-100, -100);
+    QCOMPARE(parent->childrenBoundingRect(), QRectF(-100, -100, 300, 300));
+
+    QGraphicsRectItem *childChild = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
+    childChild->setParentItem(child);
+    childChild->setPos(500, 500);
+    child->rotate(90);
+
+
+    scene.addPolygon(parent->mapToScene(parent->boundingRect() | parent->childrenBoundingRect()))->setPen(QPen(Qt::red));;
+
+    QGraphicsView view(&scene);
+    view.show();
+
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(30);
+
+    QCOMPARE(parent->childrenBoundingRect(), QRectF(-500, -100, 600, 800));
+}
+
+void tst_QGraphicsItem::childrenBoundingRectTransformed()
+{
+    QGraphicsScene scene;
+
+    QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
+    rect2->setParentItem(rect);
+    rect3->setParentItem(rect2);
+    rect4->setParentItem(rect3);
+    rect5->setParentItem(rect4);
+
+    rect2->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect2->setPos(25, 25);
+    rect3->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect3->setPos(25, 25);
+    rect4->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect4->setPos(25, 25);
+    rect5->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect5->setPos(25, 25);
+
+    QRectF subTreeRect = rect->childrenBoundingRect();
+    QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
+    QCOMPARE(subTreeRect.top(), qreal(75.0));
+    QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
+    QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
+
+    rect->rotate(45);
+    rect2->rotate(-45);
+    rect3->rotate(45);
+    rect4->rotate(-45);
+    rect5->rotate(45);
+
+    subTreeRect = rect->childrenBoundingRect();
+    QCOMPARE(rect->childrenBoundingRect(), QRectF(-100, 75, 275, 250));
+}
+
+void tst_QGraphicsItem::childrenBoundingRect2()
+{
+    QGraphicsItemGroup box;
+    QGraphicsLineItem l1(0, 0, 100, 0, &box);
+    QGraphicsLineItem l2(100, 0, 100, 100, &box);
+    QGraphicsLineItem l3(0, 0, 0, 100, &box);
+    // Make sure lines (zero with/height) are included in the childrenBoundingRect.
+    QCOMPARE(box.childrenBoundingRect(), QRectF(0, 0, 100, 100));
+}
+
+void tst_QGraphicsItem::childrenBoundingRect3()
+{
+    QGraphicsScene scene;
+
+    QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
+    rect2->setParentItem(rect);
+    rect3->setParentItem(rect2);
+    rect4->setParentItem(rect3);
+    rect5->setParentItem(rect4);
+
+    rect2->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect2->setPos(25, 25);
+    rect3->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect3->setPos(25, 25);
+    rect4->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect4->setPos(25, 25);
+    rect5->setTransform(QTransform().translate(50, 50).rotate(45));
+    rect5->setPos(25, 25);
+
+    // Try to mess up the cached bounding rect.
+    (void)rect2->childrenBoundingRect();
+
+    QRectF subTreeRect = rect->childrenBoundingRect();
+    QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
+    QCOMPARE(subTreeRect.top(), qreal(75.0));
+    QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
+    QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
+}
+
+void tst_QGraphicsItem::group()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::green));
+    QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::blue));
+    QGraphicsRectItem *parent2 = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::red));
+    parent2->setPos(-50, 50);
+    child->rotate(45);
+    child->setParentItem(parent);
+    parent->setPos(25, 25);
+    child->setPos(25, 25);
+
+    QCOMPARE(parent->group(), (QGraphicsItemGroup *)0);
+    QCOMPARE(parent2->group(), (QGraphicsItemGroup *)0);
+    QCOMPARE(child->group(), (QGraphicsItemGroup *)0);
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+
+    QGraphicsItemGroup *group = new QGraphicsItemGroup;
+    group->setSelected(true);
+    scene.addItem(group);
+
+    QRectF parentSceneBoundingRect = parent->sceneBoundingRect();
+    group->addToGroup(parent);
+    QCOMPARE(parent->group(), group);
+    QCOMPARE(parent->sceneBoundingRect(), parentSceneBoundingRect);
+
+    QCOMPARE(parent->parentItem(), (QGraphicsItem *)group);
+    QCOMPARE(group->children().size(), 1);
+    QCOMPARE(scene.items().size(), 4);
+    QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 3);
+
+    QTest::qWait(25);
+
+    QRectF parent2SceneBoundingRect = parent2->sceneBoundingRect();
+    group->addToGroup(parent2);
+    QCOMPARE(parent2->group(), group);
+    QCOMPARE(parent2->sceneBoundingRect(), parent2SceneBoundingRect);
+
+    QCOMPARE(parent2->parentItem(), (QGraphicsItem *)group);
+    QCOMPARE(group->children().size(), 2);
+    QCOMPARE(scene.items().size(), 4);
+    QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 4);
+
+    QTest::qWait(25);
+
+    QList<QGraphicsItem *> newItems;
+    for (int i = 0; i < 100; ++i) {
+        QGraphicsItem *item = scene.addRect(QRectF(-25, -25, 50, 50), QPen(Qt::black, 0),
+                                            QBrush(QColor(rand() % 255, rand() % 255,
+                                                          rand() % 255, rand() % 255)));
+        newItems << item;
+        item->setPos(-1000 + rand() % 2000,
+                     -1000 + rand() % 2000);
+        item->rotate(rand() % 90);
+    }
+
+    view.fitInView(scene.itemsBoundingRect());
+
+    int n = 0;
+    foreach (QGraphicsItem *item, newItems) {
+        group->addToGroup(item);
+        QCOMPARE(item->group(), group);
+        if ((n++ % 100) == 0)
+            QTest::qWait(10);
+    }
+}
+
+void tst_QGraphicsItem::setGroup()
+{
+    QGraphicsItemGroup group1;
+    QGraphicsItemGroup group2;
+
+    QGraphicsRectItem *rect = new QGraphicsRectItem;
+    QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
+    QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
+    rect->setGroup(&group1);
+    QCOMPARE(rect->group(), &group1);
+    QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group1);
+    rect->setGroup(&group2);
+    QCOMPARE(rect->group(), &group2);
+    QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group2);
+    rect->setGroup(0);
+    QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
+    QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsItem::nestedGroups()
+{
+    QGraphicsItemGroup *group1 = new QGraphicsItemGroup;
+    QGraphicsItemGroup *group2 = new QGraphicsItemGroup;
+
+    QGraphicsRectItem *rect = new QGraphicsRectItem;
+    QGraphicsRectItem *rect2 = new QGraphicsRectItem;
+    rect2->setParentItem(rect);
+
+    group1->addToGroup(rect);
+    QCOMPARE(rect->group(), group1);
+    QCOMPARE(rect2->group(), group1);
+
+    group2->addToGroup(group1);
+    QCOMPARE(rect->group(), group1);
+    QCOMPARE(rect2->group(), group1);
+    QCOMPARE(group1->group(), group2);
+    QCOMPARE(group2->group(), (QGraphicsItemGroup *)0);
+
+    QGraphicsScene scene;
+    scene.addItem(group1);
+
+    QCOMPARE(rect->group(), group1);
+    QCOMPARE(rect2->group(), group1);
+    QCOMPARE(group1->group(), (QGraphicsItemGroup *)0);
+    QVERIFY(group2->children().isEmpty());
+
+    delete group2;
+}
+
+void tst_QGraphicsItem::warpChildrenIntoGroup()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *parentRectItem = scene.addRect(QRectF(0, 0, 100, 100));
+    QGraphicsRectItem *childRectItem = scene.addRect(QRectF(0, 0, 100, 100));
+    parentRectItem->rotate(90);
+    childRectItem->setPos(-50, -25);
+    childRectItem->setParentItem(parentRectItem);
+
+    QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
+    QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
+
+    QGraphicsRectItem *parentOfGroup = scene.addRect(QRectF(0, 0, 100, 100));
+    parentOfGroup->setPos(-200, -200);
+    parentOfGroup->scale(2, 2);
+
+    QGraphicsItemGroup *group = new QGraphicsItemGroup;
+    group->setPos(50, 50);
+    group->setParentItem(parentOfGroup);
+
+    QCOMPARE(group->scenePos(), QPointF(-100, -100));
+
+    group->addToGroup(childRectItem);
+
+    QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
+    QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
+}
+
+void tst_QGraphicsItem::removeFromGroup()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect1 = scene.addRect(QRectF(-100, -100, 200, 200));
+    QGraphicsRectItem *rect2 = scene.addRect(QRectF(100, 100, 200, 200));
+    rect1->setFlag(QGraphicsItem::ItemIsSelectable);
+    rect2->setFlag(QGraphicsItem::ItemIsSelectable);
+    rect1->setSelected(true);
+    rect2->setSelected(true);
+
+    QGraphicsView view(&scene);
+    view.show();
+
+    qApp->processEvents(); // index items
+    qApp->processEvents(); // emit changed
+
+    QGraphicsItemGroup *group = scene.createItemGroup(scene.selectedItems());
+    QVERIFY(group);
+    QCOMPARE(group->children().size(), 2);
+    qApp->processEvents(); // index items
+    qApp->processEvents(); // emit changed
+
+    scene.destroyItemGroup(group); // calls removeFromGroup.
+
+    qApp->processEvents(); // index items
+    qApp->processEvents(); // emit changed
+
+    QCOMPARE(scene.items().size(), 2);
+    QVERIFY(!rect1->group());
+    QVERIFY(!rect2->group());
+}
+
+class ChildEventTester : public QGraphicsRectItem
+{
+public:
+    ChildEventTester(const QRectF &rect, QGraphicsItem *parent = 0)
+        : QGraphicsRectItem(rect, parent), counter(0)
+    { }
+
+    int counter;
+
+protected:
+    void focusInEvent(QFocusEvent *event)
+    { ++counter; QGraphicsRectItem::focusInEvent(event); }
+    void mousePressEvent(QGraphicsSceneMouseEvent *)
+    { ++counter; }
+    void mouseMoveEvent(QGraphicsSceneMouseEvent *)
+    { ++counter; }
+    void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
+    { ++counter; }
+};
+
+void tst_QGraphicsItem::handlesChildEvents()
+{
+    ChildEventTester *blue = new ChildEventTester(QRectF(0, 0, 100, 100));
+    ChildEventTester *red = new ChildEventTester(QRectF(0, 0, 50, 50));
+    ChildEventTester *green = new ChildEventTester(QRectF(0, 0, 25, 25));
+    ChildEventTester *gray = new ChildEventTester(QRectF(0, 0, 25, 25));
+    ChildEventTester *yellow = new ChildEventTester(QRectF(0, 0, 50, 50));
+
+    blue->setBrush(QBrush(Qt::blue));
+    red->setBrush(QBrush(Qt::red));
+    yellow->setBrush(QBrush(Qt::yellow));
+    green->setBrush(QBrush(Qt::green));
+    gray->setBrush(QBrush(Qt::gray));
+    red->setPos(50, 0);
+    yellow->setPos(50, 50);
+    green->setPos(25, 0);
+    gray->setPos(25, 25);
+    red->setParentItem(blue);
+    yellow->setParentItem(blue);
+    green->setParentItem(red);
+    gray->setParentItem(red);
+
+    QGraphicsScene scene;
+    scene.addItem(blue);
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(20);
+
+    // Pull out the items, closest item first
+    QList<QGraphicsItem *> items = scene.items(scene.itemsBoundingRect());
+    QCOMPARE(items.at(0), (QGraphicsItem *)yellow);
+    QCOMPARE(items.at(1), (QGraphicsItem *)gray);
+    QCOMPARE(items.at(2), (QGraphicsItem *)green);
+    QCOMPARE(items.at(3), (QGraphicsItem *)red);
+    QCOMPARE(items.at(4), (QGraphicsItem *)blue);
+
+    QCOMPARE(blue->counter, 0);
+
+    // Send events to the toplevel item
+    QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+    QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
+
+    pressEvent.setButton(Qt::LeftButton);
+    pressEvent.setScenePos(blue->mapToScene(5, 5));
+    pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    releaseEvent.setButton(Qt::LeftButton);
+    releaseEvent.setScenePos(blue->mapToScene(5, 5));
+    releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    QApplication::sendEvent(&scene, &pressEvent);
+    QApplication::sendEvent(&scene, &releaseEvent);
+
+    QCOMPARE(blue->counter, 2);
+
+    // Send events to a level1 item
+    pressEvent.setScenePos(red->mapToScene(5, 5));
+    pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    releaseEvent.setScenePos(red->mapToScene(5, 5));
+    releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
+    QApplication::sendEvent(&scene, &pressEvent);
+    QApplication::sendEvent(&scene, &releaseEvent);
+
+    QCOMPARE(blue->counter, 2);
+    QCOMPARE(red->counter, 2);
+
+    // Send events to a level2 item
+    pressEvent.setScenePos(green->mapToScene(5, 5));
+    pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    releaseEvent.setScenePos(green->mapToScene(5, 5));
+    releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
+    QApplication::sendEvent(&scene, &pressEvent);
+    QApplication::sendEvent(&scene, &releaseEvent);
+
+    QCOMPARE(blue->counter, 2);
+    QCOMPARE(red->counter, 2);
+    QCOMPARE(green->counter, 2);
+
+    blue->setHandlesChildEvents(true);
+
+    // Send events to a level1 item
+    pressEvent.setScenePos(red->mapToScene(5, 5));
+    pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    releaseEvent.setScenePos(red->mapToScene(5, 5));
+    releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
+    QApplication::sendEvent(&scene, &pressEvent);
+    QApplication::sendEvent(&scene, &releaseEvent);
+
+    QCOMPARE(blue->counter, 4);
+    QCOMPARE(red->counter, 2);
+
+    // Send events to a level2 item
+    pressEvent.setScenePos(green->mapToScene(5, 5));
+    pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    releaseEvent.setScenePos(green->mapToScene(5, 5));
+    releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
+    QApplication::sendEvent(&scene, &pressEvent);
+    QApplication::sendEvent(&scene, &releaseEvent);
+
+    QCOMPARE(blue->counter, 6);
+    QCOMPARE(red->counter, 2);
+    QCOMPARE(green->counter, 2);
+
+    blue->setHandlesChildEvents(false);
+
+    // Send events to a level1 item
+    pressEvent.setScenePos(red->mapToScene(5, 5));
+    pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    releaseEvent.setScenePos(red->mapToScene(5, 5));
+    releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
+    QApplication::sendEvent(&scene, &pressEvent);
+    QApplication::sendEvent(&scene, &releaseEvent);
+
+    QCOMPARE(blue->counter, 6);
+    QCOMPARE(red->counter, 4);
+
+    // Send events to a level2 item
+    pressEvent.setScenePos(green->mapToScene(5, 5));
+    pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
+    releaseEvent.setScenePos(green->mapToScene(5, 5));
+    releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
+    QApplication::sendEvent(&scene, &pressEvent);
+    QApplication::sendEvent(&scene, &releaseEvent);
+
+    QCOMPARE(blue->counter, 6);
+    QCOMPARE(red->counter, 4);
+    QCOMPARE(green->counter, 4);
+}
+
+void tst_QGraphicsItem::handlesChildEvents2()
+{
+    ChildEventTester *root = new ChildEventTester(QRectF(0, 0, 10, 10));
+    root->setHandlesChildEvents(true);
+    QVERIFY(root->handlesChildEvents());
+
+    ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
+    QVERIFY(!child->handlesChildEvents());
+
+    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->handlesChildEvents());
+    QVERIFY(!child3->handlesChildEvents());
+    QVERIFY(!child4->handlesChildEvents());
+
+    QGraphicsScene scene;
+    scene.addItem(root);
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+
+    QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
+                      view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
+    QApplication::sendEvent(view.viewport(), &event);
+
+    QTRY_COMPARE(root->counter, 1);
+}
+
+void tst_QGraphicsItem::handlesChildEvents3()
+{
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    ChildEventTester *group2 = new ChildEventTester(QRectF(), 0);
+    ChildEventTester *group1 = new ChildEventTester(QRectF(), group2);
+    ChildEventTester *leaf = new ChildEventTester(QRectF(), group1);
+    scene.addItem(group2);
+
+    leaf->setFlag(QGraphicsItem::ItemIsFocusable);
+    group1->setFlag(QGraphicsItem::ItemIsFocusable);
+    group1->setHandlesChildEvents(true);
+    group2->setFlag(QGraphicsItem::ItemIsFocusable);
+    group2->setHandlesChildEvents(true);
+
+    leaf->setFocus();
+    QVERIFY(leaf->hasFocus()); // group2 stole the event, but leaf still got focus
+    QVERIFY(!group1->hasFocus());
+    QVERIFY(!group2->hasFocus());
+    QCOMPARE(leaf->counter, 0);
+    QCOMPARE(group1->counter, 0);
+    QCOMPARE(group2->counter, 1);
+
+    group1->setFocus();
+    QVERIFY(group1->hasFocus()); // group2 stole the event, but group1 still got focus
+    QVERIFY(!leaf->hasFocus());
+    QVERIFY(!group2->hasFocus());
+    QCOMPARE(leaf->counter, 0);
+    QCOMPARE(group1->counter, 0);
+    QCOMPARE(group2->counter, 2);
+
+    group2->setFocus();
+    QVERIFY(group2->hasFocus()); // group2 stole the event, and now group2 also has focus
+    QVERIFY(!leaf->hasFocus());
+    QVERIFY(!group1->hasFocus());
+    QCOMPARE(leaf->counter, 0);
+    QCOMPARE(group1->counter, 0);
+    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::qWaitForWindowShown(&view);
+    QTest::qWait(20);
+
+    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);
+
+    QTRY_COMPARE(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();
+
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+
+    QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
+                      view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
+    QApplication::sendEvent(view.viewport(), &event);
+
+    QTRY_COMPARE(root->counter, 1);
+    QCOMPARE(child->counter, 0);
+    QCOMPARE(child2->counter, 0);
+    QCOMPARE(child3->counter, 0);
+    QCOMPARE(child4->counter, 0);
+}
+
+class CustomItem : public QGraphicsItem
+{
+public:
+    QRectF boundingRect() const
+    { return QRectF(-110, -110, 220, 220); }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+    {
+        for (int x = -100; x <= 100; x += 25)
+            painter->drawLine(x, -100, x, 100);
+        for (int y = -100; y <= 100; y += 25)
+            painter->drawLine(-100, y, 100, y);
+
+        QFont font = painter->font();
+        font.setPointSize(4);
+        painter->setFont(font);
+        for (int x = -100; x < 100; x += 25) {
+            for (int y = -100; y < 100; y += 25) {
+                painter->drawText(QRectF(x, y, 25, 25), Qt::AlignCenter, QString("%1x%2").arg(x).arg(y));
+            }
+        }
+    }
+};
+
+void tst_QGraphicsItem::ensureVisible()
+{
+    QGraphicsScene scene;
+    scene.setSceneRect(-200, -200, 400, 400);
+    QGraphicsItem *item = new CustomItem;
+    scene.addItem(item);
+
+    QGraphicsView view(&scene);
+    view.setFixedSize(300, 300);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+
+    for (int i = 0; i < 25; ++i) {
+        view.scale(qreal(1.06), qreal(1.06));
+        QApplication::processEvents();
+    }
+
+    item->ensureVisible(-100, -100, 25, 25);
+    QTest::qWait(25);
+
+    for (int x = -100; x < 100; x += 25) {
+        for (int y = -100; y < 100; y += 25) {
+            int xmargin = rand() % 75;
+            int ymargin = rand() % 75;
+            item->ensureVisible(x, y, 25, 25, xmargin, ymargin);
+            QApplication::processEvents();
+
+            QPolygonF viewScenePoly;
+            viewScenePoly << view.mapToScene(view.rect().topLeft())
+                          << view.mapToScene(view.rect().topRight())
+                          << view.mapToScene(view.rect().bottomRight())
+                          << view.mapToScene(view.rect().bottomLeft());
+
+            QVERIFY(scene.items(viewScenePoly).contains(item));
+
+            QPainterPath path;
+            path.addPolygon(viewScenePoly);
+            QVERIFY(path.contains(item->mapToScene(x + 12, y + 12)));
+
+            QPolygonF viewScenePolyMinusMargins;
+            viewScenePolyMinusMargins << view.mapToScene(view.rect().topLeft() + QPoint(xmargin, ymargin))
+                          << view.mapToScene(view.rect().topRight() + QPoint(-xmargin, ymargin))
+                          << view.mapToScene(view.rect().bottomRight() + QPoint(-xmargin, -ymargin))
+                          << view.mapToScene(view.rect().bottomLeft() + QPoint(xmargin, -ymargin));
+
+            QPainterPath path2;
+            path2.addPolygon(viewScenePolyMinusMargins);
+            QVERIFY(path2.contains(item->mapToScene(x + 12, y + 12)));
+        }
+    }
+
+    item->ensureVisible(100, 100, 25, 25);
+    QTest::qWait(25);
+}
+
+void tst_QGraphicsItem::cursor()
+{
+#ifndef QT_NO_CURSOR
+    QGraphicsScene scene;
+    QGraphicsRectItem *item1 = scene.addRect(QRectF(0, 0, 50, 50));
+    QGraphicsRectItem *item2 = scene.addRect(QRectF(0, 0, 50, 50));
+    item1->setPos(-100, 0);
+    item2->setPos(50, 0);
+
+    QVERIFY(!item1->hasCursor());
+    QVERIFY(!item2->hasCursor());
+
+    item1->setCursor(Qt::IBeamCursor);
+    item2->setCursor(Qt::PointingHandCursor);
+
+    QVERIFY(item1->hasCursor());
+    QVERIFY(item2->hasCursor());
+
+    item1->setCursor(QCursor());
+    item2->setCursor(QCursor());
+
+    QVERIFY(item1->hasCursor());
+    QVERIFY(item2->hasCursor());
+
+    item1->unsetCursor();
+    item2->unsetCursor();
+
+    QVERIFY(!item1->hasCursor());
+    QVERIFY(!item2->hasCursor());
+
+    item1->setCursor(Qt::IBeamCursor);
+    item2->setCursor(Qt::PointingHandCursor);
+
+    QGraphicsView view(&scene);
+    view.setFixedSize(200, 100);
+    view.show();
+    QTest::mouseMove(&view, view.rect().center());
+
+    QTest::qWait(25);
+
+    QCursor cursor = view.viewport()->cursor();
+
+    {
+        QMouseEvent event(QEvent::MouseMove, QPoint(100, 50), Qt::NoButton, 0, 0);
+        QApplication::sendEvent(view.viewport(), &event);
+    }
+
+    QTest::qWait(25);
+
+    QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
+
+    {
+        QTest::mouseMove(view.viewport(), view.mapFromScene(item1->sceneBoundingRect().center()));
+        QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
+        QApplication::sendEvent(view.viewport(), &event);
+    }
+
+#if !defined(Q_OS_WINCE)
+    QTest::qWait(250);
+#else
+    // Test environment does not have any cursor, therefore no shape
+    return;
+#endif
+
+    QCOMPARE(view.viewport()->cursor().shape(), item1->cursor().shape());
+
+    {
+        QTest::mouseMove(view.viewport(), view.mapFromScene(item2->sceneBoundingRect().center()));
+        QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item2->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
+        QApplication::sendEvent(view.viewport(), &event);
+    }
+
+    QTest::qWait(25);
+
+    QCOMPARE(view.viewport()->cursor().shape(), item2->cursor().shape());
+
+    {
+        QTest::mouseMove(view.viewport(), view.rect().center());
+        QMouseEvent event(QEvent::MouseMove, QPoint(100, 25), Qt::NoButton, 0, 0);
+        QApplication::sendEvent(view.viewport(), &event);
+    }
+
+    QTest::qWait(25);
+
+    QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
+#endif
+}
+/*
+void tst_QGraphicsItem::textControlGetterSetter()
+{
+    QGraphicsTextItem *item = new QGraphicsTextItem;
+    QVERIFY(item->textControl()->parent() == item);
+    QPointer<QTextControl> control = item->textControl();
+    delete item;
+    QVERIFY(!control);
+
+    item = new QGraphicsTextItem;
+
+    QPointer<QTextControl> oldControl = control;
+    control = new QTextControl;
+
+    item->setTextControl(control);
+    QVERIFY(item->textControl() == control);
+    QVERIFY(!control->parent());
+    QVERIFY(!oldControl);
+
+    // set some text to give it a size, to test that
+    // setTextControl (re)connects signals
+    const QRectF oldBoundingRect = item->boundingRect();
+    QVERIFY(oldBoundingRect.isValid());
+    item->setPlainText("Some text");
+    item->adjustSize();
+    QVERIFY(item->boundingRect().isValid());
+    QVERIFY(item->boundingRect() != oldBoundingRect);
+
+    // test that on setting a control the item size
+    // is adjusted
+    oldControl = control;
+    control = new QTextControl;
+    control->setPlainText("foo!");
+    item->setTextControl(control);
+    QCOMPARE(item->boundingRect().size(), control->document()->documentLayout()->documentSize());
+
+    QVERIFY(oldControl);
+    delete oldControl;
+
+    delete item;
+    QVERIFY(control);
+    delete control;
+}
+*/
+
+void tst_QGraphicsItem::defaultItemTest_QGraphicsLineItem()
+{
+    QGraphicsLineItem item;
+    QCOMPARE(item.line(), QLineF());
+    QCOMPARE(item.pen(), QPen());
+    QCOMPARE(item.shape(), QPainterPath());
+
+    item.setPen(QPen(Qt::black, 1));
+    QCOMPARE(item.pen(), QPen(Qt::black, 1));
+    item.setLine(QLineF(0, 0, 10, 0));
+    QCOMPARE(item.line(), QLineF(0, 0, 10, 0));
+    QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 11, 1));
+    QCOMPARE(item.shape().elementCount(), 11);
+
+    QPainterPath path;
+    path.moveTo(0, -0.5);
+    path.lineTo(10, -0.5);
+    path.lineTo(10.5, -0.5);
+    path.lineTo(10.5, 0.5);
+    path.lineTo(10, 0.5);
+    path.lineTo(0, 0.5);
+    path.lineTo(-0.5, 0.5);
+    path.lineTo(-0.5, -0.5);
+    path.lineTo(0, -0.5);
+    path.lineTo(0, 0);
+    path.lineTo(10, 0);
+    path.closeSubpath();
+
+    for (int i = 0; i < 11; ++i)
+        QCOMPARE(QPointF(item.shape().elementAt(i)), QPointF(path.elementAt(i)));
+}
+
+void tst_QGraphicsItem::defaultItemTest_QGraphicsPixmapItem()
+{
+    QGraphicsPixmapItem item;
+    QVERIFY(item.pixmap().isNull());
+    QCOMPARE(item.offset(), QPointF());
+    QCOMPARE(item.transformationMode(), Qt::FastTransformation);
+
+    QPixmap pixmap(300, 200);
+    pixmap.fill(Qt::red);
+    item.setPixmap(pixmap);
+    QCOMPARE(item.pixmap(), pixmap);
+
+    item.setTransformationMode(Qt::FastTransformation);
+    QCOMPARE(item.transformationMode(), Qt::FastTransformation);
+    item.setTransformationMode(Qt::SmoothTransformation);
+    QCOMPARE(item.transformationMode(), Qt::SmoothTransformation);
+
+    item.setOffset(-15, -15);
+    QCOMPARE(item.offset(), QPointF(-15, -15));
+    item.setOffset(QPointF(-10, -10));
+    QCOMPARE(item.offset(), QPointF(-10, -10));
+
+    QCOMPARE(item.boundingRect(), QRectF(-10.5, -10.5, 301, 201));
+}
+
+void tst_QGraphicsItem::defaultItemTest_QGraphicsTextItem()
+{
+    QGraphicsTextItem *text = new QGraphicsTextItem;
+    QVERIFY(!text->openExternalLinks());
+    QVERIFY(text->textCursor().isNull());
+    QCOMPARE(text->defaultTextColor(), QPalette().color(QPalette::Text));
+    QVERIFY(text->document() != 0);
+    QCOMPARE(text->font(), QApplication::font());
+    QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::NoTextInteraction));
+    QCOMPARE(text->textWidth(), -1.0);
+    QCOMPARE(text->toPlainText(), QString(""));
+
+    QGraphicsScene scene;
+    scene.addItem(text);
+    text->setPlainText("Hello world");
+    text->setFlag(QGraphicsItem::ItemIsMovable);
+
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+        event.setScenePos(QPointF(1, 1));
+        event.setButton(Qt::LeftButton);
+        event.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event);
+        QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
+        event2.setScenePos(QPointF(11, 11));
+        event2.setButton(Qt::LeftButton);
+        event2.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event2);
+    }
+
+    QCOMPARE(text->pos(), QPointF(10, 10));
+
+    text->setTextInteractionFlags(Qt::TextEditorInteraction);
+    QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::TextEditorInteraction));
+
+    {
+        QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
+        event2.setScenePos(QPointF(21, 21));
+        event2.setButton(Qt::LeftButton);
+        event2.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event2);
+    }
+
+    QCOMPARE(text->pos(), QPointF(20, 20)); // clicked on edge, item moved
+}
+
+void tst_QGraphicsItem::defaultItemTest_QGraphicsEllipseItem()
+{
+    QGraphicsEllipseItem item;
+    QVERIFY(item.rect().isNull());
+    QVERIFY(item.boundingRect().isNull());
+    QVERIFY(item.shape().isEmpty());
+    QCOMPARE(item.spanAngle(), 360 * 16);
+    QCOMPARE(item.startAngle(), 0);
+
+    item.setRect(0, 0, 100, 100);
+    QCOMPARE(item.boundingRect(), QRectF(0, 0, 100, 100));
+
+    item.setSpanAngle(90 * 16);
+    qFuzzyCompare(item.boundingRect().left(), qreal(50.0));
+    qFuzzyCompare(item.boundingRect().top(), qreal(0.0));
+    qFuzzyCompare(item.boundingRect().width(), qreal(50.0));
+    qFuzzyCompare(item.boundingRect().height(), qreal(50.0));
+
+    item.setPen(QPen(Qt::black, 1));
+    QCOMPARE(item.boundingRect(), QRectF(49.5, -0.5, 51, 51));
+
+    item.setSpanAngle(180 * 16);
+    QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 51));
+
+    item.setSpanAngle(360 * 16);
+    QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 101));
+}
+
+class ItemChangeTester : public QGraphicsRectItem
+{
+public:
+    ItemChangeTester()
+    { setFlag(ItemSendsGeometryChanges); clear(); }
+    ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent)
+    { setFlag(ItemSendsGeometryChanges); clear(); }
+
+    void clear()
+    {
+        itemChangeReturnValue = QVariant();
+        itemSceneChangeTargetScene = 0;
+        changes.clear();
+        values.clear();
+        oldValues.clear();
+    }
+
+    QVariant itemChangeReturnValue;
+    QGraphicsScene *itemSceneChangeTargetScene;
+
+    QList<GraphicsItemChange> changes;
+    QList<QVariant> values;
+    QList<QVariant> oldValues;
+protected:
+    QVariant itemChange(GraphicsItemChange change, const QVariant &value)
+    {
+        changes << change;
+        values << value;
+        switch (change) {
+        case QGraphicsItem::ItemPositionChange:
+            oldValues << pos();
+            break;
+        case QGraphicsItem::ItemPositionHasChanged:
+            break;
+        case QGraphicsItem::ItemMatrixChange: {
+            QVariant variant;
+            qVariantSetValue<QMatrix>(variant, matrix());
+            oldValues << variant;
+        }
+            break;
+        case QGraphicsItem::ItemTransformChange: {
+            QVariant variant;
+            qVariantSetValue<QTransform>(variant, transform());
+            oldValues << variant;
+        }
+            break;
+        case QGraphicsItem::ItemTransformHasChanged:
+            break;
+        case QGraphicsItem::ItemVisibleChange:
+            oldValues << isVisible();
+            break;
+        case QGraphicsItem::ItemVisibleHasChanged:
+            break;
+        case QGraphicsItem::ItemEnabledChange:
+            oldValues << isEnabled();
+            break;
+        case QGraphicsItem::ItemEnabledHasChanged:
+            break;
+        case QGraphicsItem::ItemSelectedChange:
+            oldValues << isSelected();
+            break;
+        case QGraphicsItem::ItemSelectedHasChanged:
+            break;
+        case QGraphicsItem::ItemParentChange:
+            oldValues << qVariantFromValue<void *>(parentItem());
+            break;
+        case QGraphicsItem::ItemParentHasChanged:
+            break;
+        case QGraphicsItem::ItemChildAddedChange:
+            oldValues << children().size();
+            break;
+        case QGraphicsItem::ItemChildRemovedChange:
+            oldValues << children().size();
+            break;
+        case QGraphicsItem::ItemSceneChange:
+            oldValues << qVariantFromValue<QGraphicsScene *>(scene());
+            if (itemSceneChangeTargetScene
+                && qVariantValue<QGraphicsScene *>(value)
+                && itemSceneChangeTargetScene != qVariantValue<QGraphicsScene *>(value)) {
+                return qVariantFromValue<QGraphicsScene *>(itemSceneChangeTargetScene);
+            }
+            return value;
+        case QGraphicsItem::ItemSceneHasChanged:
+            break;
+        case QGraphicsItem::ItemCursorChange:
+#ifndef QT_NO_CURSOR
+            oldValues << cursor();
+#endif
+            break;
+        case QGraphicsItem::ItemCursorHasChanged:
+            break;
+        case QGraphicsItem::ItemToolTipChange:
+            oldValues << toolTip();
+            break;
+        case QGraphicsItem::ItemToolTipHasChanged:
+            break;
+        case QGraphicsItem::ItemFlagsChange:
+            oldValues << quint32(flags());
+            break;
+        case QGraphicsItem::ItemFlagsHaveChanged:
+            break;
+        case QGraphicsItem::ItemZValueChange:
+            oldValues << zValue();
+            break;
+        case QGraphicsItem::ItemZValueHasChanged:
+            break;
+        case QGraphicsItem::ItemOpacityChange:
+            oldValues << opacity();
+            break;
+        case QGraphicsItem::ItemOpacityHasChanged:
+            break;
+        }
+        return itemChangeReturnValue.isValid() ? itemChangeReturnValue : value;
+    }
+};
+
+void tst_QGraphicsItem::itemChange()
+{
+    ItemChangeTester tester;
+    tester.itemSceneChangeTargetScene = 0;
+
+    ItemChangeTester testerHelper;
+    QVERIFY(tester.changes.isEmpty());
+    QVERIFY(tester.values.isEmpty());
+
+    int changeCount = 0;
+    {
+        // ItemEnabledChange
+        tester.itemChangeReturnValue = true;
+        tester.setEnabled(false);
+        ++changeCount;
+        ++changeCount; // HasChanged
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemEnabledChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemEnabledHasChanged);
+        QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
+        QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
+        QCOMPARE(tester.oldValues.last(), QVariant(true));
+        QCOMPARE(tester.isEnabled(), true);
+    }
+    {
+        // ItemMatrixChange / ItemTransformHasChanged
+        qVariantSetValue<QMatrix>(tester.itemChangeReturnValue, QMatrix().rotate(90));
+        tester.setMatrix(QMatrix().translate(50, 0), true);
+        ++changeCount; // notification sent too
+        QCOMPARE(tester.changes.size(), ++changeCount);
+        QCOMPARE(int(tester.changes.at(tester.changes.size() - 2)), int(QGraphicsItem::ItemMatrixChange));
+        QCOMPARE(int(tester.changes.last()), int(QGraphicsItem::ItemTransformHasChanged));
+        QCOMPARE(qVariantValue<QMatrix>(tester.values.at(tester.values.size() - 2)),
+                 QMatrix().translate(50, 0));
+        QCOMPARE(tester.values.last(), QVariant(QTransform(QMatrix().rotate(90))));
+        QVariant variant;
+        qVariantSetValue<QMatrix>(variant, QMatrix());
+        QCOMPARE(tester.oldValues.last(), variant);
+        QCOMPARE(tester.matrix(), QMatrix().rotate(90));
+    }
+    {
+        tester.resetTransform();
+        ++changeCount;
+        ++changeCount; // notification sent too
+
+        // ItemTransformChange / ItemTransformHasChanged
+        qVariantSetValue<QTransform>(tester.itemChangeReturnValue, QTransform().rotate(90));
+        tester.translate(50, 0);
+        ++changeCount; // notification sent too
+        ++changeCount;
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformHasChanged);
+        QCOMPARE(qVariantValue<QTransform>(tester.values.at(tester.values.size() - 2)),
+                 QTransform().translate(50, 0));
+        QCOMPARE(qVariantValue<QTransform>(tester.values.at(tester.values.size() - 1)),
+                 QTransform().rotate(90));
+        QVariant variant;
+        qVariantSetValue<QTransform>(variant, QTransform());
+        QCOMPARE(tester.oldValues.last(), variant);
+        QCOMPARE(tester.transform(), QTransform().rotate(90));
+    }
+    {
+        // ItemPositionChange / ItemPositionHasChanged
+        tester.itemChangeReturnValue = QPointF(42, 0);
+        tester.setPos(0, 42);
+        ++changeCount; // notification sent too
+        ++changeCount;
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemPositionChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemPositionHasChanged);
+        QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(0, 42)));
+        QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(42, 0)));
+        QCOMPARE(tester.oldValues.last(), QVariant(QPointF()));
+        QCOMPARE(tester.pos(), QPointF(42, 0));
+    }
+    {
+        // ItemZValueChange / ItemZValueHasChanged
+        tester.itemChangeReturnValue = qreal(2.0);
+        tester.setZValue(1.0);
+        ++changeCount; // notification sent too
+        ++changeCount;
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemZValueChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemZValueHasChanged);
+        QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.0)));
+        QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0)));
+        QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0)));
+        QCOMPARE(tester.zValue(), qreal(2.0));
+    }
+    {
+        // ItemFlagsChange
+        tester.itemChangeReturnValue = QGraphicsItem::ItemIsSelectable;
+        tester.setFlag(QGraphicsItem::ItemIsSelectable, false);
+        QCOMPARE(tester.changes.size(), changeCount);  // No change
+        tester.setFlag(QGraphicsItem::ItemIsSelectable, true);
+        ++changeCount;
+        ++changeCount; // ItemFlagsHasChanged
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemFlagsChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemFlagsHaveChanged);
+        QVariant expectedFlags = qVariantFromValue<quint32>(QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges));
+        QCOMPARE(tester.values.at(tester.values.size() - 2), expectedFlags);
+        QCOMPARE(tester.values.at(tester.values.size() - 1), qVariantFromValue<quint32>(QGraphicsItem::ItemIsSelectable));
+    }
+    {
+        // ItemSelectedChange
+        tester.setSelected(false);
+        QCOMPARE(tester.changes.size(), changeCount); // No change :-)
+        tester.itemChangeReturnValue = true;
+        tester.setSelected(true);
+        ++changeCount;
+        ++changeCount; // ItemSelectedHasChanged
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSelectedHasChanged);
+        QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(true));
+        QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
+        QCOMPARE(tester.oldValues.last(), QVariant(false));
+        QCOMPARE(tester.isSelected(), true);
+
+        tester.itemChangeReturnValue = false;
+        tester.setSelected(true);
+
+        // the value hasn't changed to the itemChange return value
+        // bacause itemChange is never called (true -> true is a noop).
+        QCOMPARE(tester.isSelected(), true);
+    }
+    {
+        // ItemVisibleChange
+        tester.itemChangeReturnValue = false;
+        QVERIFY(tester.isVisible());
+        tester.setVisible(false);
+        ++changeCount; // ItemVisibleChange
+        ++changeCount; // ItemSelectedChange
+        ++changeCount; // ItemSelectedHasChanged
+        ++changeCount; // ItemVisibleHasChanged
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemVisibleChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSelectedChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedHasChanged);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemVisibleHasChanged);
+        QCOMPARE(tester.values.at(tester.values.size() - 4), QVariant(false));
+        QCOMPARE(tester.values.at(tester.values.size() - 3), QVariant(false));
+        QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
+        QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(false));
+        QCOMPARE(tester.isVisible(), false);
+    }
+    {
+        // ItemParentChange
+        qVariantSetValue<QGraphicsItem *>(tester.itemChangeReturnValue, 0);
+        tester.setParentItem(&testerHelper);
+        QCOMPARE(tester.changes.size(), ++changeCount);
+        QCOMPARE(tester.changes.last(), QGraphicsItem::ItemParentChange);
+        QCOMPARE(qVariantValue<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
+        QCOMPARE(qVariantValue<QGraphicsItem *>(tester.oldValues.last()), (QGraphicsItem *)0);
+        QCOMPARE(tester.parentItem(), (QGraphicsItem *)0);
+    }
+    {
+        // ItemOpacityChange
+        tester.itemChangeReturnValue = 1.0;
+        tester.setOpacity(0.7);
+        QCOMPARE(tester.changes.size(), ++changeCount);
+        QCOMPARE(tester.changes.last(), QGraphicsItem::ItemOpacityChange);
+        QVERIFY(qFuzzyCompare(qreal(tester.values.last().toDouble()), qreal(0.7)));
+        QCOMPARE(tester.oldValues.last().toDouble(), double(1.0));
+        QCOMPARE(tester.opacity(), qreal(1.0));
+        tester.itemChangeReturnValue = 0.7;
+        tester.setOpacity(0.7);
+        ++changeCount; // ItemOpacityChange
+        ++changeCount; // ItemOpacityHasChanged
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemOpacityChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemOpacityHasChanged);
+        QCOMPARE(tester.opacity(), qreal(0.7));
+    }
+    {
+        // ItemChildAddedChange
+        tester.itemChangeReturnValue.clear();
+        testerHelper.setParentItem(&tester);
+        QCOMPARE(tester.changes.size(), ++changeCount);
+        QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildAddedChange);
+        QCOMPARE(qVariantValue<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
+    }
+    {
+        // ItemChildRemovedChange 1
+        testerHelper.setParentItem(0);
+        QCOMPARE(tester.changes.size(), ++changeCount);
+        QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildRemovedChange);
+        QCOMPARE(qVariantValue<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
+
+        // ItemChildRemovedChange 1
+        ItemChangeTester *test = new ItemChangeTester;
+        test->itemSceneChangeTargetScene = 0;
+        int count = 0;
+        QGraphicsScene *scene = new QGraphicsScene;
+        scene->addItem(test);
+        count = test->changes.size();
+        //We test here the fact that when a child is deleted the parent receive only one ItemChildRemovedChange
+        QGraphicsRectItem *child = new QGraphicsRectItem(test);
+        //We received ItemChildAddedChange
+        QCOMPARE(test->changes.size(), ++count);
+        QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildAddedChange);
+        delete child;
+        child = 0;
+        QCOMPARE(test->changes.size(), ++count);
+        QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
+
+        ItemChangeTester *childTester = new ItemChangeTester(test);
+        //Changes contains all sceneHasChanged and so on, we don't want to test that
+        int childCount = childTester->changes.size();
+        //We received ItemChildAddedChange
+        QCOMPARE(test->changes.size(), ++count);
+        child = new QGraphicsRectItem(childTester);
+        //We received ItemChildAddedChange
+        QCOMPARE(childTester->changes.size(), ++childCount);
+        QCOMPARE(childTester->changes.last(), QGraphicsItem::ItemChildAddedChange);
+        //Delete the child of the top level with all its children
+        delete childTester;
+        //Only one removal
+        QCOMPARE(test->changes.size(), ++count);
+        QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
+        delete scene;
+    }
+    {
+        // ItemChildRemovedChange 2
+        ItemChangeTester parent;
+        ItemChangeTester *child = new ItemChangeTester;
+        child->setParentItem(&parent);
+        QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildAddedChange);
+        QCOMPARE(qVariantValue<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
+        delete child;
+        QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildRemovedChange);
+        QCOMPARE(qVariantValue<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
+    }
+    {
+        // !!! Note: If this test crashes because of double-deletion, there's
+        // a bug somewhere in QGraphicsScene or QGraphicsItem.
+
+        // ItemSceneChange
+        QGraphicsScene scene;
+        QGraphicsScene scene2;
+        scene.addItem(&tester);
+        ++changeCount; // ItemSceneChange (scene)
+        ++changeCount; // ItemSceneHasChanged (scene)
+        QCOMPARE(tester.changes.size(), changeCount);
+
+        QCOMPARE(tester.scene(), &scene);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
+        // Item's old value was 0
+        // Item's current value is scene
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene);
+        scene2.addItem(&tester);
+        ++changeCount; // ItemSceneChange (0) was: (scene)
+        ++changeCount; // ItemSceneHasChanged (0)
+        ++changeCount; // ItemSceneChange (scene2) was: (0)
+        ++changeCount; // ItemSceneHasChanged (scene2)
+        QCOMPARE(tester.changes.size(), changeCount);
+
+        QCOMPARE(tester.scene(), &scene2);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemSceneChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSceneHasChanged);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
+        // Item's last old value was scene
+        // Item's last current value is 0
+
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 2)), (QGraphicsScene *)&scene);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 1)), (QGraphicsScene *)0);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 4)), (QGraphicsScene *)0);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)0);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene2);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene2);
+        // Item's last old value was 0
+        // Item's last current value is scene2
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene2);
+
+        scene2.removeItem(&tester);
+        ++changeCount; // ItemSceneChange (0) was: (scene2)
+        ++changeCount; // ItemSceneHasChanged (0)
+        QCOMPARE(tester.changes.size(), changeCount);
+
+        QCOMPARE(tester.scene(), (QGraphicsScene *)0);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
+        QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
+        // Item's last old value was scene2
+        // Item's last current value is 0
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)&scene2);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)0);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)0);
+
+        tester.itemSceneChangeTargetScene = &scene;
+        scene2.addItem(&tester);
+        ++changeCount; // ItemSceneChange (scene2) was: (0)
+        ++changeCount; // ItemSceneChange (scene) was: (0)
+        ++changeCount; // ItemSceneHasChanged (scene)
+        QCOMPARE(tester.values.size(), changeCount);
+
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)&scene2);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene);
+        QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene);
+
+        QCOMPARE(tester.scene(), &scene);
+        tester.itemSceneChangeTargetScene = 0;
+        tester.itemChangeReturnValue = QVariant();
+        scene.removeItem(&tester);
+        ++changeCount; // ItemSceneChange
+        ++changeCount; // ItemSceneHasChanged
+        QCOMPARE(tester.scene(), (QGraphicsScene *)0);
+    }
+    {
+        // ItemToolTipChange/ItemToolTipHasChanged
+        const QString toolTip(QLatin1String("I'm soo cool"));
+        const QString overridenToolTip(QLatin1String("No, you are not soo cool"));
+        tester.itemChangeReturnValue = overridenToolTip;
+        tester.setToolTip(toolTip);
+        ++changeCount; // ItemToolTipChange
+        ++changeCount; // ItemToolTipHasChanged
+        QCOMPARE(tester.changes.size(), changeCount);
+        QCOMPARE(tester.changes.at(changeCount - 2), QGraphicsItem::ItemToolTipChange);
+        QCOMPARE(tester.values.at(changeCount - 2).toString(), toolTip);
+        QCOMPARE(tester.changes.at(changeCount - 1), QGraphicsItem::ItemToolTipHasChanged);
+        QCOMPARE(tester.values.at(changeCount - 1).toString(), overridenToolTip);
+        QCOMPARE(tester.toolTip(), overridenToolTip);
+        tester.itemChangeReturnValue = QVariant();
+    }
+}
+
+class EventFilterTesterItem : public QGraphicsLineItem
+{
+public:
+    QList<QEvent::Type> filteredEvents;
+    QList<QGraphicsItem *> filteredEventReceivers;
+    bool handlesSceneEvents;
+
+    QList<QEvent::Type> receivedEvents;
+
+    EventFilterTesterItem() : handlesSceneEvents(false) {}
+
+protected:
+    bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+    {
+        filteredEvents << event->type();
+        filteredEventReceivers << watched;
+        return handlesSceneEvents;
+    }
+
+    bool sceneEvent(QEvent *event)
+    {
+        return QGraphicsLineItem::sceneEvent(event);
+    }
+};
+
+void tst_QGraphicsItem::sceneEventFilter()
+{
+    QGraphicsScene scene;
+
+    QGraphicsView view(&scene);
+    view.show();
+    QApplication::setActiveWindow(&view);
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(25);
+
+    QGraphicsTextItem *text1 = scene.addText(QLatin1String("Text1"));
+    QGraphicsTextItem *text2 = scene.addText(QLatin1String("Text2"));
+    QGraphicsTextItem *text3 = scene.addText(QLatin1String("Text3"));
+    text1->setFlag(QGraphicsItem::ItemIsFocusable);
+    text2->setFlag(QGraphicsItem::ItemIsFocusable);
+    text3->setFlag(QGraphicsItem::ItemIsFocusable);
+
+    EventFilterTesterItem *tester = new EventFilterTesterItem;
+    scene.addItem(tester);
+
+    QTRY_VERIFY(!text1->hasFocus());
+    text1->installSceneEventFilter(tester);
+    text1->setFocus();
+    QTRY_VERIFY(text1->hasFocus());
+
+    QCOMPARE(tester->filteredEvents.size(), 1);
+    QCOMPARE(tester->filteredEvents.at(0), QEvent::FocusIn);
+    QCOMPARE(tester->filteredEventReceivers.at(0), static_cast<QGraphicsItem *>(text1));
+
+    text2->installSceneEventFilter(tester);
+    text3->installSceneEventFilter(tester);
+
+    text2->setFocus();
+    text3->setFocus();
+
+    QCOMPARE(tester->filteredEvents.size(), 5);
+    QCOMPARE(tester->filteredEvents.at(1), QEvent::FocusOut);
+    QCOMPARE(tester->filteredEventReceivers.at(1), static_cast<QGraphicsItem *>(text1));
+    QCOMPARE(tester->filteredEvents.at(2), QEvent::FocusIn);
+    QCOMPARE(tester->filteredEventReceivers.at(2), static_cast<QGraphicsItem *>(text2));
+    QCOMPARE(tester->filteredEvents.at(3), QEvent::FocusOut);
+    QCOMPARE(tester->filteredEventReceivers.at(3), static_cast<QGraphicsItem *>(text2));
+    QCOMPARE(tester->filteredEvents.at(4), QEvent::FocusIn);
+    QCOMPARE(tester->filteredEventReceivers.at(4), static_cast<QGraphicsItem *>(text3));
+
+    text1->removeSceneEventFilter(tester);
+    text1->setFocus();
+
+    QCOMPARE(tester->filteredEvents.size(), 6);
+    QCOMPARE(tester->filteredEvents.at(5), QEvent::FocusOut);
+    QCOMPARE(tester->filteredEventReceivers.at(5), static_cast<QGraphicsItem *>(text3));
+
+    tester->handlesSceneEvents = true;
+    text2->setFocus();
+
+    QCOMPARE(tester->filteredEvents.size(), 7);
+    QCOMPARE(tester->filteredEvents.at(6), QEvent::FocusIn);
+    QCOMPARE(tester->filteredEventReceivers.at(6), static_cast<QGraphicsItem *>(text2));
+
+    QVERIFY(text2->hasFocus());
+
+    //Let check if the items are correctly removed from the sceneEventFilters array
+    //to avoid stale pointers.
+    QGraphicsView gv;
+    QGraphicsScene *anotherScene = new QGraphicsScene;
+    QGraphicsTextItem *ti = anotherScene->addText("This is a test #1");
+    ti->moveBy(50, 50);
+    QGraphicsTextItem *ti2 = anotherScene->addText("This is a test #2");
+    QGraphicsTextItem *ti3 = anotherScene->addText("This is a test #3");
+    gv.setScene(anotherScene);
+    gv.show();
+    QTest::qWaitForWindowShown(&gv);
+    QTest::qWait(25);
+    ti->installSceneEventFilter(ti2);
+    ti3->installSceneEventFilter(ti);
+    delete ti2;
+    //we souldn't crash
+    QTest::mouseMove(gv.viewport(), gv.mapFromScene(ti->scenePos()));
+    QTest::qWait(30);
+    delete ti;
+}
+
+class GeometryChanger : public QGraphicsItem
+{
+public:
+    void changeGeometry()
+    { prepareGeometryChange(); }
+};
+
+void tst_QGraphicsItem::prepareGeometryChange()
+{
+    {
+        QGraphicsScene scene;
+        QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+        QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
+        ((GeometryChanger *)item)->changeGeometry();
+        QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
+    }
+}
+
+
+class PaintTester : public QGraphicsRectItem
+{
+public:
+    PaintTester() : widget(NULL), painted(0) { setRect(QRectF(10, 10, 20, 20));}
+
+    void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *w)
+    {
+        widget = w;
+        painted++;
+    }
+
+    QWidget*  widget;
+    int painted;
+};
+
+void tst_QGraphicsItem::paint()
+{
+    QGraphicsScene scene;
+
+    PaintTester paintTester;
+    scene.addItem(&paintTester);
+
+    QGraphicsView view(&scene);
+
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+#ifdef Q_OS_WIN32
+    //we try to switch the desktop: if it fails, we skip the test
+    if (::SwitchDesktop( ::GetThreadDesktop( ::GetCurrentThreadId() ) ) == 0) {
+        QSKIP("The Graphics View doesn't get the paint events", SkipSingle);
+    }
+#endif
+
+    QTRY_COMPARE(paintTester.widget, view.viewport());
+
+    view.hide();
+
+    QGraphicsScene scene2;
+    QGraphicsView view2(&scene2);
+    view2.show();
+    QTest::qWaitForWindowShown(&view2);
+    QTest::qWait(25);
+
+    PaintTester tester2;
+    scene2.addItem(&tester2);
+    qApp->processEvents();
+
+    //First show one paint
+    QTRY_COMPARE(tester2.painted, 1);
+
+    //nominal case, update call paint
+    tester2.update();
+    qApp->processEvents();
+    QTRY_VERIFY(tester2.painted == 2);
+
+    //we remove the item from the scene, number of updates is still the same
+    tester2.update();
+    scene2.removeItem(&tester2);
+    qApp->processEvents();
+    QTRY_VERIFY(tester2.painted == 2);
+
+    //We re-add the item, the number of paint should increase
+    scene2.addItem(&tester2);
+    tester2.update();
+    qApp->processEvents();
+    QTRY_VERIFY(tester2.painted == 3);
+}
+
+class HarakiriItem : public QGraphicsRectItem
+{
+public:
+    HarakiriItem(int harakiriPoint)
+        : QGraphicsRectItem(QRectF(0, 0, 100, 100)), harakiri(harakiriPoint)
+    { dead = 0; }
+
+    static int dead;
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+    {
+        QGraphicsRectItem::paint(painter, option, widget);
+        if (harakiri == 0) {
+            // delete unsupported since 4.5
+            /*
+            dead = 1;
+            delete this;
+            */
+        }
+    }
+
+    void advance(int n)
+    {
+        if (harakiri == 1 && n == 0) {
+            // delete unsupported
+            /*
+            dead = 1;
+            delete this;
+            */
+        }
+        if (harakiri == 2 && n == 1) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+protected:
+    void contextMenuEvent(QGraphicsSceneContextMenuEvent *)
+    {
+        if (harakiri == 3) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
+    {
+        // ??
+        QGraphicsRectItem::dragEnterEvent(event);
+    }
+
+    void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
+    {
+        // ??
+        QGraphicsRectItem::dragLeaveEvent(event);
+    }
+
+    void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
+    {
+        // ??
+        QGraphicsRectItem::dragMoveEvent(event);
+    }
+
+    void dropEvent(QGraphicsSceneDragDropEvent *event)
+    {
+        // ??
+        QGraphicsRectItem::dropEvent(event);
+    }
+
+    void focusInEvent(QFocusEvent *)
+    {
+        if (harakiri == 4) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void focusOutEvent(QFocusEvent *)
+    {
+        if (harakiri == 5) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void hoverEnterEvent(QGraphicsSceneHoverEvent *)
+    {
+        if (harakiri == 6) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
+    {
+        if (harakiri == 7) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void hoverMoveEvent(QGraphicsSceneHoverEvent *)
+    {
+        if (harakiri == 8) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void inputMethodEvent(QInputMethodEvent *event)
+    {
+        // ??
+        QGraphicsRectItem::inputMethodEvent(event);
+    }
+
+    QVariant inputMethodQuery(Qt::InputMethodQuery query) const
+    {
+        // ??
+        return QGraphicsRectItem::inputMethodQuery(query);
+    }
+
+    QVariant itemChange(GraphicsItemChange change, const QVariant &value)
+    {
+        // deletion not supported
+        return QGraphicsRectItem::itemChange(change, value);
+    }
+
+    void keyPressEvent(QKeyEvent *)
+    {
+        if (harakiri == 9) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void keyReleaseEvent(QKeyEvent *)
+    {
+        if (harakiri == 10) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *)
+    {
+        if (harakiri == 11) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void mouseMoveEvent(QGraphicsSceneMouseEvent *)
+    {
+        if (harakiri == 12) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void mousePressEvent(QGraphicsSceneMouseEvent *)
+    {
+        if (harakiri == 13) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
+    {
+        if (harakiri == 14) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+    bool sceneEvent(QEvent *event)
+    {
+        // deletion not supported
+        return QGraphicsRectItem::sceneEvent(event);
+    }
+
+    bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+    {
+        // deletion not supported
+        return QGraphicsRectItem::sceneEventFilter(watched, event);
+    }
+
+    void wheelEvent(QGraphicsSceneWheelEvent *)
+    {
+        if (harakiri == 16) {
+            dead = 1;
+            delete this;
+        }
+    }
+
+private:
+    int harakiri;
+};
+
+int HarakiriItem::dead;
+
+void tst_QGraphicsItem::deleteItemInEventHandlers()
+{
+    for (int i = 0; i < 17; ++i) {
+        QGraphicsScene scene;
+        HarakiriItem *item = new HarakiriItem(i);
+        item->setAcceptsHoverEvents(true);
+        item->setFlag(QGraphicsItem::ItemIsFocusable);
+
+        scene.addItem(item);
+
+        item->installSceneEventFilter(item); // <- ehey!
+
+        QGraphicsView view(&scene);
+        view.show();
+
+        qApp->processEvents();
+        qApp->processEvents();
+
+        if (!item->dead)
+            scene.advance();
+
+        if (!item->dead) {
+            QContextMenuEvent event(QContextMenuEvent::Other,
+                                    view.mapFromScene(item->scenePos()));
+            QCoreApplication::sendEvent(view.viewport(), &event);
+        }
+        if (!item->dead)
+            QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos()));
+        if (!item->dead)
+            QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
+        if (!item->dead)
+            QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
+        if (!item->dead)
+            QTest::mouseClick(view.viewport(), Qt::RightButton, 0, view.mapFromScene(item->scenePos()));
+        if (!item->dead)
+            QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos() + QPointF(20, -20)));
+        if (!item->dead)
+            item->setFocus();
+        if (!item->dead)
+            item->clearFocus();
+        if (!item->dead)
+            item->setFocus();
+        if (!item->dead)
+            QTest::keyPress(view.viewport(), Qt::Key_A);
+        if (!item->dead)
+            QTest::keyRelease(view.viewport(), Qt::Key_A);
+        if (!item->dead)
+            QTest::keyPress(view.viewport(), Qt::Key_A);
+        if (!item->dead)
+            QTest::keyRelease(view.viewport(), Qt::Key_A);
+    }
+}
+
+class ItemPaintsOutsideShape : public QGraphicsItem
+{
+public:
+    QRectF boundingRect() const
+    {
+        return QRectF(0, 0, 100, 100);
+    }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+    {
+        painter->fillRect(-50, -50, 200, 200, Qt::red);
+        painter->fillRect(0, 0, 100, 100, Qt::blue);
+    }
+};
+
+void tst_QGraphicsItem::itemClipsToShape()
+{
+    QGraphicsItem *clippedItem = new ItemPaintsOutsideShape;
+    clippedItem->setFlag(QGraphicsItem::ItemClipsToShape);
+
+    QGraphicsItem *unclippedItem = new ItemPaintsOutsideShape;
+    unclippedItem->setPos(200, 0);
+
+    QGraphicsScene scene(-50, -50, 400, 200);
+    scene.addItem(clippedItem);
+    scene.addItem(unclippedItem);
+
+    QImage image(400, 200, QImage::Format_ARGB32_Premultiplied);
+    image.fill(0);
+    QPainter painter(&image);
+    painter.setRenderHint(QPainter::Antialiasing);
+    scene.render(&painter);
+    painter.end();
+
+    QCOMPARE(image.pixel(45, 100), QRgb(0));
+    QCOMPARE(image.pixel(100, 45), QRgb(0));
+    QCOMPARE(image.pixel(155, 100), QRgb(0));
+    QCOMPARE(image.pixel(45, 155), QRgb(0));
+    QCOMPARE(image.pixel(55, 100), QColor(Qt::blue).rgba());
+    QCOMPARE(image.pixel(100, 55), QColor(Qt::blue).rgba());
+    QCOMPARE(image.pixel(145, 100), QColor(Qt::blue).rgba());
+    QCOMPARE(image.pixel(55, 145), QColor(Qt::blue).rgba());
+    QCOMPARE(image.pixel(245, 100), QColor(Qt::red).rgba());
+    QCOMPARE(image.pixel(300, 45), QColor(Qt::red).rgba());
+    QCOMPARE(image.pixel(355, 100), QColor(Qt::red).rgba());
+    QCOMPARE(image.pixel(245, 155), QColor(Qt::red).rgba());
+    QCOMPARE(image.pixel(255, 100), QColor(Qt::blue).rgba());
+    QCOMPARE(image.pixel(300, 55), QColor(Qt::blue).rgba());
+    QCOMPARE(image.pixel(345, 100), QColor(Qt::blue).rgba());
+    QCOMPARE(image.pixel(255, 145), QColor(Qt::blue).rgba());
+}
+
+void tst_QGraphicsItem::itemClipsChildrenToShape()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::yellow));
+
+    QGraphicsItem *ellipse = scene.addEllipse(0, 0, 100, 100, QPen(Qt::NoPen), QBrush(Qt::green));
+    ellipse->setParentItem(rect);
+
+    QGraphicsItem *clippedEllipse = scene.addEllipse(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::blue));
+    clippedEllipse->setParentItem(ellipse);
+
+    QGraphicsItem *clippedEllipse2 = scene.addEllipse(0, 0, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
+    clippedEllipse2->setParentItem(clippedEllipse);
+
+    QGraphicsItem *clippedEllipse3 = scene.addEllipse(50, 50, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
+    clippedEllipse3->setParentItem(clippedEllipse);
+
+    QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
+    ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    QVERIFY((ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
+
+    QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
+    image.fill(0);
+    QPainter painter(&image);
+    painter.setRenderHint(QPainter::Antialiasing);
+    scene.render(&painter);
+    painter.end();
+
+    QCOMPARE(image.pixel(16, 16), QColor(255, 0, 0).rgba());
+    QCOMPARE(image.pixel(32, 32), QColor(0, 0, 255).rgba());
+    QCOMPARE(image.pixel(50, 50), QColor(0, 255, 0).rgba());
+    QCOMPARE(image.pixel(12, 12), QColor(255, 255, 0).rgba());
+    QCOMPARE(image.pixel(60, 60), QColor(255, 0, 0).rgba());
+}
+
+void tst_QGraphicsItem::itemClipsChildrenToShape2()
+{
+    QGraphicsRectItem *parent = new QGraphicsRectItem(QRectF(0, 0, 10, 10));
+    QGraphicsEllipseItem *child1 = new QGraphicsEllipseItem(QRectF(50, 50, 100, 100));
+    QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(15, 15, 80, 80));
+
+    child1->setParentItem(parent);
+    child1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    child2->setParentItem(child1);
+
+    parent->setBrush(Qt::blue);
+    child1->setBrush(Qt::green);
+    child2->setBrush(Qt::red);
+
+    QGraphicsScene scene;
+    scene.addItem(parent);
+
+    QCOMPARE(scene.itemAt(5, 5), (QGraphicsItem *)parent);
+    QCOMPARE(scene.itemAt(15, 5), (QGraphicsItem *)0);
+    QCOMPARE(scene.itemAt(5, 15), (QGraphicsItem *)0);
+    QCOMPARE(scene.itemAt(60, 60), (QGraphicsItem *)0);
+    QCOMPARE(scene.itemAt(140, 60), (QGraphicsItem *)0);
+    QCOMPARE(scene.itemAt(60, 140), (QGraphicsItem *)0);
+    QCOMPARE(scene.itemAt(140, 140), (QGraphicsItem *)0);
+    QCOMPARE(scene.itemAt(75, 75), (QGraphicsItem *)child2);
+    QCOMPARE(scene.itemAt(75, 100), (QGraphicsItem *)child1);
+    QCOMPARE(scene.itemAt(100, 75), (QGraphicsItem *)child1);
+
+#if 1
+    QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
+    image.fill(0);
+    QPainter painter(&image);
+    scene.render(&painter);
+    painter.end();
+
+    QCOMPARE(image.pixel(5, 5), QColor(0, 0, 255).rgba());
+    QCOMPARE(image.pixel(5, 10), QRgb(0));
+    QCOMPARE(image.pixel(10, 5), QRgb(0));
+    QCOMPARE(image.pixel(40, 40), QRgb(0));
+    QCOMPARE(image.pixel(90, 40), QRgb(0));
+    QCOMPARE(image.pixel(40, 90), QRgb(0));
+    QCOMPARE(image.pixel(95, 95), QRgb(0));
+    QCOMPARE(image.pixel(50, 70), QColor(0, 255, 0).rgba());
+    QCOMPARE(image.pixel(70, 50), QColor(0, 255, 0).rgba());
+    QCOMPARE(image.pixel(50, 60), QColor(255, 0, 0).rgba());
+    QCOMPARE(image.pixel(60, 50), QColor(255, 0, 0).rgba());
+#else
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWait(5000);
+#endif
+}
+
+void tst_QGraphicsItem::itemClipsChildrenToShape3()
+{
+    // Construct a scene with nested children, each 50 pixels offset from the elder.
+    // Set a top-level clipping flag
+    QGraphicsScene scene;
+    QGraphicsRectItem *parent = scene.addRect( 0, 0, 150, 150 );
+    QGraphicsRectItem *child = scene.addRect( 0, 0, 150, 150 );
+    QGraphicsRectItem *grandchild = scene.addRect( 0, 0, 150, 150 );
+    child->setParentItem(parent);
+    grandchild->setParentItem(child);
+    child->setPos( 50, 50 );
+    grandchild->setPos( 50, 50 );
+    parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+
+    QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)parent);
+    QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)child);
+    QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
+    QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
+
+    // Move child to fully overlap the parent.  The grandchild should
+    // now occupy two-thirds of the scene
+    child->prepareGeometryChange();
+    child->setPos( 0, 0 );
+
+    QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)child);
+    QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)grandchild);
+    QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
+    QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
+}
+
+class MyProxyWidget : public QGraphicsProxyWidget
+{
+public:
+    MyProxyWidget(QGraphicsItem *parent) : QGraphicsProxyWidget(parent)
+    {
+        painted = false;
+    }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+    {
+        QGraphicsProxyWidget::paint(painter, option, widget);
+        painted = true;
+    }
+    bool painted;
+};
+
+void tst_QGraphicsItem::itemClipsChildrenToShape4()
+{
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+
+    QGraphicsWidget * outerWidget = new QGraphicsWidget();
+    outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
+    MyProxyWidget * innerWidget = new MyProxyWidget(outerWidget);
+    QLabel * label = new QLabel();
+    label->setText("Welcome back my friends to the show that never ends...");
+    innerWidget->setWidget(label);
+    view.resize(300, 300);
+    scene.addItem(outerWidget);
+    outerWidget->resize( 200, 100 );
+    scene.addEllipse( 100, 100, 100, 50 );   // <-- this is important to trigger the right codepath*
+    //now the label is shown
+    outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false );
+    QApplication::setActiveWindow(&view);
+    view.show();
+    QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
+    QTRY_COMPARE(innerWidget->painted, true);
+}
+
+void tst_QGraphicsItem::itemClipsTextChildToShape()
+{
+    // Construct a scene with a rect that clips its children, with one text
+    // child that has text that exceeds the size of the rect.
+    QGraphicsScene scene;
+    QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::black), Qt::black);
+    rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    QGraphicsTextItem *text = new QGraphicsTextItem("This is a long sentence that's wider than 50 pixels.");
+    text->setParentItem(rect);
+
+    // Render this scene to a transparent image.
+    QRectF sr = scene.itemsBoundingRect();
+    QImage image(sr.size().toSize(), QImage::Format_ARGB32_Premultiplied);
+    image.fill(0);
+    QPainter painter(&image);
+    scene.render(&painter);
+
+    // Erase the area immediately underneath the rect.
+    painter.setCompositionMode(QPainter::CompositionMode_Source);
+    painter.fillRect(rect->sceneBoundingRect().translated(-sr.topLeft()).adjusted(-0.5, -0.5, 0.5, 0.5),
+                     Qt::transparent);
+    painter.end();
+
+    // Check that you get a truly transparent image back (i.e., the text was
+    // clipped away, so there should be no trails left after erasing only the
+    // rect's area).
+    QImage emptyImage(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
+    emptyImage.fill(0);
+    QCOMPARE(image, emptyImage);
+}
+
+void tst_QGraphicsItem::itemClippingDiscovery()
+{
+    // A simple scene with an ellipse parent and two rect children, one a
+    // child of the other.
+    QGraphicsScene scene;
+    QGraphicsEllipseItem *clipItem = scene.addEllipse(0, 0, 100, 100);
+    QGraphicsRectItem *leftRectItem = scene.addRect(0, 0, 50, 100);
+    QGraphicsRectItem *rightRectItem = scene.addRect(50, 0, 50, 100);
+    leftRectItem->setParentItem(clipItem);
+    rightRectItem->setParentItem(clipItem);
+
+    // The rects item are both visible at these points.
+    QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)leftRectItem);
+    QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)rightRectItem);
+
+    // The ellipse clips the rects now.
+    clipItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+
+    // The rect items are no longer visible at these points.
+    QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
+    if (sizeof(qreal) != sizeof(double))
+        QSKIP("This fails due to internal rounding errors", SkipSingle);
+    QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsItem::ancestorFlags()
+{
+    QGraphicsItem *level1 = new QGraphicsRectItem;
+    QGraphicsItem *level21 = new QGraphicsRectItem;
+    level21->setParentItem(level1);
+    QGraphicsItem *level22 = new QGraphicsRectItem;
+    level22->setParentItem(level1);
+    QGraphicsItem *level31 = new QGraphicsRectItem;
+    level31->setParentItem(level21);
+    QGraphicsItem *level32 = new QGraphicsRectItem;
+    level32->setParentItem(level21);
+
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
+
+    // HandlesChildEvents: 1) Root level sets a flag
+    level1->setHandlesChildEvents(true);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // HandlesChildEvents: 2) Root level set it again
+    level1->setHandlesChildEvents(true);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // HandlesChildEvents: 3) Root level unsets a flag
+    level1->setHandlesChildEvents(false);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
+
+    // HandlesChildEvents: 4) Child item sets a flag
+    level21->setHandlesChildEvents(true);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // HandlesChildEvents: 5) Parent item sets a flag
+    level1->setHandlesChildEvents(true);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // HandlesChildEvents: 6) Child item unsets a flag
+    level21->setHandlesChildEvents(false);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // HandlesChildEvents: 7) Parent item unsets a flag
+    level21->setHandlesChildEvents(true);
+    level1->setHandlesChildEvents(false);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // Reparent the child to root
+    level21->setParentItem(0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // Reparent the child to level1 again.
+    level1->setHandlesChildEvents(true);
+    level21->setParentItem(level1);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // Reparenting level31 back to level1.
+    level31->setParentItem(level1);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // Reparenting level31 back to level21.
+    level31->setParentItem(0);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
+    level31->setParentItem(level21);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // Level1 doesn't handle child events
+    level1->setHandlesChildEvents(false);
+    QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+    QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
+    QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
+
+    // Nobody handles child events
+    level21->setHandlesChildEvents(false);
+
+    for (int i = 0; i < 2; ++i) {
+        QGraphicsItem::GraphicsItemFlag flag = !i ? QGraphicsItem::ItemClipsChildrenToShape
+                                               : QGraphicsItem::ItemIgnoresTransformations;
+        int ancestorFlag = !i ? QGraphicsItemPrivate::AncestorClipsChildren
+                           : QGraphicsItemPrivate::AncestorIgnoresTransformations;
+
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
+
+        // HandlesChildEvents: 1) Root level sets a flag
+        level1->setFlag(flag, true);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // HandlesChildEvents: 2) Root level set it again
+        level1->setFlag(flag, true);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // HandlesChildEvents: 3) Root level unsets a flag
+        level1->setFlag(flag, false);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
+
+        // HandlesChildEvents: 4) Child item sets a flag
+        level21->setFlag(flag, true);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // HandlesChildEvents: 5) Parent item sets a flag
+        level1->setFlag(flag, true);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // HandlesChildEvents: 6) Child item unsets a flag
+        level21->setFlag(flag, false);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // HandlesChildEvents: 7) Parent item unsets a flag
+        level21->setFlag(flag, true);
+        level1->setFlag(flag, false);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // Reparent the child to root
+        level21->setParentItem(0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // Reparent the child to level1 again.
+        level1->setFlag(flag, true);
+        level21->setParentItem(level1);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // Reparenting level31 back to level1.
+        level31->setParentItem(level1);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // Reparenting level31 back to level21.
+        level31->setParentItem(0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
+        level31->setParentItem(level21);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // Level1 doesn't handle child events
+        level1->setFlag(flag, false);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
+
+        // Nobody handles child events
+        level21->setFlag(flag, false);
+        QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
+        QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
+    }
+
+    delete level1;
+}
+
+void tst_QGraphicsItem::untransformable()
+{
+    QGraphicsItem *item1 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
+    item1->setZValue(1);
+    item1->setFlag(QGraphicsItem::ItemIgnoresTransformations);
+    item1->rotate(45);
+    ((QGraphicsEllipseItem *)item1)->setBrush(Qt::red);
+
+    QGraphicsItem *item2 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
+    item2->setParentItem(item1);
+    item2->rotate(45);
+    item2->setPos(100, 0);
+    ((QGraphicsEllipseItem *)item2)->setBrush(Qt::green);
+
+    QGraphicsItem *item3 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
+    item3->setParentItem(item2);
+    item3->setPos(100, 0);
+    ((QGraphicsEllipseItem *)item3)->setBrush(Qt::blue);
+
+    QGraphicsScene scene(-500, -500, 1000, 1000);
+    scene.addItem(item1);
+
+    QGraphicsView view(&scene);
+    view.resize(300, 300);
+    view.show();
+    view.scale(8, 8);
+    view.centerOn(0, 0);
+
+// Painting with the DiagCrossPattern is really slow on Mac
+// when zoomed out. (The test times out). Task to fix is 155567.
+#if !defined(Q_WS_MAC) || 1
+    view.setBackgroundBrush(QBrush(Qt::black, Qt::DiagCrossPattern));
+#endif
+
+    QTest::qWaitForWindowShown(&view);
+
+    for (int i = 0; i < 10; ++i) {
+        QPoint center = view.viewport()->rect().center();
+        QCOMPARE(view.itemAt(center), item1);
+        QCOMPARE(view.itemAt(center - QPoint(40, 0)), item1);
+        QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item1);
+        QCOMPARE(view.itemAt(center - QPoint(0, 40)), item1);
+        QCOMPARE(view.itemAt(center - QPoint(0, -40)), item1);
+
+        center += QPoint(70, 70);
+        QCOMPARE(view.itemAt(center - QPoint(40, 0)), item2);
+        QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item2);
+        QCOMPARE(view.itemAt(center - QPoint(0, 40)), item2);
+        QCOMPARE(view.itemAt(center - QPoint(0, -40)), item2);
+
+        center += QPoint(0, 100);
+        QCOMPARE(view.itemAt(center - QPoint(40, 0)), item3);
+        QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item3);
+        QCOMPARE(view.itemAt(center - QPoint(0, 40)), item3);
+        QCOMPARE(view.itemAt(center - QPoint(0, -40)), item3);
+
+        view.scale(0.5, 0.5);
+        view.rotate(13);
+        view.shear(qreal(0.01), qreal(0.01));
+        view.translate(10, 10);
+        QTest::qWait(25);
+    }
+}
+
+class ContextMenuItem : public QGraphicsRectItem
+{
+public:
+    ContextMenuItem()
+        : ignoreEvent(true), gotEvent(false), eventWasAccepted(false)
+    { }
+    bool ignoreEvent;
+    bool gotEvent;
+    bool eventWasAccepted;
+protected:
+    void contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+    {
+        gotEvent = true;
+        eventWasAccepted = event->isAccepted();
+        if (ignoreEvent)
+            event->ignore();
+    }
+};
+
+void tst_QGraphicsItem::contextMenuEventPropagation()
+{
+    ContextMenuItem *bottomItem = new ContextMenuItem;
+    bottomItem->setRect(0, 0, 100, 100);
+    ContextMenuItem *topItem = new ContextMenuItem;
+    topItem->setParentItem(bottomItem);
+    topItem->setRect(0, 0, 100, 100);
+
+    QGraphicsScene scene;
+
+    QGraphicsView view(&scene);
+    view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
+    view.show();
+    view.resize(200, 200);
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(20);
+
+    QContextMenuEvent event(QContextMenuEvent::Mouse, QPoint(10, 10),
+                            view.viewport()->mapToGlobal(QPoint(10, 10)));
+    event.ignore();
+    QApplication::sendEvent(view.viewport(), &event);
+    QVERIFY(!event.isAccepted());
+
+    scene.addItem(bottomItem);
+    topItem->ignoreEvent = true;
+    bottomItem->ignoreEvent = true;
+
+    QApplication::sendEvent(view.viewport(), &event);
+    QVERIFY(!event.isAccepted());
+    QCOMPARE(topItem->gotEvent, true);
+    QCOMPARE(topItem->eventWasAccepted, true);
+    QCOMPARE(bottomItem->gotEvent, true);
+    QCOMPARE(bottomItem->eventWasAccepted, true);
+
+    topItem->ignoreEvent = false;
+    topItem->gotEvent = false;
+    bottomItem->gotEvent = false;
+
+    QApplication::sendEvent(view.viewport(), &event);
+    QVERIFY(event.isAccepted());
+    QCOMPARE(topItem->gotEvent, true);
+    QCOMPARE(bottomItem->gotEvent, false);
+    QCOMPARE(topItem->eventWasAccepted, true);
+}
+
+void tst_QGraphicsItem::itemIsMovable()
+{
+    QGraphicsRectItem *rect = new QGraphicsRectItem(-50, -50, 100, 100);
+    rect->setFlag(QGraphicsItem::ItemIsMovable);
+
+    QGraphicsScene scene;
+    scene.addItem(rect);
+
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+        event.setButton(Qt::LeftButton);
+        event.setButtons(Qt::LeftButton);
+        qApp->sendEvent(&scene, &event);
+    }
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+        event.setButton(Qt::LeftButton);
+        event.setButtons(Qt::LeftButton);
+        qApp->sendEvent(&scene, &event);
+    }
+    QCOMPARE(rect->pos(), QPointF(0, 0));
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+        event.setButtons(Qt::LeftButton);
+        event.setScenePos(QPointF(10, 10));
+        qApp->sendEvent(&scene, &event);
+    }
+    QCOMPARE(rect->pos(), QPointF(10, 10));
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+        event.setButtons(Qt::RightButton);
+        event.setScenePos(QPointF(20, 20));
+        qApp->sendEvent(&scene, &event);
+    }
+    QCOMPARE(rect->pos(), QPointF(10, 10));
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+        event.setButtons(Qt::LeftButton);
+        event.setScenePos(QPointF(30, 30));
+        qApp->sendEvent(&scene, &event);
+    }
+    QCOMPARE(rect->pos(), QPointF(30, 30));
+}
+
+class ItemAddScene : public QGraphicsScene
+{
+    Q_OBJECT
+public:
+    ItemAddScene()
+    {
+        QTimer::singleShot(500, this, SLOT(newTextItem()));
+    }
+
+public slots:
+    void newTextItem()
+    {
+        // Add a text item
+        QGraphicsItem *item = new QGraphicsTextItem("This item will not ensure that it's visible", 0, this);
+        item->setPos(.0, .0);
+        item->show();
+    }
+};
+
+void tst_QGraphicsItem::task141694_textItemEnsureVisible()
+{
+    ItemAddScene scene;
+    scene.setSceneRect(-1000, -1000, 2000, 2000);
+
+    QGraphicsView view(&scene);
+    view.setFixedSize(200, 200);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+
+    view.ensureVisible(-1000, -1000, 5, 5);
+    int hscroll = view.horizontalScrollBar()->value();
+    int vscroll = view.verticalScrollBar()->value();
+
+    QTest::qWait(10);
+
+    // This should not cause the view to scroll
+    QTRY_COMPARE(view.horizontalScrollBar()->value(), hscroll);
+    QCOMPARE(view.verticalScrollBar()->value(), vscroll);
+}
+
+void tst_QGraphicsItem::task128696_textItemEnsureMovable()
+{
+    QGraphicsTextItem *item = new QGraphicsTextItem;
+    item->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
+    item->setTextInteractionFlags(Qt::TextEditorInteraction);
+    item->setPlainText("abc de\nf ghi\n   j k l");
+
+    QGraphicsScene scene;
+    scene.setSceneRect(-100, -100, 200, 200);
+    scene.addItem(item);
+
+    QGraphicsView view(&scene);
+    view.setFixedSize(200, 200);
+    view.show();
+
+    QGraphicsSceneMouseEvent event1(QEvent::GraphicsSceneMousePress);
+    event1.setScenePos(QPointF(0, 0));
+    event1.setButton(Qt::LeftButton);
+    event1.setButtons(Qt::LeftButton);
+    QApplication::sendEvent(&scene, &event1);
+    QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
+
+    QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
+    event2.setScenePos(QPointF(10, 10));
+    event2.setButton(Qt::LeftButton);
+    event2.setButtons(Qt::LeftButton);
+    QApplication::sendEvent(&scene, &event2);
+    QCOMPARE(item->pos(), QPointF(10, 10));
+}
+
+void tst_QGraphicsItem::task177918_lineItemUndetected()
+{
+    QGraphicsScene scene;
+    QGraphicsLineItem *line = scene.addLine(10, 10, 10, 10);
+    QCOMPARE(line->boundingRect(), QRectF(10, 10, 0, 0));
+
+    QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemShape).isEmpty());
+    QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemShape).isEmpty());
+    QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemBoundingRect).isEmpty());
+    QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemBoundingRect).isEmpty());
+}
+
+void tst_QGraphicsItem::task240400_clickOnTextItem_data()
+{
+    QTest::addColumn<int>("flags");
+    QTest::addColumn<int>("textFlags");
+    QTest::newRow("editor, noflags") << 0 << int(Qt::TextEditorInteraction);
+    QTest::newRow("editor, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::TextEditorInteraction);
+    QTest::newRow("editor, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::TextEditorInteraction);
+    QTest::newRow("editor, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
+                                                  << int(Qt::TextEditorInteraction);
+    QTest::newRow("noninteractive, noflags") << 0 << int(Qt::NoTextInteraction);
+    QTest::newRow("noninteractive, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::NoTextInteraction);
+    QTest::newRow("noninteractive, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::NoTextInteraction);
+    QTest::newRow("noninteractive, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
+                                                          << int(Qt::NoTextInteraction);
+}
+
+void tst_QGraphicsItem::task240400_clickOnTextItem()
+{
+    QFETCH(int, flags);
+    QFETCH(int, textFlags);
+
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    QGraphicsTextItem *item = scene.addText("Hello");
+    item->setFlags(QGraphicsItem::GraphicsItemFlags(flags));
+    item->setTextInteractionFlags(Qt::TextInteractionFlags(textFlags));
+    bool focusable = (item->flags() & QGraphicsItem::ItemIsFocusable);
+    QVERIFY(textFlags ? focusable : !focusable);
+
+    int column = item->textCursor().columnNumber();
+    QCOMPARE(column, 0);
+
+    QVERIFY(!item->hasFocus());
+
+    // Click in the top-left corner of the item
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+        event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
+        event.setButton(Qt::LeftButton);
+        event.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event);
+    }
+    if (flags || textFlags)
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
+    else
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
+        event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
+        event.setButton(Qt::LeftButton);
+        event.setButtons(0);
+        QApplication::sendEvent(&scene, &event);
+    }
+    if (textFlags)
+        QVERIFY(item->hasFocus());
+    else
+        QVERIFY(!item->hasFocus());
+    QVERIFY(!scene.mouseGrabberItem());
+    bool selectable = (flags & QGraphicsItem::ItemIsSelectable);
+    QVERIFY(selectable ? item->isSelected() : !item->isSelected());
+
+    // Now click in the middle and check that the cursor moved.
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+        event.setScenePos(item->sceneBoundingRect().center());
+        event.setButton(Qt::LeftButton);
+        event.setButtons(Qt::LeftButton);
+        QApplication::sendEvent(&scene, &event);
+    }
+    if (flags || textFlags)
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
+    else
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
+        event.setScenePos(item->sceneBoundingRect().center());
+        event.setButton(Qt::LeftButton);
+        event.setButtons(0);
+        QApplication::sendEvent(&scene, &event);
+    }
+    if (textFlags)
+        QVERIFY(item->hasFocus());
+    else
+        QVERIFY(!item->hasFocus());
+    QVERIFY(!scene.mouseGrabberItem());
+
+    QVERIFY(selectable ? item->isSelected() : !item->isSelected());
+
+    //
+    if (textFlags & Qt::TextEditorInteraction)
+        QVERIFY(item->textCursor().columnNumber() > column);
+    else
+        QCOMPARE(item->textCursor().columnNumber(), 0);
+}
+
+class TextItem : public QGraphicsSimpleTextItem
+{
+public:
+    TextItem(const QString& text) : QGraphicsSimpleTextItem(text)
+    {
+        updates = 0;
+    }
+
+    void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
+    {
+        updates++;
+        QGraphicsSimpleTextItem::paint(painter, option, widget);
+    }
+
+    int updates;
+};
+
+void tst_QGraphicsItem::ensureUpdateOnTextItem()
+{
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(25);
+    TextItem *text1 = new TextItem(QLatin1String("123"));
+    scene.addItem(text1);
+    qApp->processEvents();
+    QTRY_COMPARE(text1->updates,1);
+
+    //same bouding rect but we have to update
+    text1->setText(QLatin1String("321"));
+    qApp->processEvents();
+    QTRY_COMPARE(text1->updates,2);
+}
+
+void tst_QGraphicsItem::task243707_addChildBeforeParent()
+{
+    // Task reports that adding the child before the parent leads to an
+    // inconsistent internal state that can cause a crash.  This test shows
+    // one such crash.
+    QGraphicsScene scene;
+    QGraphicsWidget *widget = new QGraphicsWidget;
+    QGraphicsWidget *widget2 = new QGraphicsWidget(widget);
+    scene.addItem(widget2);
+    QVERIFY(!widget2->parentItem());
+    scene.addItem(widget);
+    QVERIFY(!widget->commonAncestorItem(widget2));
+    QVERIFY(!widget2->commonAncestorItem(widget));
+}
+
+void tst_QGraphicsItem::task197802_childrenVisibility()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem item(QRectF(0,0,20,20));
+
+    QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(0,0,10,10), &item);
+    scene.addItem(&item);
+
+    //freshly created: both visible
+    QVERIFY(item.isVisible());
+    QVERIFY(item2->isVisible());
+
+    //hide child: parent visible, child not
+    item2->hide();
+    QVERIFY(item.isVisible());
+    QVERIFY(!item2->isVisible());
+
+    //hide parent: parent and child invisible
+    item.hide();
+    QVERIFY(!item.isVisible());
+    QVERIFY(!item2->isVisible());
+
+    //ask to show the child: parent and child invisible anyways
+    item2->show();
+    QVERIFY(!item.isVisible());
+    QVERIFY(!item2->isVisible());
+
+    //show the parent: both parent and child visible
+    item.show();
+    QVERIFY(item.isVisible());
+    QVERIFY(item2->isVisible());
+
+    delete item2;
+}
+
+void tst_QGraphicsItem::boundingRegion_data()
+{
+    QTest::addColumn<QLineF>("line");
+    QTest::addColumn<qreal>("granularity");
+    QTest::addColumn<QTransform>("transform");
+    QTest::addColumn<QRegion>("expectedRegion");
+
+    QTest::newRow("(0, 0, 10, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.0) << QTransform()
+                                                                        << QRegion(QRect(0, 0, 10, 10));
+    {
+        QRegion r;
+        r += QRect(0, 0, 6, 2);
+        r += QRect(0, 2, 8, 2);
+        r += QRect(0, 4, 10, 2);
+        r += QRect(2, 6, 8, 2);
+        r += QRect(4, 8, 6, 2);
+        QTest::newRow("(0, 0, 10, 10) | 0.5 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.5) << QTransform() << r;
+    }
+    {
+        QRegion r;
+        r += QRect(0, 0, 4, 1); r += QRect(0, 1, 5, 1); r += QRect(0, 2, 6, 1);
+        r += QRect(0, 3, 7, 1); r += QRect(1, 4, 7, 1); r += QRect(2, 5, 7, 1);
+        r += QRect(3, 6, 7, 1); r += QRect(4, 7, 6, 1); r += QRect(5, 8, 5, 1);
+        r += QRect(6, 9, 4, 1);
+        QTest::newRow("(0, 0, 10, 10) | 1.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(1.0) << QTransform() << r;
+    }
+    QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform()
+                                                                       << QRegion(QRect(0, 0, 10, 1));
+    QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform()
+                                                                      << QRegion(QRect(0, 0, 10, 1));
+    QTest::newRow("(0, 0, 10, 0) | 1.0 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(1.0) << QTransform()
+                                                                      << QRegion(QRect(0, 0, 10, 1));
+    QTest::newRow("(0, 0, 0, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.0) << QTransform()
+                                                                       << QRegion(QRect(0, 0, 1, 10));
+    QTest::newRow("(0, 0, 0, 10) | 0.5 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.5) << QTransform()
+                                                                      << QRegion(QRect(0, 0, 1, 10));
+    QTest::newRow("(0, 0, 0, 10) | 1.0 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(1.0) << QTransform()
+                                                                      << QRegion(QRect(0, 0, 1, 10));
+}
+
+void tst_QGraphicsItem::boundingRegion()
+{
+    QFETCH(QLineF, line);
+    QFETCH(qreal, granularity);
+    QFETCH(QTransform, transform);
+    QFETCH(QRegion, expectedRegion);
+
+    QGraphicsLineItem item(line);
+    QCOMPARE(item.boundingRegionGranularity(), qreal(0.0));
+    item.setBoundingRegionGranularity(granularity);
+    QCOMPARE(item.boundingRegionGranularity(), granularity);
+    QCOMPARE(item.boundingRegion(transform), expectedRegion);
+}
+
+void tst_QGraphicsItem::itemTransform_parentChild()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
+    QGraphicsItem *child = scene.addRect(0, 0, 100, 100);
+    child->setParentItem(parent);
+    child->setPos(10, 10);
+    child->scale(2, 2);
+    child->rotate(90);
+
+    QCOMPARE(child->itemTransform(parent).map(QPointF(10, 10)), QPointF(-10, 30));
+    QCOMPARE(parent->itemTransform(child).map(QPointF(-10, 30)), QPointF(10, 10));
+}
+
+void tst_QGraphicsItem::itemTransform_siblings()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
+    QGraphicsItem *brother = scene.addRect(0, 0, 100, 100);
+    QGraphicsItem *sister = scene.addRect(0, 0, 100, 100);
+    parent->scale(10, 5);
+    parent->rotate(-180);
+    parent->shear(2, 3);
+
+    brother->setParentItem(parent);
+    sister->setParentItem(parent);
+
+    brother->setPos(10, 10);
+    brother->scale(2, 2);
+    brother->rotate(90);
+    sister->setPos(10, 10);
+    sister->scale(2, 2);
+    sister->rotate(90);
+
+    QCOMPARE(brother->itemTransform(sister).map(QPointF(10, 10)), QPointF(10, 10));
+    QCOMPARE(sister->itemTransform(brother).map(QPointF(10, 10)), QPointF(10, 10));
+}
+
+void tst_QGraphicsItem::itemTransform_unrelated()
+{
+    QGraphicsScene scene;
+    QGraphicsItem *stranger1 = scene.addRect(0, 0, 100, 100);
+    QGraphicsItem *stranger2 = scene.addRect(0, 0, 100, 100);
+    stranger1->setPos(10, 10);
+    stranger1->scale(2, 2);
+    stranger1->rotate(90);
+    stranger2->setPos(10, 10);
+    stranger2->scale(2, 2);
+    stranger2->rotate(90);
+
+    QCOMPARE(stranger1->itemTransform(stranger2).map(QPointF(10, 10)), QPointF(10, 10));
+    QCOMPARE(stranger2->itemTransform(stranger1).map(QPointF(10, 10)), QPointF(10, 10));
+}
+
+void tst_QGraphicsItem::opacity_data()
+{
+    QTest::addColumn<qreal>("p_opacity");
+    QTest::addColumn<int>("p_opacityFlags");
+    QTest::addColumn<qreal>("c1_opacity");
+    QTest::addColumn<int>("c1_opacityFlags");
+    QTest::addColumn<qreal>("c2_opacity");
+    QTest::addColumn<int>("c2_opacityFlags");
+    QTest::addColumn<qreal>("p_effectiveOpacity");
+    QTest::addColumn<qreal>("c1_effectiveOpacity");
+    QTest::addColumn<qreal>("c2_effectiveOpacity");
+    QTest::addColumn<qreal>("c3_effectiveOpacity");
+
+    // Modify the opacity and see how it propagates
+    QTest::newRow("A: 1.0 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0
+                                                        << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
+    QTest::newRow("B: 0.5 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0
+                                                        << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
+    QTest::newRow("C: 0.5 0 0.1 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(0.1) << 0 << qreal(1.0) << 0
+                                                        << qreal(0.5) << qreal(0.05) << qreal(0.05) << qreal(0.05);
+    QTest::newRow("D: 0.0 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0
+                                                        << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
+
+    // Parent doesn't propagate to children - now modify the opacity and see how it propagates
+    int flags = QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
+    QTest::newRow("E: 1.0 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << flags << qreal(1.0) << 0 << qreal(1.0) << 0
+                                                        << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
+    QTest::newRow("F: 0.5 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << flags << qreal(1.0) << 0 << qreal(1.0) << 0
+                                                        << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
+    QTest::newRow("G: 0.5 2 0.1 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << flags << qreal(0.1) << 0 << qreal(1.0) << 0
+                                                        << qreal(0.5) << qreal(0.1) << qreal(0.1) << qreal(0.1);
+    QTest::newRow("H: 0.0 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << flags << qreal(1.0) << 0 << qreal(1.0) << 0
+                                                        << qreal(0.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
+
+    // Child ignores parent - now modify the opacity and see how it propagates
+    flags = QGraphicsItem::ItemIgnoresParentOpacity;
+    QTest::newRow("I: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 << qreal(1.0) << flags << qreal(1.0) << 0
+                                                        << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
+    QTest::newRow("J: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(0.5) << flags << qreal(0.5) << 0
+                                                        << qreal(0.5) << qreal(0.5) << qreal(0.25) << qreal(0.25);
+    QTest::newRow("K: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.2) << 0 << qreal(0.2) << flags << qreal(0.2) << 0
+                                                        << qreal(0.2) << qreal(0.2) << qreal(0.04) << qreal(0.04);
+    QTest::newRow("L: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << 0 << qreal(0.0) << flags << qreal(0.0) << 0
+                                                        << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
+
+    // Child ignores parent and doesn't propagate - now modify the opacity and see how it propagates
+    flags = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
+    QTest::newRow("M: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
+                                                        << qreal(1.0) << flags // c1 (no prop)
+                                                        << qreal(1.0) << 0 // c2
+                                                        << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
+    QTest::newRow("M: 0.5 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
+                                                        << qreal(1.0) << flags // c1 (no prop)
+                                                        << qreal(1.0) << 0 // c2
+                                                        << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
+    QTest::newRow("M: 0.5 0 0.5 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
+                                                        << qreal(0.5) << flags // c1 (no prop)
+                                                        << qreal(1.0) << 0 // c2
+                                                        << qreal(0.5) << qreal(0.5) << qreal(1.0) << qreal(1.0);
+    QTest::newRow("M: 0.5 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
+                                                        << qreal(0.5) << flags // c1 (no prop)
+                                                        << qreal(0.5) << 0 // c2
+                                                        << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
+    QTest::newRow("M: 1.0 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
+                                                        << qreal(0.5) << flags // c1 (no prop)
+                                                        << qreal(0.5) << 0 // c2
+                                                        << qreal(1.0) << qreal(0.5) << qreal(0.5) << qreal(0.5);
+}
+
+void tst_QGraphicsItem::opacity()
+{
+    QFETCH(qreal, p_opacity);
+    QFETCH(int, p_opacityFlags);
+    QFETCH(qreal, p_effectiveOpacity);
+    QFETCH(qreal, c1_opacity);
+    QFETCH(int, c1_opacityFlags);
+    QFETCH(qreal, c1_effectiveOpacity);
+    QFETCH(qreal, c2_opacity);
+    QFETCH(int, c2_opacityFlags);
+    QFETCH(qreal, c2_effectiveOpacity);
+    QFETCH(qreal, c3_effectiveOpacity);
+
+    QGraphicsRectItem *p = new QGraphicsRectItem;
+    QGraphicsRectItem *c1 = new QGraphicsRectItem(p);
+    QGraphicsRectItem *c2 = new QGraphicsRectItem(c1);
+    QGraphicsRectItem *c3 = new QGraphicsRectItem(c2);
+
+    QCOMPARE(p->opacity(), qreal(1.0));
+    QCOMPARE(p->effectiveOpacity(), qreal(1.0));
+    int opacityMask = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
+    QVERIFY(!(p->flags() & opacityMask));
+
+    p->setOpacity(p_opacity);
+    c1->setOpacity(c1_opacity);
+    c2->setOpacity(c2_opacity);
+    p->setFlags(QGraphicsItem::GraphicsItemFlags(p->flags() | p_opacityFlags));
+    c1->setFlags(QGraphicsItem::GraphicsItemFlags(c1->flags() | c1_opacityFlags));
+    c2->setFlags(QGraphicsItem::GraphicsItemFlags(c2->flags() | c2_opacityFlags));
+
+    QCOMPARE(int(p->flags() & opacityMask), p_opacityFlags);
+    QCOMPARE(int(c1->flags() & opacityMask), c1_opacityFlags);
+    QCOMPARE(int(c2->flags() & opacityMask), c2_opacityFlags);
+    QCOMPARE(p->opacity(), p_opacity);
+    QCOMPARE(p->effectiveOpacity(), p_effectiveOpacity);
+    QCOMPARE(c1->effectiveOpacity(), c1_effectiveOpacity);
+    QCOMPARE(c2->effectiveOpacity(), c2_effectiveOpacity);
+    QCOMPARE(c3->effectiveOpacity(), c3_effectiveOpacity);
+}
+
+void tst_QGraphicsItem::opacity2()
+{
+    EventTester *parent = new EventTester;
+    EventTester *child = new EventTester(parent);
+    EventTester *grandChild = new EventTester(child);
+
+    QGraphicsScene scene;
+    scene.addItem(parent);
+
+    class MyGraphicsView : public QGraphicsView
+    { public:
+        int repaints;
+        MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {}
+        void paintEvent(QPaintEvent *e) { ++repaints; QGraphicsView::paintEvent(e); }
+    };
+
+    MyGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTRY_VERIFY(view.repaints >= 1);
+
+#define RESET_REPAINT_COUNTERS \
+    parent->repaints = 0; \
+    child->repaints = 0; \
+    grandChild->repaints = 0; \
+    view.repaints = 0;
+
+    RESET_REPAINT_COUNTERS
+
+    child->setOpacity(0.0);
+    QTest::qWait(10);
+    QTRY_COMPARE(view.repaints, 1);
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(child->repaints, 0);
+    QCOMPARE(grandChild->repaints, 0);
+
+    RESET_REPAINT_COUNTERS
+
+    child->setOpacity(1.0);
+    QTest::qWait(10);
+    QTRY_COMPARE(view.repaints, 1);
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(child->repaints, 1);
+    QCOMPARE(grandChild->repaints, 1);
+
+    RESET_REPAINT_COUNTERS
+
+    parent->setOpacity(0.0);
+    QTest::qWait(10);
+    QTRY_COMPARE(view.repaints, 1);
+    QCOMPARE(parent->repaints, 0);
+    QCOMPARE(child->repaints, 0);
+    QCOMPARE(grandChild->repaints, 0);
+
+    RESET_REPAINT_COUNTERS
+
+    parent->setOpacity(1.0);
+    QTest::qWait(10);
+    QTRY_COMPARE(view.repaints, 1);
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(child->repaints, 1);
+    QCOMPARE(grandChild->repaints, 1);
+
+    grandChild->setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
+    RESET_REPAINT_COUNTERS
+
+    child->setOpacity(0.0);
+    QTest::qWait(10);
+    QTRY_COMPARE(view.repaints, 1);
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(child->repaints, 0);
+    QCOMPARE(grandChild->repaints, 1);
+
+    RESET_REPAINT_COUNTERS
+
+    child->setOpacity(0.0); // Already 0.0; no change.
+    QTest::qWait(10);
+    QTRY_COMPARE(view.repaints, 0);
+    QCOMPARE(parent->repaints, 0);
+    QCOMPARE(child->repaints, 0);
+    QCOMPARE(grandChild->repaints, 0);
+}
+
+void tst_QGraphicsItem::opacityZeroUpdates()
+{
+    EventTester *parent = new EventTester;
+    EventTester *child = new EventTester(parent);
+
+    child->setPos(10, 10);
+
+    QGraphicsScene scene;
+    scene.addItem(parent);
+
+    class MyGraphicsView : public QGraphicsView
+    { public:
+        int repaints;
+        QRegion paintedRegion;
+        MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {}
+        void paintEvent(QPaintEvent *e)
+        {
+            ++repaints;
+            paintedRegion += e->region();
+            QGraphicsView::paintEvent(e);
+        }
+        void reset() { repaints = 0; paintedRegion = QRegion(); }
+    };
+
+    MyGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTRY_VERIFY(view.repaints > 0);
+
+    view.reset();
+    parent->setOpacity(0.0);
+
+    QTest::qWait(20);
+
+    // transforming items bounding rect to view coordinates
+    const QRect childDeviceBoundingRect = child->deviceTransform(view.viewportTransform())
+                                           .mapRect(child->boundingRect()).toRect();
+    const QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
+                                           .mapRect(parent->boundingRect()).toRect();
+
+    QRegion expectedRegion = parentDeviceBoundingRect.adjusted(-2, -2, 2, 2);
+    expectedRegion += childDeviceBoundingRect.adjusted(-2, -2, 2, 2);
+
+    COMPARE_REGIONS(view.paintedRegion, expectedRegion);
+}
+
+class StacksBehindParentHelper : public QGraphicsRectItem
+{
+public:
+    StacksBehindParentHelper(QList<QGraphicsItem *> *paintedItems, const QRectF &rect, QGraphicsItem *parent = 0)
+        : QGraphicsRectItem(rect, parent), paintedItems(paintedItems)
+    { }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+    {
+        QGraphicsRectItem::paint(painter, option, widget);
+        paintedItems->append(this);
+    }
+
+private:
+    QList<QGraphicsItem *> *paintedItems;
+};
+
+void tst_QGraphicsItem::itemStacksBehindParent()
+{
+    StacksBehindParentHelper *parent1 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
+    StacksBehindParentHelper *child11 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent1);
+    StacksBehindParentHelper *grandChild111 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child11);
+    StacksBehindParentHelper *child12 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent1);
+    StacksBehindParentHelper *grandChild121 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child12);
+
+    StacksBehindParentHelper *parent2 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
+    StacksBehindParentHelper *child21 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent2);
+    StacksBehindParentHelper *grandChild211 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child21);
+    StacksBehindParentHelper *child22 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent2);
+    StacksBehindParentHelper *grandChild221 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child22);
+
+    parent1->setData(0, "parent1");
+    child11->setData(0, "child11");
+    grandChild111->setData(0, "grandChild111");
+    child12->setData(0, "child12");
+    grandChild121->setData(0, "grandChild121");
+    parent2->setData(0, "parent2");
+    child21->setData(0, "child21");
+    grandChild211->setData(0, "grandChild211");
+    child22->setData(0, "child22");
+    grandChild221->setData(0, "grandChild221");
+
+    // Disambiguate siblings
+    parent1->setZValue(1);
+    child11->setZValue(1);
+    child21->setZValue(1);
+
+    QGraphicsScene scene;
+    scene.addItem(parent1);
+    scene.addItem(parent2);
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTRY_VERIFY(!paintedItems.isEmpty());
+    QTest::qWait(100);
+    paintedItems.clear();
+    view.viewport()->update();
+    QApplication::processEvents();
+    QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
+                                           << grandChild111 << child11
+                                           << grandChild121 << child12 << parent1
+                                           << grandChild211 << child21
+                                           << grandChild221 << child22 << parent2));
+    QTRY_COMPARE(paintedItems, QList<QGraphicsItem *>()
+             << parent2 << child22 << grandChild221
+             << child21 << grandChild211
+             << parent1 << child12 << grandChild121
+             << child11 << grandChild111);
+
+    child11->setFlag(QGraphicsItem::ItemStacksBehindParent);
+    scene.update();
+    paintedItems.clear();
+    QApplication::processEvents();
+
+    QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
+                                           << grandChild121 << child12 << parent1
+                                           << grandChild111 << child11
+                                           << grandChild211 << child21
+                                           << grandChild221 << child22 << parent2));
+    QCOMPARE(paintedItems, QList<QGraphicsItem *>()
+             << parent2 << child22 << grandChild221
+             << child21 << grandChild211
+             << child11 << grandChild111
+             << parent1 << child12 << grandChild121);
+
+    child12->setFlag(QGraphicsItem::ItemStacksBehindParent);
+    paintedItems.clear();
+    scene.update();
+    QApplication::processEvents();
+
+    QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
+                                           << parent1 << grandChild111 << child11
+                                           << grandChild121 << child12
+                                           << grandChild211 << child21
+                                           << grandChild221 << child22 << parent2));
+    QCOMPARE(paintedItems, QList<QGraphicsItem *>()
+             << parent2 << child22 << grandChild221
+             << child21 << grandChild211
+             << child12 << grandChild121
+             << child11 << grandChild111 << parent1);
+}
+
+class ClippingAndTransformsScene : public QGraphicsScene
+{
+public:
+    QList<QGraphicsItem *> drawnItems;
+protected:
+    void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[],
+                   const QStyleOptionGraphicsItem options[], QWidget *widget = 0)
+    {
+        drawnItems.clear();
+        for (int i = 0; i < numItems; ++i)
+            drawnItems << items[i];
+        QGraphicsScene::drawItems(painter, numItems, items, options, widget);
+    }
+};
+
+void tst_QGraphicsItem::nestedClipping()
+{
+    ClippingAndTransformsScene scene;
+    scene.setSceneRect(-50, -50, 200, 200);
+
+    QGraphicsRectItem *root = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
+    root->setBrush(QColor(0, 0, 255));
+    root->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    QGraphicsRectItem *l1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
+    l1->setParentItem(root);
+    l1->setPos(-50, 0);
+    l1->setBrush(QColor(255, 0, 0));
+    l1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    QGraphicsEllipseItem *l2 = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100));
+    l2->setParentItem(l1);
+    l2->setPos(50, 50);
+    l2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    l2->setBrush(QColor(255, 255, 0));
+    QGraphicsRectItem *l3 = new QGraphicsRectItem(QRectF(0, 0, 25, 25));
+    l3->setParentItem(l2);
+    l3->setBrush(QColor(0, 255, 0));
+    l3->setPos(50 - 12, -12);
+
+    scene.addItem(root);
+
+    root->setData(0, "root");
+    l1->setData(0, "l1");
+    l2->setData(0, "l2");
+    l3->setData(0, "l3");
+
+    QGraphicsView view(&scene);
+    view.setOptimizationFlag(QGraphicsView::IndirectPainting);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(25);
+
+    QList<QGraphicsItem *> expected;
+    expected << root << l1 << l2 << l3;
+    QTRY_COMPARE(scene.drawnItems, expected);
+
+    QImage image(200, 200, QImage::Format_ARGB32_Premultiplied);
+    image.fill(0);
+
+    QPainter painter(&image);
+    scene.render(&painter);
+    painter.end();
+
+    // Check transparent areas
+    QCOMPARE(image.pixel(100, 25), qRgba(0, 0, 0, 0));
+    QCOMPARE(image.pixel(100, 175), qRgba(0, 0, 0, 0));
+    QCOMPARE(image.pixel(25, 100), qRgba(0, 0, 0, 0));
+    QCOMPARE(image.pixel(175, 100), qRgba(0, 0, 0, 0));
+    QCOMPARE(image.pixel(70, 80), qRgba(255, 0, 0, 255));
+    QCOMPARE(image.pixel(80, 130), qRgba(255, 255, 0, 255));
+    QCOMPARE(image.pixel(92, 105), qRgba(0, 255, 0, 255));
+    QCOMPARE(image.pixel(105, 105), qRgba(0, 0, 255, 255));
+#if 0
+    // Enable this to compare if the test starts failing.
+    image.save("nestedClipping_reference.png");
+#endif
+}
+
+class TransformDebugItem : public QGraphicsRectItem
+{
+public:
+    TransformDebugItem()
+        : QGraphicsRectItem(QRectF(-10, -10, 20, 20))
+    {
+        setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+    }
+
+    QTransform x;
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+               QWidget *widget = 0)
+    {
+        x = painter->worldTransform();
+        QGraphicsRectItem::paint(painter, option, widget);
+    }
+};
+
+void tst_QGraphicsItem::nestedClippingTransforms()
+{
+    TransformDebugItem *rootClipper = new TransformDebugItem;
+    rootClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    TransformDebugItem *child = new TransformDebugItem;
+    child->setParentItem(rootClipper);
+    child->setPos(2, 2);
+    TransformDebugItem *grandChildClipper = new TransformDebugItem;
+    grandChildClipper->setParentItem(child);
+    grandChildClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    grandChildClipper->setPos(4, 4);
+    TransformDebugItem *greatGrandChild = new TransformDebugItem;
+    greatGrandChild->setPos(2, 2);
+    greatGrandChild->setParentItem(grandChildClipper);
+    TransformDebugItem *grandChildClipper2 = new TransformDebugItem;
+    grandChildClipper2->setParentItem(child);
+    grandChildClipper2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    grandChildClipper2->setPos(8, 8);
+    TransformDebugItem *greatGrandChild2 = new TransformDebugItem;
+    greatGrandChild2->setPos(2, 2);
+    greatGrandChild2->setParentItem(grandChildClipper2);
+    TransformDebugItem *grandChildClipper3 = new TransformDebugItem;
+    grandChildClipper3->setParentItem(child);
+    grandChildClipper3->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    grandChildClipper3->setPos(12, 12);
+    TransformDebugItem *greatGrandChild3 = new TransformDebugItem;
+    greatGrandChild3->setPos(2, 2);
+    greatGrandChild3->setParentItem(grandChildClipper3);
+
+    QGraphicsScene scene;
+    scene.addItem(rootClipper);
+
+    QImage image(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
+    image.fill(0);
+    QPainter p(&image);
+    scene.render(&p);
+    p.end();
+
+    QCOMPARE(rootClipper->x, QTransform(1, 0, 0, 0, 1, 0, 10, 10, 1));
+    QCOMPARE(child->x, QTransform(1, 0, 0, 0, 1, 0, 12, 12, 1));
+    QCOMPARE(grandChildClipper->x, QTransform(1, 0, 0, 0, 1, 0, 16, 16, 1));
+    QCOMPARE(greatGrandChild->x, QTransform(1, 0, 0, 0, 1, 0, 18, 18, 1));
+    QCOMPARE(grandChildClipper2->x, QTransform(1, 0, 0, 0, 1, 0, 20, 20, 1));
+    QCOMPARE(greatGrandChild2->x, QTransform(1, 0, 0, 0, 1, 0, 22, 22, 1));
+    QCOMPARE(grandChildClipper3->x, QTransform(1, 0, 0, 0, 1, 0, 24, 24, 1));
+    QCOMPARE(greatGrandChild3->x, QTransform(1, 0, 0, 0, 1, 0, 26, 26, 1));
+}
+
+void tst_QGraphicsItem::sceneTransformCache()
+{
+    // Test that an item's scene transform is updated correctly when the
+    // parent is transformed.
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
+    QGraphicsRectItem *rect2 = scene.addRect(0, 0, 100, 100);
+    rect2->setParentItem(rect);
+    rect2->rotate(90);
+    rect->translate(0, 50);
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+
+    rect->translate(0, 100);
+    QTransform x;
+    x.translate(0, 150);
+    x.rotate(90);
+    QCOMPARE(rect2->sceneTransform(), x);
+
+    scene.removeItem(rect);
+
+    //Crazy use case : rect4 child of rect3 so the transformation of rect4 will be cached.Good!
+    //We remove rect4 from the scene, then the validTransform bit flag is set to 0 and the index of the cache
+    //add to the freeTransformSlots. The problem was that sceneTransformIndex was not set to -1 so if a new item arrive
+    //with a child (rect6) that will be cached then it will take the freeSlot (ex rect4) and put it his transform. But if rect4 is
+    //added back to the scene then it will set the transform to his old sceneTransformIndex value that will erase the new
+    //value of rect6 so rect6 transform will be wrong.
+    QGraphicsRectItem *rect3 = scene.addRect(0, 0, 100, 100);
+    QGraphicsRectItem *rect4 = scene.addRect(0, 0, 100, 100);
+    rect3->setPos(QPointF(10,10));
+
+    rect4->setParentItem(rect3);
+    rect4->setPos(QPointF(10,10));
+
+    QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(20,20));
+
+    scene.removeItem(rect4);
+    //rect4 transform is local only
+    QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
+
+    QGraphicsRectItem *rect5 = scene.addRect(0, 0, 100, 100);
+    QGraphicsRectItem *rect6 = scene.addRect(0, 0, 100, 100);
+    rect5->setPos(QPointF(20,20));
+
+    rect6->setParentItem(rect5);
+    rect6->setPos(QPointF(10,10));
+    //test if rect6 transform is ok
+    QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
+
+    scene.addItem(rect4);
+
+    QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
+    //test if rect6 transform is still correct
+    QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
+}
+
+void tst_QGraphicsItem::tabChangesFocus_data()
+{
+    QTest::addColumn<bool>("tabChangesFocus");
+    QTest::newRow("tab changes focus") << true;
+    QTest::newRow("tab doesn't change focus") << false;
+}
+
+void tst_QGraphicsItem::tabChangesFocus()
+{
+    QFETCH(bool, tabChangesFocus);
+
+    QGraphicsScene scene;
+    QGraphicsTextItem *item = scene.addText("Hello");
+    item->setTabChangesFocus(tabChangesFocus);
+    item->setTextInteractionFlags(Qt::TextEditorInteraction);
+    item->setFocus();
+
+    QDial *dial1 = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+
+    QDial *dial2 = new QDial;
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->addWidget(dial1);
+    layout->addWidget(view);
+    layout->addWidget(dial2);
+
+    QWidget widget;
+    widget.setLayout(layout);
+    widget.show();
+    QTest::qWaitForWindowShown(&widget);
+
+    QTRY_VERIFY(scene.isActive());
+
+    dial1->setFocus();
+    QTest::qWait(15);
+    QTRY_VERIFY(dial1->hasFocus());
+
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QTest::qWait(15);
+    QTRY_VERIFY(view->hasFocus());
+    QTRY_VERIFY(item->hasFocus());
+
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QTest::qWait(15);
+
+    if (tabChangesFocus) {
+        QTRY_VERIFY(!view->hasFocus());
+        QTRY_VERIFY(!item->hasFocus());
+        QTRY_VERIFY(dial2->hasFocus());
+    } else {
+        QTRY_VERIFY(view->hasFocus());
+        QTRY_VERIFY(item->hasFocus());
+        QCOMPARE(item->toPlainText(), QString("\tHello"));
+    }
+}
+
+void tst_QGraphicsItem::cacheMode()
+{
+    QGraphicsScene scene(0, 0, 100, 100);
+    QGraphicsView view(&scene);
+    view.resize(150, 150);
+    view.show();
+    QApplication::setActiveWindow(&view);
+    QTest::qWaitForWindowShown(&view);
+
+    // Increase the probability of window activation
+    // not causing another repaint of test items.
+    QTest::qWait(50);
+
+    EventTester *tester = new EventTester;
+    EventTester *testerChild = new EventTester;
+    testerChild->setParentItem(tester);
+    EventTester *testerChild2 = new EventTester;
+    testerChild2->setParentItem(testerChild);
+    testerChild2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
+
+    scene.addItem(tester);
+    QTest::qWait(10);
+
+    for (int i = 0; i < 2; ++i) {
+        // No visual change.
+        QTRY_COMPARE(tester->repaints, 1);
+        QCOMPARE(testerChild->repaints, 1);
+        QCOMPARE(testerChild2->repaints, 1);
+        tester->setCacheMode(QGraphicsItem::NoCache);
+        testerChild->setCacheMode(QGraphicsItem::NoCache);
+        testerChild2->setCacheMode(QGraphicsItem::NoCache);
+        QTest::qWait(25);
+        QTRY_COMPARE(tester->repaints, 1);
+        QCOMPARE(testerChild->repaints, 1);
+        QCOMPARE(testerChild2->repaints, 1);
+        tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+        testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+        testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+        QTest::qWait(25);
+    }
+
+    // The first move causes a repaint as the item is painted into its pixmap.
+    // (Only occurs if the item has previously been painted without cache).
+    tester->setPos(10, 10);
+    testerChild->setPos(10, 10);
+    testerChild2->setPos(10, 10);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 2);
+    QCOMPARE(testerChild->repaints, 2);
+    QCOMPARE(testerChild2->repaints, 2);
+
+    // Consecutive moves should not repaint.
+    tester->setPos(20, 20);
+    testerChild->setPos(20, 20);
+    testerChild2->setPos(20, 20);
+    QTest::qWait(250);
+    QCOMPARE(tester->repaints, 2);
+    QCOMPARE(testerChild->repaints, 2);
+    QCOMPARE(testerChild2->repaints, 2);
+
+    // Translating does not result in a repaint.
+    tester->translate(10, 10);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 2);
+    QCOMPARE(testerChild->repaints, 2);
+    QCOMPARE(testerChild2->repaints, 2);
+
+    // Rotating results in a repaint.
+    tester->rotate(45);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 3);
+    QCOMPARE(testerChild->repaints, 3);
+    QCOMPARE(testerChild2->repaints, 2);
+
+    // Change to ItemCoordinateCache (triggers repaint).
+    tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
+    testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
+    testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 4);
+    QCOMPARE(testerChild->repaints, 4);
+    QCOMPARE(testerChild2->repaints, 3);
+
+    // Rotating items with ItemCoordinateCache doesn't cause a repaint.
+    tester->rotate(22);
+    testerChild->rotate(22);
+    testerChild2->rotate(22);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 4);
+    QCOMPARE(testerChild->repaints, 4);
+    QCOMPARE(testerChild2->repaints, 3);
+
+    // Explicit update causes a repaint.
+    tester->update(0, 0, 5, 5);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 5);
+    QCOMPARE(testerChild->repaints, 4);
+    QCOMPARE(testerChild2->repaints, 3);
+
+    // Updating outside the item's bounds does not cause a repaint.
+    tester->update(10, 10, 5, 5);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 5);
+    QCOMPARE(testerChild->repaints, 4);
+    QCOMPARE(testerChild2->repaints, 3);
+
+    // Resizing an item should cause a repaint of that item. (because of
+    // autosize).
+    tester->setGeometry(QRectF(-15, -15, 30, 30));
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 6);
+    QCOMPARE(testerChild->repaints, 4);
+    QCOMPARE(testerChild2->repaints, 3);
+
+    // Set fixed size.
+    tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
+    testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
+    testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
+    QTest::qWait(20);
+    QTRY_COMPARE(tester->repaints, 7);
+    QCOMPARE(testerChild->repaints, 5);
+    QCOMPARE(testerChild2->repaints, 4);
+
+    // Resizing the item should cause a repaint.
+    testerChild->setGeometry(QRectF(-15, -15, 30, 30));
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 7);
+    QCOMPARE(testerChild->repaints, 6);
+    QCOMPARE(testerChild2->repaints, 4);
+
+    // Scaling the view does not cause a repaint.
+    view.scale(0.7, 0.7);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 7);
+    QCOMPARE(testerChild->repaints, 6);
+    QCOMPARE(testerChild2->repaints, 4);
+
+    // Switch to device coordinate cache.
+    tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+    testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+    testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 8);
+    QCOMPARE(testerChild->repaints, 7);
+    QCOMPARE(testerChild2->repaints, 5);
+
+    // Scaling the view back should cause repaints for two of the items.
+    view.setTransform(QTransform());
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 9);
+    QCOMPARE(testerChild->repaints, 8);
+    QCOMPARE(testerChild2->repaints, 5);
+
+    // Rotating the base item (perspective) should repaint two items.
+    tester->setTransform(QTransform().rotate(10, Qt::XAxis));
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 10);
+    QCOMPARE(testerChild->repaints, 9);
+    QCOMPARE(testerChild2->repaints, 5);
+
+    // Moving the middle item should case a repaint even if it's a move,
+    // because the parent is rotated with a perspective.
+    testerChild->setPos(1, 1);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 10);
+    QCOMPARE(testerChild->repaints, 10);
+    QCOMPARE(testerChild2->repaints, 5);
+
+    // Make a huge item
+    tester->setGeometry(QRectF(-4000, -4000, 8000, 8000));
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 11);
+    QCOMPARE(testerChild->repaints, 10);
+    QCOMPARE(testerChild2->repaints, 5);
+
+    // Move the large item - will cause a repaint as the
+    // cache is clipped.
+    tester->setPos(5, 0);
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 12);
+    QCOMPARE(testerChild->repaints, 10);
+    QCOMPARE(testerChild2->repaints, 5);
+
+    // Hiding and showing should invalidate the cache
+    tester->hide();
+    QTest::qWait(25);
+    tester->show();
+    QTest::qWait(25);
+    QTRY_COMPARE(tester->repaints, 13);
+    QCOMPARE(testerChild->repaints, 11);
+    QCOMPARE(testerChild2->repaints, 6);
+}
+
+void tst_QGraphicsItem::updateCachedItemAfterMove()
+{
+    // A simple item that uses ItemCoordinateCache
+    EventTester *tester = new EventTester;
+    tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+
+    // Add to a scene, show in a view, ensure it's painted and reset its
+    // repaint counter.
+    QGraphicsScene scene;
+    scene.addItem(tester);
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+
+    QTest::qWait(12);
+    QTRY_VERIFY(tester->repaints > 0);
+    tester->repaints = 0;
+
+    // Move the item, should not cause repaints
+    tester->setPos(10, 0);
+    QTest::qWait(12);
+    QCOMPARE(tester->repaints, 0);
+
+    // Move then update, should cause one repaint
+    tester->setPos(20, 0);
+    tester->update();
+    QTest::qWait(12);
+    QCOMPARE(tester->repaints, 1);
+
+    // Hiding the item doesn't cause a repaint
+    tester->hide();
+    QTest::qWait(12);
+    QCOMPARE(tester->repaints, 1);
+
+    // Moving a hidden item doesn't cause a repaint
+    tester->setPos(30, 0);
+    tester->update();
+    QTest::qWait(12);
+    QCOMPARE(tester->repaints, 1);
+}
+
+class Track : public QGraphicsRectItem
+{
+public:
+    Track(const QRectF &rect)
+        : QGraphicsRectItem(rect)
+    {
+        setAcceptHoverEvents(true);
+    }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
+    {
+        QGraphicsRectItem::paint(painter, option, widget);
+        painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1x%2\n%3x%4").arg(p.x()).arg(p.y()).arg(sp.x()).arg(sp.y()));
+    }
+
+protected:
+    void hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+    {
+        p = event->pos();
+        sp = event->widget()->mapFromGlobal(event->screenPos());
+        update();
+    }
+private:
+    QPointF p;
+    QPoint sp;
+};
+
+void tst_QGraphicsItem::deviceTransform_data()
+{
+    QTest::addColumn<bool>("untransformable1");
+    QTest::addColumn<bool>("untransformable2");
+    QTest::addColumn<bool>("untransformable3");
+    QTest::addColumn<qreal>("rotation1");
+    QTest::addColumn<qreal>("rotation2");
+    QTest::addColumn<qreal>("rotation3");
+    QTest::addColumn<QTransform>("deviceX");
+    QTest::addColumn<QPointF>("mapResult1");
+    QTest::addColumn<QPointF>("mapResult2");
+    QTest::addColumn<QPointF>("mapResult3");
+
+    QTest::newRow("nil") << false << false << false
+                         << qreal(0.0) << qreal(0.0) << qreal(0.0)
+                         << QTransform()
+                         << QPointF(150, 150) << QPointF(250, 250) << QPointF(350, 350);
+    QTest::newRow("deviceX rot 90") << false << false << false
+                         << qreal(0.0) << qreal(0.0) << qreal(0.0)
+                         << QTransform().rotate(90)
+                         << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-350, 350);
+    QTest::newRow("deviceX rot 90 100") << true << false << false
+                         << qreal(0.0) << qreal(0.0) << qreal(0.0)
+                         << QTransform().rotate(90)
+                         << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
+    QTest::newRow("deviceX rot 90 010") << false << true << false
+                         << qreal(0.0) << qreal(0.0) << qreal(0.0)
+                         << QTransform().rotate(90)
+                         << QPointF(-150, 150) << QPointF(-150, 250) << QPointF(-50, 350);
+    QTest::newRow("deviceX rot 90 001") << false << false << true
+                         << qreal(0.0) << qreal(0.0) << qreal(0.0)
+                         << QTransform().rotate(90)
+                         << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-250, 350);
+    QTest::newRow("deviceX rot 90 111") << true << true << true
+                         << qreal(0.0) << qreal(0.0) << qreal(0.0)
+                         << QTransform().rotate(90)
+                         << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
+    QTest::newRow("deviceX rot 90 101") << true << false << true
+                         << qreal(0.0) << qreal(0.0) << qreal(0.0)
+                         << QTransform().rotate(90)
+                         << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
+}
+
+void tst_QGraphicsItem::deviceTransform()
+{
+    QFETCH(bool, untransformable1);
+    QFETCH(bool, untransformable2);
+    QFETCH(bool, untransformable3);
+    QFETCH(qreal, rotation1);
+    QFETCH(qreal, rotation2);
+    QFETCH(qreal, rotation3);
+    QFETCH(QTransform, deviceX);
+    QFETCH(QPointF, mapResult1);
+    QFETCH(QPointF, mapResult2);
+    QFETCH(QPointF, mapResult3);
+
+    QGraphicsScene scene;
+    Track *rect1 = new Track(QRectF(0, 0, 100, 100));
+    Track *rect2 = new Track(QRectF(0, 0, 100, 100));
+    Track *rect3 = new Track(QRectF(0, 0, 100, 100));
+    rect2->setParentItem(rect1);
+    rect3->setParentItem(rect2);
+    rect1->setPos(100, 100);
+    rect2->setPos(100, 100);
+    rect3->setPos(100, 100);
+    rect1->rotate(rotation1);
+    rect2->rotate(rotation2);
+    rect3->rotate(rotation3);
+    rect1->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable1);
+    rect2->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable2);
+    rect3->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable3);
+    rect1->setBrush(Qt::red);
+    rect2->setBrush(Qt::green);
+    rect3->setBrush(Qt::blue);
+    scene.addItem(rect1);
+
+    QCOMPARE(rect1->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult1);
+    QCOMPARE(rect2->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult2);
+    QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3);
+}
+
+class MyGraphicsView : public QGraphicsView
+{
+public:
+    int repaints;
+    QRegion paintedRegion;
+    MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {}
+    void paintEvent(QPaintEvent *e)
+    {
+        paintedRegion += e->region();
+        ++repaints;
+        QGraphicsView::paintEvent(e);
+    }
+    void reset() { repaints = 0; paintedRegion = QRegion(); }
+};
+
+void tst_QGraphicsItem::update()
+{
+    QGraphicsScene scene;
+    scene.setSceneRect(-100, -100, 200, 200);
+    MyGraphicsView view(&scene);
+
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(100);
+
+    EventTester *item = new EventTester;
+    scene.addItem(item);
+    QTest::qWait(100); // Make sure all pending updates are processed.
+    item->repaints = 0;
+
+    item->update(); // Item marked as dirty
+    scene.update(); // Entire scene marked as dirty
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 1);
+
+    // Make sure the dirty state from the previous update is reset so that
+    // the item don't think it is already dirty and discards this update.
+    item->update();
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 2);
+
+    // Make sure a partial update doesn't cause a full update to be discarded.
+    view.reset();
+    item->repaints = 0;
+    item->update(QRectF(0, 0, 5, 5));
+    item->update();
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
+                                                         .mapRect(item->boundingRect()).toRect();
+    QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
+    // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
+    QCOMPARE(view.paintedRegion, expectedRegion);
+
+    // Make sure update requests outside the bounding rect are discarded.
+    view.reset();
+    item->repaints = 0;
+    item->update(-15, -15, 5, 5); // Item's brect: (-10, -10, 20, 20)
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 0);
+    QCOMPARE(view.repaints, 0);
+
+    // Make sure the area occupied by an item is repainted when hiding it.
+    view.reset();
+    item->repaints = 0;
+    item->update(); // Full update; all sub-sequent update requests are discarded.
+    item->hide(); // visible set to 0. ignoreVisible must be set to 1; the item won't be processed otherwise.
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 0);
+    QCOMPARE(view.repaints, 1);
+    // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
+    QCOMPARE(view.paintedRegion, expectedRegion);
+
+    // Make sure item is repainted when shown (after being hidden).
+    view.reset();
+    item->repaints = 0;
+    item->show();
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
+    QCOMPARE(view.paintedRegion, expectedRegion);
+
+    item->repaints = 0;
+    item->hide();
+    qApp->processEvents();
+    view.reset();
+    const QPointF originalPos = item->pos();
+    item->setPos(5000, 5000);
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 0);
+    QCOMPARE(view.repaints, 0);
+    qApp->processEvents();
+
+    item->setPos(originalPos);
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 0);
+    QCOMPARE(view.repaints, 0);
+    item->show();
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
+    QCOMPARE(view.paintedRegion, expectedRegion);
+
+    QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
+    item->setPos(originalPos + QPoint(50, 50));
+    viewPrivate->updateAll();
+    QVERIFY(viewPrivate->fullUpdatePending);
+    QTest::qWait(50);
+    item->repaints = 0;
+    view.reset();
+    item->setPos(originalPos);
+    QTest::qWait(50);
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    COMPARE_REGIONS(view.paintedRegion, expectedRegion + expectedRegion.translated(50, 50));
+
+    // Make sure moving a parent item triggers an update on the children
+    // (even though the parent itself is outside the viewport).
+    QGraphicsRectItem *parent = new QGraphicsRectItem(0, 0, 10, 10);
+    parent->setPos(-400, 0);
+    item->setParentItem(parent);
+    item->setPos(400, 0);
+    scene.addItem(parent);
+    QTest::qWait(50);
+    itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
+                                                   .mapRect(item->boundingRect()).toRect();
+    expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
+    view.reset();
+    item->repaints = 0;
+    parent->translate(-400, 0);
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 0);
+    QCOMPARE(view.repaints, 1);
+    QCOMPARE(view.paintedRegion, expectedRegion);
+    view.reset();
+    item->repaints = 0;
+    parent->translate(400, 0);
+    qApp->processEvents();
+    QCOMPARE(item->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    QCOMPARE(view.paintedRegion, expectedRegion);
+    QCOMPARE(view.paintedRegion, expectedRegion);
+}
+
+void tst_QGraphicsItem::setTransformProperties_data()
+{
+    QTest::addColumn<QPointF>("origin");
+    QTest::addColumn<qreal>("rotation");
+    QTest::addColumn<qreal>("scale");
+
+    QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(1.0);
+
+    QTest::newRow("rotation") << QPointF() << qreal(42.2) << qreal(1.0);
+
+    QTest::newRow("rotation dicentred") << QPointF(qreal(22.3), qreal(-56.2))
+                                << qreal(-2578.2)
+                                << qreal(1.0);
+
+    QTest::newRow("Scale")    << QPointF() << qreal(0.0)
+                                          << qreal(6);
+
+    QTest::newRow("Everything dicentred")  << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196);
+}
+
+/**
+ * the normal QCOMPARE doesn't work because it doesn't use qFuzzyCompare
+ */
+#define QCOMPARE_TRANSFORM(X1, X2)   QVERIFY(((X1)*(X2).inverted()).isIdentity())
+
+void tst_QGraphicsItem::setTransformProperties()
+{
+    QFETCH(QPointF,origin);
+    QFETCH(qreal,rotation);
+    QFETCH(qreal,scale);
+
+    QTransform result;
+    result.translate(origin.x(), origin.y());
+    result.rotate(rotation, Qt::ZAxis);
+    result.scale(scale, scale);
+    result.translate(-origin.x(), -origin.y());
+
+    QGraphicsScene scene;
+    QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
+    scene.addItem(item);
+
+    item->setRotation(rotation);
+    item->setScale(scale);
+    item->setTransformOriginPoint(origin);
+
+    QCOMPARE(item->rotation(), rotation);
+    QCOMPARE(item->scale(), scale);
+    QCOMPARE(item->transformOriginPoint(), origin);
+
+    QCOMPARE(QTransform(), item->transform());
+    QCOMPARE(result, item->sceneTransform());
+
+    //-----------------------------------------------------------------
+    //Change the rotation Z
+    item->setRotation(45);
+    QTransform result2;
+    result2.translate(origin.x(), origin.y());
+    result2.rotate(45);
+    result2.scale(scale, scale);
+    result2.translate(-origin.x(), -origin.y());
+
+    QCOMPARE(item->rotation(), 45.);
+    QCOMPARE(item->scale(), scale);
+    QCOMPARE(item->transformOriginPoint(), origin);
+
+    QCOMPARE(QTransform(), item->transform());
+    QCOMPARE(result2, item->sceneTransform());
+
+    //-----------------------------------------------------------------
+    // calling setTransform() and setPos should change the sceneTransform
+    item->setTransform(result);
+    item->setPos(100, -150.5);
+
+    QCOMPARE(item->rotation(), 45.);
+    QCOMPARE(item->scale(), scale);
+    QCOMPARE(item->transformOriginPoint(), origin);
+    QCOMPARE(result, item->transform());
+
+    QTransform result3(result);
+
+    result3.translate(origin.x(), origin.y());
+    result3.rotate(45);
+    result3.scale(scale, scale);
+    result3.translate(-origin.x(), -origin.y());
+
+    result3 *= QTransform::fromTranslate(100, -150.5); //the pos;
+
+    QCOMPARE(result3, item->sceneTransform());
+
+    //-----------------------------------------------------
+    // setting the propertiees should be the same as setting a transform
+    {//with center origin on the matrix
+        QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
+        scene.addItem(item1);
+        QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
+        scene.addItem(item2);
+
+        item1->setPos(12.3, -5);
+        item2->setPos(12.3, -5);
+        item1->setRotation(rotation);
+        item1->setScale(scale);
+        item1->setTransformOriginPoint(origin);
+
+        item2->setTransform(result);
+
+        QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform());
+
+        QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform());
+        QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform());
+    }
+}
+
+class MyStyleOptionTester : public QGraphicsRectItem
+{
+public:
+    MyStyleOptionTester(const QRectF &rect)
+        : QGraphicsRectItem(rect), startTrack(false)
+    {}
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
+    {
+        if (startTrack) {
+            //Doesn't use the extended style option so the exposed rect is the boundingRect
+            if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) {
+                QCOMPARE(option->exposedRect, boundingRect());
+                QCOMPARE(option->matrix, QMatrix());
+            } else {
+                QVERIFY(option->exposedRect != QRect());
+                QVERIFY(option->exposedRect != boundingRect());
+                QCOMPARE(option->matrix, sceneTransform().toAffine());
+            }
+        }
+        QGraphicsRectItem::paint(painter, option, widget);
+    }
+    bool startTrack;
+};
+
+void tst_QGraphicsItem::itemUsesExtendedStyleOption()
+{
+    QGraphicsScene scene(0, 0, 300, 300);
+    QGraphicsPixmapItem item;
+    item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
+    QCOMPARE(item.flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
+    item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
+    QCOMPARE(item.flags(), 0);
+
+    //We now test the content of the style option
+    MyStyleOptionTester *rect = new MyStyleOptionTester(QRect(0, 0, 100, 100));
+    scene.addItem(rect);
+    rect->setPos(200, 200);
+    QGraphicsView view(&scene);
+    rect->startTrack = false;
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(60);
+    rect->startTrack = true;
+    rect->update(10, 10, 10, 10);
+    QTest::qWait(60);
+    rect->startTrack = false;
+    rect->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
+    QVERIFY((rect->flags() & QGraphicsItem::ItemUsesExtendedStyleOption));
+    QTest::qWait(60);
+    rect->startTrack = true;
+    rect->update(10, 10, 10, 10);
+    QTest::qWait(60);
+}
+
+void tst_QGraphicsItem::itemSendsGeometryChanges()
+{
+    ItemChangeTester item;
+    item.setFlags(0);
+    item.clear();
+
+    QTransform x = QTransform().rotate(45);
+    QPointF pos(10, 10);
+    qreal o(0.5);
+    item.setTransform(x);
+    item.setPos(pos);
+    QCOMPARE(item.transform(), x);
+    QCOMPARE(item.pos(), pos);
+    QCOMPARE(item.changes.size(), 0);
+
+    item.setOpacity(o);
+    QCOMPARE(item.changes.size(), 2); // opacity
+
+    item.setFlag(QGraphicsItem::ItemSendsGeometryChanges);
+    QCOMPARE(item.changes.size(), 4); // flags
+    item.setTransform(QTransform());
+    item.setPos(QPointF());
+    QCOMPARE(item.changes.size(), 8); // transform + pos
+    QCOMPARE(item.transform(), QTransform());
+    QCOMPARE(item.pos(), QPointF());
+    QCOMPARE(item.opacity(), o);
+
+    QCOMPARE(item.changes, QList<QGraphicsItem::GraphicsItemChange>()
+             << QGraphicsItem::ItemOpacityChange
+             << QGraphicsItem::ItemOpacityHasChanged
+             << QGraphicsItem::ItemFlagsChange
+             << QGraphicsItem::ItemFlagsHaveChanged
+             << QGraphicsItem::ItemTransformChange
+             << QGraphicsItem::ItemTransformHasChanged
+             << QGraphicsItem::ItemPositionChange
+             << QGraphicsItem::ItemPositionHasChanged);
+}
+
+// Make sure we update moved items correctly.
+void tst_QGraphicsItem::moveItem()
+{
+    QGraphicsScene scene;
+    scene.setSceneRect(-50, -50, 200, 200);
+
+    MyGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(100);
+
+    EventTester *parent = new EventTester;
+    EventTester *child = new EventTester(parent);
+    EventTester *grandChild = new EventTester(child);
+
+#define RESET_COUNTERS \
+    parent->repaints = 0; \
+    child->repaints = 0; \
+    grandChild->repaints = 0; \
+    view.reset();
+
+    scene.addItem(parent);
+    QTest::qWait(100);
+
+    RESET_COUNTERS
+
+    // Item's boundingRect:  (-10, -10, 20, 20).
+    QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
+                                     .mapRect(parent->boundingRect()).toRect()
+                                     .adjusted(-2, -2, 2, 2); // Adjusted for antialiasing.
+
+    parent->setPos(20, 20);
+    qApp->processEvents();
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    QRegion expectedParentRegion = parentDeviceBoundingRect; // old position
+    parentDeviceBoundingRect.translate(20, 20);
+    expectedParentRegion += parentDeviceBoundingRect; // new position
+    COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
+
+    RESET_COUNTERS
+
+    child->setPos(20, 20);
+    qApp->processEvents();
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(child->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    const QRegion expectedChildRegion = expectedParentRegion.translated(20, 20);
+    COMPARE_REGIONS(view.paintedRegion, expectedChildRegion);
+
+    RESET_COUNTERS
+
+    grandChild->setPos(20, 20);
+    qApp->processEvents();
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(child->repaints, 1);
+    QCOMPARE(grandChild->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    const QRegion expectedGrandChildRegion = expectedParentRegion.translated(40, 40);
+    COMPARE_REGIONS(view.paintedRegion, expectedGrandChildRegion);
+
+    RESET_COUNTERS
+
+    parent->translate(20, 20);
+    qApp->processEvents();
+    QCOMPARE(parent->repaints, 1);
+    QCOMPARE(child->repaints, 1);
+    QCOMPARE(grandChild->repaints, 1);
+    QCOMPARE(view.repaints, 1);
+    expectedParentRegion.translate(20, 20);
+    expectedParentRegion += expectedChildRegion.translated(20, 20);
+    expectedParentRegion += expectedGrandChildRegion.translated(20, 20);
+    COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
+}
+
+void tst_QGraphicsItem::sorting_data()
+{
+    QTest::addColumn<int>("index");
+
+    QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex);
+    QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex);
+}
+
+void tst_QGraphicsItem::sorting()
+{
+    _paintedItems.clear();
+
+    QGraphicsScene scene;
+    QGraphicsItem *grid[100][100];
+    for (int x = 0; x < 100; ++x) {
+        for (int y = 0; y < 100; ++y) {
+            PainterItem *item = new PainterItem;
+            item->setPos(x * 25, y * 25);
+            item->setData(0, QString("%1x%2").arg(x).arg(y));
+            grid[x][y] = item;
+            scene.addItem(item);
+        }
+    }
+
+    PainterItem *item1 = new PainterItem;
+    PainterItem *item2 = new PainterItem;
+    item1->setData(0, "item1");
+    item2->setData(0, "item2");
+    scene.addItem(item1);
+    scene.addItem(item2);
+
+    QGraphicsView view(&scene);
+    view.setResizeAnchor(QGraphicsView::NoAnchor);
+    view.setTransformationAnchor(QGraphicsView::NoAnchor);
+    view.resize(120, 100);
+    view.setFrameStyle(0);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(100);
+
+    _paintedItems.clear();
+
+    view.viewport()->repaint();
+#ifdef Q_WS_MAC
+    // There's no difference between repaint and update on the Mac,
+    // so we have to process events here to make sure we get the event.
+    QTest::qWait(100);
+#endif
+
+    QCOMPARE(_paintedItems, QList<QGraphicsItem *>()
+                 << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3]
+                 << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3]
+                 << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3]
+                 << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3]
+                 << grid[4][0] << grid[4][1] << grid[4][2] << grid[4][3]
+                 << item1 << item2);
+}
+
+void tst_QGraphicsItem::itemHasNoContents()
+{
+    PainterItem *item1 = new PainterItem;
+    PainterItem *item2 = new PainterItem;
+    item2->setParentItem(item1);
+    item2->setPos(50, 50);
+    item1->setFlag(QGraphicsItem::ItemHasNoContents);
+    item1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+
+    QGraphicsScene scene;
+    scene.addItem(item1);
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTRY_VERIFY(!_paintedItems.isEmpty());
+
+    _paintedItems.clear();
+
+    view.viewport()->repaint();
+#ifdef Q_WS_MAC
+    // There's no difference between update() and repaint() on the Mac,
+    // so we have to process events here to make sure we get the event.
+    QTest::qWait(10);
+#endif
+
+    QTRY_COMPARE(_paintedItems, QList<QGraphicsItem *>() << item2);
+}
+
+void tst_QGraphicsItem::hitTestUntransformableItem()
+{
+    QGraphicsScene scene;
+    scene.setSceneRect(-100, -100, 200, 200);
+
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(100);
+
+    // Confuse the BSP with dummy items.
+    QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
+    dummy->setPos(-100, -100);
+    scene.addItem(dummy);
+    for (int i = 0; i < 100; ++i) {
+        QGraphicsItem *parent = dummy;
+        dummy = new QGraphicsRectItem(0, 0, 20, 20);
+        dummy->setPos(-100 + i, -100 + i);
+        dummy->setParentItem(parent);
+    }
+
+    QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
+    item1->setPos(-200, -200);
+
+    QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 20, 20);
+    item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
+    item2->setParentItem(item1);
+    item2->setPos(200, 200);
+
+    QGraphicsRectItem *item3 = new QGraphicsRectItem(0, 0, 20, 20);
+    item3->setParentItem(item2);
+    item3->setPos(80, 80);
+
+    scene.addItem(item1);
+    QTest::qWait(100);
+
+    QList<QGraphicsItem *> items = scene.items(QPointF(80, 80));
+    QCOMPARE(items.size(), 1);
+    QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
+
+    scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+    QTest::qWait(100);
+
+    items = scene.items(QPointF(80, 80));
+    QCOMPARE(items.size(), 1);
+    QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
+}
+
+void tst_QGraphicsItem::hitTestGraphicsEffectItem()
+{
+    QGraphicsScene scene;
+    scene.setSceneRect(-100, -100, 200, 200);
+
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(100);
+
+    // Confuse the BSP with dummy items.
+    QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
+    dummy->setPos(-100, -100);
+    scene.addItem(dummy);
+    for (int i = 0; i < 100; ++i) {
+        QGraphicsItem *parent = dummy;
+        dummy = new QGraphicsRectItem(0, 0, 20, 20);
+        dummy->setPos(-100 + i, -100 + i);
+        dummy->setParentItem(parent);
+    }
+
+    const QRectF itemBoundingRect(0, 0, 20, 20);
+    EventTester *item1 = new EventTester;
+    item1->br = itemBoundingRect;
+    item1->setPos(-200, -200);
+
+    EventTester *item2 = new EventTester;
+    item2->br = itemBoundingRect;
+    item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
+    item2->setParentItem(item1);
+    item2->setPos(200, 200);
+
+    EventTester *item3 = new EventTester;
+    item3->br = itemBoundingRect;
+    item3->setParentItem(item2);
+    item3->setPos(80, 80);
+
+    scene.addItem(item1);
+    QTest::qWait(100);
+
+    item1->repaints = 0;
+    item2->repaints = 0;
+    item3->repaints = 0;
+
+    // Apply shadow effect to the entire sub-tree.
+    QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
+    shadow->setOffset(-20, -20);
+    item1->setGraphicsEffect(shadow);
+    QTest::qWait(50);
+
+    // Make sure all items are repainted.
+    QCOMPARE(item1->repaints, 1);
+    QCOMPARE(item2->repaints, 1);
+    QCOMPARE(item3->repaints, 1);
+
+    // Make sure an item doesn't respond to a click on its shadow.
+    QList<QGraphicsItem *> items = scene.items(QPointF(75, 75));
+    QVERIFY(items.isEmpty());
+    items = scene.items(QPointF(80, 80));
+    QCOMPARE(items.size(), 1);
+    QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
+
+    item1->repaints = 0;
+    item2->repaints = 0;
+    item3->repaints = 0;
+
+    view.viewport()->update(75, 75, 20, 20);
+    QTest::qWait(50);
+
+    // item1 is the effect source and must therefore be repainted.
+    // item2 intersects with the exposed region
+    // item3 is just another child outside the exposed region
+    QCOMPARE(item1->repaints, 1);
+    QCOMPARE(item2->repaints, 1);
+    QCOMPARE(item3->repaints, 0);
+
+    scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+    QTest::qWait(100);
+
+    items = scene.items(QPointF(75, 75));
+    QVERIFY(items.isEmpty());
+    items = scene.items(QPointF(80, 80));
+    QCOMPARE(items.size(), 1);
+    QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
+}
+
+void tst_QGraphicsItem::focusProxy()
+{
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    QGraphicsItem *item = scene.addRect(0, 0, 10, 10);
+    item->setFlag(QGraphicsItem::ItemIsFocusable);
+    QVERIFY(!item->focusProxy());
+
+    QGraphicsItem *item2 = scene.addRect(0, 0, 10, 10);
+    item2->setFlag(QGraphicsItem::ItemIsFocusable);
+    item->setFocusProxy(item2);
+    QCOMPARE(item->focusProxy(), item2);
+
+    item->setFocus();
+    QVERIFY(item->hasFocus());
+    QVERIFY(item2->hasFocus());
+
+    // Try to make a focus chain loop
+    QString err;
+    QTextStream stream(&err);
+    stream << "QGraphicsItem::setFocusProxy: "
+           << (void*)item << " is already in the focus proxy chain" << flush;
+    QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
+    item2->setFocusProxy(item); // fails
+    QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
+    QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
+
+    // Try to assign self as focus proxy
+    QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
+    item->setFocusProxy(item); // fails
+    QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
+    QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
+
+    // Reset the focus proxy
+    item->setFocusProxy(0);
+    QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
+    QVERIFY(!item->hasFocus());
+    QVERIFY(item2->hasFocus());
+
+    // Test deletion
+    item->setFocusProxy(item2);
+    QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
+    delete item2;
+    QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
+
+    // Test event delivery
+    item2 = scene.addRect(0, 0, 10, 10);
+    item2->setFlag(QGraphicsItem::ItemIsFocusable);
+    item->setFocusProxy(item2);
+    item->clearFocus();
+
+    EventSpy focusInSpy(&scene, item, QEvent::FocusIn);
+    EventSpy focusOutSpy(&scene, item, QEvent::FocusOut);
+    EventSpy focusInSpy2(&scene, item2, QEvent::FocusIn);
+    EventSpy focusOutSpy2(&scene, item2, QEvent::FocusOut);
+    QCOMPARE(focusInSpy.count(), 0);
+    QCOMPARE(focusOutSpy.count(), 0);
+    QCOMPARE(focusInSpy2.count(), 0);
+    QCOMPARE(focusOutSpy2.count(), 0);
+
+    item->setFocus();
+    QCOMPARE(focusInSpy.count(), 0);
+    QCOMPARE(focusInSpy2.count(), 1);
+    item->clearFocus();
+    QCOMPARE(focusOutSpy.count(), 0);
+    QCOMPARE(focusOutSpy2.count(), 1);
+
+    // Test two items proxying one item.
+    QGraphicsItem *item3 = scene.addRect(0, 0, 10, 10);
+    item3->setFlag(QGraphicsItem::ItemIsFocusable);
+    item3->setFocusProxy(item2); // item and item3 use item2 as proxy
+
+    QCOMPARE(item->focusProxy(), item2);
+    QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
+    QCOMPARE(item3->focusProxy(), item2);
+    delete item2;
+    QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
+    QCOMPARE(item3->focusProxy(), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsItem::subFocus()
+{
+    // Construct a text item that's not part of a scene (yet)
+    // and has no parent. Setting focus on it will not make
+    // the item gain input focus; that requires a scene. But
+    // it does set subfocus, indicating that the item wishes
+    // to gain focus later.
+    QGraphicsTextItem *text = new QGraphicsTextItem("Hello");
+    text->setTextInteractionFlags(Qt::TextEditorInteraction);
+    QVERIFY(!text->hasFocus());
+    text->setFocus();
+    QVERIFY(!text->hasFocus());
+    QCOMPARE(text->focusItem(), (QGraphicsItem *)text);
+
+    // Add a sibling.
+    QGraphicsTextItem *text2 = new QGraphicsTextItem("Hi");
+    text2->setTextInteractionFlags(Qt::TextEditorInteraction);
+    text2->setPos(30, 30);
+
+    // Add both items to a scene and check that it's text that
+    // got input focus.
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    scene.addItem(text);
+    scene.addItem(text2);
+    QVERIFY(text->hasFocus());
+
+    text->setData(0, "text");
+    text2->setData(0, "text2");
+
+    // Remove text2 and set subfocus on it. Then readd. Reparent it onto the
+    // other item and see that it gains input focus.
+    scene.removeItem(text2);
+    text2->setFocus();
+    scene.addItem(text2);
+    QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
+    text2->setParentItem(text);
+    QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
+    QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
+    QVERIFY(!text->hasFocus());
+    QVERIFY(text2->hasFocus());
+
+    // Remove both items from the scene, restore subfocus and
+    // readd them. Now the subfocus should kick in and give
+    // text2 focus.
+    scene.removeItem(text);
+    QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
+    QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
+    text2->setFocus();
+    QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
+    QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
+    scene.addItem(text);
+
+    // Hiding and showing text should pass focus to text2.
+    QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
+    QVERIFY(text2->hasFocus());
+
+    // Subfocus should repropagate to root when reparenting.
+    QGraphicsRectItem *rect = new QGraphicsRectItem;
+    QGraphicsRectItem *rect2 = new QGraphicsRectItem(rect);
+    QGraphicsRectItem *rect3 = new QGraphicsRectItem(rect2);
+    rect3->setFlag(QGraphicsItem::ItemIsFocusable);
+
+    text->setData(0, "text");
+    text2->setData(0, "text2");
+    rect->setData(0, "rect");
+    rect2->setData(0, "rect2");
+    rect3->setData(0, "rect3");
+
+    rect3->setFocus();
+    QVERIFY(!rect3->hasFocus());
+    QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
+    QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
+    QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
+    rect->setParentItem(text2);
+    QCOMPARE(text->focusItem(), (QGraphicsItem *)rect3);
+    QCOMPARE(text2->focusItem(), (QGraphicsItem *)rect3);
+    QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
+    QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
+    QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
+    QVERIFY(!rect->hasFocus());
+    QVERIFY(!rect2->hasFocus());
+    QVERIFY(rect3->hasFocus());
+
+    delete rect2;
+    QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
+    QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
+    QCOMPARE(rect->focusItem(), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsItem::focusProxyDeletion()
+{
+    QGraphicsRectItem *rect = new QGraphicsRectItem;
+    QGraphicsRectItem *rect2 = new QGraphicsRectItem;
+    rect->setFocusProxy(rect2);
+    QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
+
+    delete rect2;
+    QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
+
+    rect2 = new QGraphicsRectItem;
+    rect->setFocusProxy(rect2);
+    delete rect; // don't crash
+
+    rect = new QGraphicsRectItem;
+    rect->setFocusProxy(rect2);
+    QGraphicsScene *scene = new QGraphicsScene;
+    scene->addItem(rect);
+    scene->addItem(rect2);
+    delete rect2;
+    QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
+
+    rect2 = new QGraphicsRectItem;
+    QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
+    rect->setFocusProxy(rect2);
+    QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
+    scene->addItem(rect2);
+    rect->setFocusProxy(rect2);
+    QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
+    delete rect; // don't crash
+
+    rect = new QGraphicsRectItem;
+    rect2 = new QGraphicsRectItem;
+    rect->setFocusProxy(rect2);
+    QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
+    scene->addItem(rect);
+    scene->addItem(rect2);
+    rect->setFocusProxy(rect2);
+    delete scene; // don't crash
+}
+
+void tst_QGraphicsItem::negativeZStacksBehindParent()
+{
+    QGraphicsRectItem rect;
+    QCOMPARE(rect.zValue(), qreal(0.0));
+    QVERIFY(!(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent));
+    QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
+    rect.setZValue(-1);
+    QCOMPARE(rect.zValue(), qreal(-1.0));
+    QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
+    rect.setZValue(0);
+    rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
+    QVERIFY(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent);
+    QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
+    rect.setZValue(-1);
+    QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
+    rect.setZValue(0);
+    QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
+    rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
+    rect.setZValue(-1);
+    rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, true);
+    QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
+    rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
+    QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
+}
+
+void tst_QGraphicsItem::setGraphicsEffect()
+{
+    // Check that we don't have any effect by default.
+    QGraphicsItem *item = new QGraphicsRectItem(0, 0, 10, 10);
+    QVERIFY(!item->graphicsEffect());
+
+    // SetGet check.
+    QPointer<QGraphicsEffect> blurEffect = new QGraphicsBlurEffect;
+    item->setGraphicsEffect(blurEffect);
+    QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(blurEffect));
+
+    // Ensure the existing effect is deleted when setting a new one.
+    QPointer<QGraphicsEffect> shadowEffect = new QGraphicsDropShadowEffect;
+    item->setGraphicsEffect(shadowEffect);
+    QVERIFY(!blurEffect);
+    QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(shadowEffect));
+    blurEffect = new QGraphicsBlurEffect;
+
+    // Ensure the effect is uninstalled when setting it on a new target.
+    QGraphicsItem *anotherItem = new QGraphicsRectItem(0, 0, 10, 10);
+    anotherItem->setGraphicsEffect(blurEffect);
+    item->setGraphicsEffect(blurEffect);
+    QVERIFY(!anotherItem->graphicsEffect());
+    QVERIFY(!shadowEffect);
+
+    // Ensure the existing effect is deleted when deleting the item.
+    delete item;
+    QVERIFY(!blurEffect);
+    delete anotherItem;
+}
+
+void tst_QGraphicsItem::panel()
+{
+    QGraphicsScene scene;
+
+    QGraphicsRectItem *panel1 = new QGraphicsRectItem;
+    QGraphicsRectItem *panel2 = new QGraphicsRectItem;
+    QGraphicsRectItem *panel3 = new QGraphicsRectItem;
+    QGraphicsRectItem *panel4 = new QGraphicsRectItem;
+    QGraphicsRectItem *notPanel1 = new QGraphicsRectItem;
+    QGraphicsRectItem *notPanel2 = new QGraphicsRectItem;
+    panel1->setFlag(QGraphicsItem::ItemIsPanel);
+    panel2->setFlag(QGraphicsItem::ItemIsPanel);
+    panel3->setFlag(QGraphicsItem::ItemIsPanel);
+    panel4->setFlag(QGraphicsItem::ItemIsPanel);
+    scene.addItem(panel1);
+    scene.addItem(panel2);
+    scene.addItem(panel3);
+    scene.addItem(panel4);
+    scene.addItem(notPanel1);
+    scene.addItem(notPanel2);
+
+    EventSpy spy_activate_panel1(&scene, panel1, QEvent::WindowActivate);
+    EventSpy spy_deactivate_panel1(&scene, panel1, QEvent::WindowDeactivate);
+    EventSpy spy_activate_panel2(&scene, panel2, QEvent::WindowActivate);
+    EventSpy spy_deactivate_panel2(&scene, panel2, QEvent::WindowDeactivate);
+    EventSpy spy_activate_panel3(&scene, panel3, QEvent::WindowActivate);
+    EventSpy spy_deactivate_panel3(&scene, panel3, QEvent::WindowDeactivate);
+    EventSpy spy_activate_panel4(&scene, panel4, QEvent::WindowActivate);
+    EventSpy spy_deactivate_panel4(&scene, panel4, QEvent::WindowDeactivate);
+    EventSpy spy_activate_notPanel1(&scene, notPanel1, QEvent::WindowActivate);
+    EventSpy spy_deactivate_notPanel1(&scene, notPanel1, QEvent::WindowDeactivate);
+    EventSpy spy_activate_notPanel2(&scene, notPanel1, QEvent::WindowActivate);
+    EventSpy spy_deactivate_notPanel2(&scene, notPanel1, QEvent::WindowDeactivate);
+
+    QCOMPARE(spy_activate_panel1.count(), 0);
+    QCOMPARE(spy_deactivate_panel1.count(), 0);
+    QCOMPARE(spy_activate_panel2.count(), 0);
+    QCOMPARE(spy_deactivate_panel2.count(), 0);
+    QCOMPARE(spy_activate_panel3.count(), 0);
+    QCOMPARE(spy_deactivate_panel3.count(), 0);
+    QCOMPARE(spy_activate_panel4.count(), 0);
+    QCOMPARE(spy_deactivate_panel4.count(), 0);
+    QCOMPARE(spy_activate_notPanel1.count(), 0);
+    QCOMPARE(spy_deactivate_notPanel1.count(), 0);
+    QCOMPARE(spy_activate_notPanel2.count(), 0);
+    QCOMPARE(spy_deactivate_notPanel2.count(), 0);
+
+    QVERIFY(!scene.activePanel());
+    QVERIFY(!scene.isActive());
+
+    QEvent activate(QEvent::WindowActivate);
+    QEvent deactivate(QEvent::WindowDeactivate);
+
+    QApplication::sendEvent(&scene, &activate);
+
+    // No previous activation, so the scene is active.
+    QVERIFY(scene.isActive());
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)panel1);
+    QVERIFY(panel1->isActive());
+    QVERIFY(!panel2->isActive());
+    QVERIFY(!panel3->isActive());
+    QVERIFY(!panel4->isActive());
+    QVERIFY(!notPanel1->isActive());
+    QVERIFY(!notPanel2->isActive());
+    QCOMPARE(spy_deactivate_notPanel1.count(), 0);
+    QCOMPARE(spy_deactivate_notPanel2.count(), 0);
+    QCOMPARE(spy_activate_panel1.count(), 1);
+    QCOMPARE(spy_activate_panel2.count(), 0);
+    QCOMPARE(spy_activate_panel3.count(), 0);
+    QCOMPARE(spy_activate_panel4.count(), 0);
+
+    // Switch back to scene.
+    scene.setActivePanel(0);
+    QVERIFY(!scene.activePanel());
+    QVERIFY(!panel1->isActive());
+    QVERIFY(!panel2->isActive());
+    QVERIFY(!panel3->isActive());
+    QVERIFY(!panel4->isActive());
+    QVERIFY(notPanel1->isActive());
+    QVERIFY(notPanel2->isActive());
+    QCOMPARE(spy_activate_notPanel1.count(), 1);
+    QCOMPARE(spy_activate_notPanel2.count(), 1);
+
+    // Deactivate the scene
+    QApplication::sendEvent(&scene, &deactivate);
+    QVERIFY(!scene.activePanel());
+    QVERIFY(!panel1->isActive());
+    QVERIFY(!panel2->isActive());
+    QVERIFY(!panel3->isActive());
+    QVERIFY(!panel4->isActive());
+    QVERIFY(!notPanel1->isActive());
+    QVERIFY(!notPanel2->isActive());
+    QCOMPARE(spy_deactivate_notPanel1.count(), 1);
+    QCOMPARE(spy_deactivate_notPanel2.count(), 1);
+
+    // Reactivate the scene
+    QApplication::sendEvent(&scene, &activate);
+    QVERIFY(!scene.activePanel());
+    QVERIFY(!panel1->isActive());
+    QVERIFY(!panel2->isActive());
+    QVERIFY(!panel3->isActive());
+    QVERIFY(!panel4->isActive());
+    QVERIFY(notPanel1->isActive());
+    QVERIFY(notPanel2->isActive());
+    QCOMPARE(spy_activate_notPanel1.count(), 2);
+    QCOMPARE(spy_activate_notPanel2.count(), 2);
+
+    // Switch to panel1
+    scene.setActivePanel(panel1);
+    QVERIFY(panel1->isActive());
+    QCOMPARE(spy_deactivate_notPanel1.count(), 2);
+    QCOMPARE(spy_deactivate_notPanel2.count(), 2);
+    QCOMPARE(spy_activate_panel1.count(), 2);
+
+    // Deactivate the scene
+    QApplication::sendEvent(&scene, &deactivate);
+    QVERIFY(!panel1->isActive());
+    QCOMPARE(spy_deactivate_panel1.count(), 2);
+
+    // Reactivate the scene
+    QApplication::sendEvent(&scene, &activate);
+    QVERIFY(panel1->isActive());
+    QCOMPARE(spy_activate_panel1.count(), 3);
+
+    // Deactivate the scene
+    QApplication::sendEvent(&scene, &deactivate);
+    QVERIFY(!panel1->isActive());
+    QVERIFY(!scene.activePanel());
+    scene.setActivePanel(0);
+
+    // Reactivate the scene
+    QApplication::sendEvent(&scene, &activate);
+    QVERIFY(!panel1->isActive());
+}
+
+void tst_QGraphicsItem::addPanelToActiveScene()
+{
+    QGraphicsScene scene;
+    QVERIFY(!scene.isActive());
+
+    QGraphicsRectItem *rect = new QGraphicsRectItem;
+    scene.addItem(rect);
+    QVERIFY(!rect->isActive());
+    scene.removeItem(rect);
+
+    QEvent activate(QEvent::WindowActivate);
+    QEvent deactivate(QEvent::WindowDeactivate);
+
+    QApplication::sendEvent(&scene, &activate);
+    QVERIFY(scene.isActive());
+    scene.addItem(rect);
+    QVERIFY(rect->isActive());
+    scene.removeItem(rect);
+
+    rect->setFlag(QGraphicsItem::ItemIsPanel);
+    scene.addItem(rect);
+    QVERIFY(rect->isActive());
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
+
+    QGraphicsRectItem *rect2 = new QGraphicsRectItem;
+    scene.addItem(rect2);
+    QVERIFY(rect->isActive());
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
+}
+
+void tst_QGraphicsItem::activate()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect = scene.addRect(-10, -10, 20, 20);
+    QVERIFY(!rect->isActive());
+
+    QEvent activate(QEvent::WindowActivate);
+    QEvent deactivate(QEvent::WindowDeactivate);
+
+    QApplication::sendEvent(&scene, &activate);
+
+    // Non-panel item (active when scene is active).
+    QVERIFY(rect->isActive());
+
+    QGraphicsRectItem *rect2 = new QGraphicsRectItem;
+    rect2->setFlag(QGraphicsItem::ItemIsPanel);
+    QGraphicsRectItem *rect3 = new QGraphicsRectItem;
+    rect3->setFlag(QGraphicsItem::ItemIsPanel);
+
+    // Test normal activation.
+    QVERIFY(!rect2->isActive());
+    scene.addItem(rect2);
+    QVERIFY(rect2->isActive()); // first panel item is activated
+    scene.addItem(rect3);
+    QVERIFY(!rect3->isActive()); // second panel item is _not_ activated
+    rect3->setActive(true);
+    QVERIFY(rect3->isActive());
+    scene.removeItem(rect3);
+    QVERIFY(!rect3->isActive()); // no panel is active anymore
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
+    scene.addItem(rect3);
+    QVERIFY(rect3->isActive()); // second panel item is activated
+
+    // Test pending activation.
+    scene.removeItem(rect3);
+    rect2->setActive(true);
+    QVERIFY(rect2->isActive()); // first panel item is activated
+    rect3->setActive(true);
+    QVERIFY(!rect3->isActive()); // not active (yet)
+    scene.addItem(rect3);
+    QVERIFY(rect3->isActive()); // now becomes active
+
+    // Test pending deactivation.
+    scene.removeItem(rect3);
+    rect3->setActive(false);
+    scene.addItem(rect3);
+    QVERIFY(!rect3->isActive()); // doesn't become active
+
+    // Child of panel activation.
+    rect3->setActive(true);
+    QGraphicsRectItem *rect4 = new QGraphicsRectItem;
+    rect4->setFlag(QGraphicsItem::ItemIsPanel);
+    QGraphicsRectItem *rect5 = new QGraphicsRectItem(rect4);
+    QGraphicsRectItem *rect6 = new QGraphicsRectItem(rect5);
+    scene.addItem(rect4);
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect3);
+    scene.removeItem(rect4);
+    rect6->setActive(true);
+    scene.addItem(rect4);
+    QVERIFY(rect4->isActive());
+    QVERIFY(rect5->isActive());
+    QVERIFY(rect6->isActive());
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect4);
+    scene.removeItem(rect4); // no active panel
+    rect6->setActive(false);
+    scene.addItem(rect4);
+    QVERIFY(!rect4->isActive());
+    QVERIFY(!rect5->isActive());
+    QVERIFY(!rect6->isActive());
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
+
+    // Controlling auto-activation when the scene changes activation.
+    rect4->setActive(true);
+    QApplication::sendEvent(&scene, &deactivate);
+    QVERIFY(!scene.isActive());
+    QVERIFY(!rect4->isActive());
+    rect4->setActive(false);
+    QApplication::sendEvent(&scene, &activate);
+    QVERIFY(scene.isActive());
+    QVERIFY(!scene.activePanel());
+    QVERIFY(!rect4->isActive());
+}
+
+void tst_QGraphicsItem::setActivePanelOnInactiveScene()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *item = scene.addRect(QRectF());
+    QGraphicsRectItem *panel = scene.addRect(QRectF());
+    panel->setFlag(QGraphicsItem::ItemIsPanel);
+
+    EventSpy itemActivateSpy(&scene, item, QEvent::WindowActivate);
+    EventSpy itemDeactivateSpy(&scene, item, QEvent::WindowDeactivate);
+    EventSpy panelActivateSpy(&scene, panel, QEvent::WindowActivate);
+    EventSpy panelDeactivateSpy(&scene, panel, QEvent::WindowDeactivate);
+    EventSpy sceneActivationChangeSpy(&scene, QEvent::ActivationChange);
+
+    scene.setActivePanel(panel);
+    QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
+    QCOMPARE(itemActivateSpy.count(), 0);
+    QCOMPARE(itemDeactivateSpy.count(), 0);
+    QCOMPARE(panelActivateSpy.count(), 0);
+    QCOMPARE(panelDeactivateSpy.count(), 0);
+    QCOMPARE(sceneActivationChangeSpy.count(), 0);
+}
+
+void tst_QGraphicsItem::activationOnShowHide()
+{
+    QGraphicsScene scene;
+    QEvent activate(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &activate);
+
+    QGraphicsRectItem *rootPanel = scene.addRect(QRectF());
+    rootPanel->setFlag(QGraphicsItem::ItemIsPanel);
+    rootPanel->setActive(true);
+
+    QGraphicsRectItem *subPanel = new QGraphicsRectItem;
+    subPanel->setFlag(QGraphicsItem::ItemIsPanel);
+
+    // Reparenting onto an active panel auto-activates the child panel.
+    subPanel->setParentItem(rootPanel);
+    QVERIFY(subPanel->isActive());
+    QVERIFY(!rootPanel->isActive());
+
+    // Hiding an active child panel will reactivate the parent panel.
+    subPanel->hide();
+    QVERIFY(rootPanel->isActive());
+
+    // Showing a child panel will auto-activate it.
+    subPanel->show();
+    QVERIFY(subPanel->isActive());
+    QVERIFY(!rootPanel->isActive());
+
+    // Adding an unrelated panel doesn't affect activation.
+    QGraphicsRectItem *otherPanel = new QGraphicsRectItem;
+    otherPanel->setFlag(QGraphicsItem::ItemIsPanel);
+    scene.addItem(otherPanel);
+    QVERIFY(subPanel->isActive());
+
+    // Showing an unrelated panel doesn't affect activation.
+    otherPanel->hide();
+    otherPanel->show();
+    QVERIFY(subPanel->isActive());
+
+    // Add a non-panel item.
+    QGraphicsRectItem *otherItem = new QGraphicsRectItem;
+    scene.addItem(otherItem);
+    otherItem->setActive(true);
+    QVERIFY(otherItem->isActive());
+
+    // Reparent a panel onto an active non-panel item.
+    subPanel->setParentItem(otherItem);
+    QVERIFY(subPanel->isActive());
+
+    // Showing a child panel of a non-panel item will activate it.
+    subPanel->hide();
+    QVERIFY(!subPanel->isActive());
+    QVERIFY(otherItem->isActive());
+    subPanel->show();
+    QVERIFY(subPanel->isActive());
+
+    // Hiding a toplevel active panel will pass activation back
+    // to the non-panel items.
+    rootPanel->setActive(true);
+    rootPanel->hide();
+    QVERIFY(!rootPanel->isActive());
+    QVERIFY(otherItem->isActive());
+}
+
+class MoveWhileDying : public QGraphicsRectItem
+{
+public:
+    MoveWhileDying(QGraphicsItem *parent = 0)
+        : QGraphicsRectItem(parent)
+    { }
+    ~MoveWhileDying()
+    {
+        foreach (QGraphicsItem *c, childItems()) {
+            foreach (QGraphicsItem *cc, c->childItems()) {
+                cc->moveBy(10, 10);
+            }
+            c->moveBy(10, 10);
+        }
+        if (QGraphicsItem *p = parentItem()) { p->moveBy(10, 10); }
+    }
+};
+
+void tst_QGraphicsItem::moveWhileDeleting()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect = new QGraphicsRectItem;
+    MoveWhileDying *silly = new MoveWhileDying(rect);
+    QGraphicsRectItem *child = new QGraphicsRectItem(silly);
+    scene.addItem(rect);
+    delete rect; // don't crash!
+
+    rect = new QGraphicsRectItem;
+    silly = new MoveWhileDying(rect);
+    child = new QGraphicsRectItem(silly);
+
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(125);
+
+    delete rect;
+
+    rect = new QGraphicsRectItem;
+    rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    silly = new MoveWhileDying(rect);
+    child = new QGraphicsRectItem(silly);
+
+    QTest::qWait(125);
+
+    delete rect;
+
+    rect = new MoveWhileDying;
+    rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+    child = new QGraphicsRectItem(rect);
+    silly = new MoveWhileDying(child);
+
+    QTest::qWait(125);
+
+    delete rect;
+}
+
+class MyRectItem : public QGraphicsWidget
+{
+    Q_OBJECT
+public:
+    MyRectItem(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
+    {
+
+    }
+
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+    {
+        painter->setBrush(brush);
+        painter->drawRect(boundingRect());
+    }
+    void move()
+    {
+        setPos(-100,-100);
+        topLevel->collidingItems(Qt::IntersectsItemBoundingRect);
+    }
+public:
+    QGraphicsItem *topLevel;
+    QBrush brush;
+};
+
+
+void tst_QGraphicsItem::ensureDirtySceneTransform()
+{
+    QGraphicsScene scene;
+
+    MyRectItem *topLevel = new MyRectItem;
+    topLevel->setGeometry(0, 0, 100, 100);
+    topLevel->setPos(-50, -50);
+    topLevel->brush = QBrush(QColor(Qt::black));
+    scene.addItem(topLevel);
+
+    MyRectItem *parent = new MyRectItem;
+    parent->topLevel = topLevel;
+    parent->setGeometry(0, 0, 100, 100);
+    parent->setPos(0, 0);
+    parent->brush = QBrush(QColor(Qt::magenta));
+    parent->setObjectName("parent");
+    scene.addItem(parent);
+
+    MyRectItem *child = new MyRectItem(parent);
+    child->setGeometry(0, 0, 80, 80);
+    child->setPos(10, 10);
+    child->setObjectName("child");
+    child->brush = QBrush(QColor(Qt::blue));
+
+    MyRectItem *child2 = new MyRectItem(parent);
+    child2->setGeometry(0, 0, 80, 80);
+    child2->setPos(15, 15);
+    child2->setObjectName("child2");
+    child2->brush = QBrush(QColor(Qt::green));
+
+    MyRectItem *child3 = new MyRectItem(parent);
+    child3->setGeometry(0, 0, 80, 80);
+    child3->setPos(20, 20);
+    child3->setObjectName("child3");
+    child3->brush = QBrush(QColor(Qt::gray));
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+
+    //We move the parent
+    parent->move();
+    QApplication::processEvents();
+
+    //We check if all items moved
+    QCOMPARE(child->pos(), QPointF(10, 10));
+    QCOMPARE(child2->pos(), QPointF(15, 15));
+    QCOMPARE(child3->pos(), QPointF(20, 20));
+
+    QCOMPARE(child->sceneBoundingRect(), QRectF(-90, -90, 80, 80));
+    QCOMPARE(child2->sceneBoundingRect(), QRectF(-85, -85, 80, 80));
+    QCOMPARE(child3->sceneBoundingRect(), QRectF(-80, -80, 80, 80));
+
+    QCOMPARE(child->sceneTransform(), QTransform::fromTranslate(-90, -90));
+    QCOMPARE(child2->sceneTransform(), QTransform::fromTranslate(-85, -85));
+    QCOMPARE(child3->sceneTransform(), QTransform::fromTranslate(-80, -80));
+}
+
+void tst_QGraphicsItem::focusScope()
+{
+    // ItemIsFocusScope is an internal feature (for now).
+    QGraphicsScene scene;
+
+    QGraphicsRectItem *scope3 = new QGraphicsRectItem;
+    scope3->setData(0, "scope3");
+    scope3->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
+    scope3->setFocus();
+    QVERIFY(!scope3->focusScopeItem());
+    QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
+
+    QGraphicsRectItem *scope2 = new QGraphicsRectItem;
+    scope2->setData(0, "scope2");
+    scope2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
+    scope2->setFocus();
+    QVERIFY(!scope2->focusScopeItem());
+    scope3->setParentItem(scope2);
+    QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
+    QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope2);
+
+    QGraphicsRectItem *scope1 = new QGraphicsRectItem;
+    scope1->setData(0, "scope1");
+    scope1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
+    scope1->setFocus();
+    QVERIFY(!scope1->focusScopeItem());
+    scope2->setParentItem(scope1);
+
+    QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope1);
+    QCOMPARE(scope2->focusItem(), (QGraphicsItem *)0);
+    QCOMPARE(scope3->focusItem(), (QGraphicsItem *)0);
+    QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
+    QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
+    QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
+
+    scene.addItem(scope1);
+
+    QEvent windowActivate(QEvent::WindowActivate);
+    qApp->sendEvent(&scene, &windowActivate);
+    scene.setFocus();
+
+    QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
+    QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
+    QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
+    QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
+    QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
+    QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
+
+    QVERIFY(scope3->hasFocus());
+
+    scope3->hide();
+    QVERIFY(scope2->hasFocus());
+    scope2->hide();
+    QVERIFY(scope1->hasFocus());
+    scope2->show();
+    QVERIFY(scope2->hasFocus());
+    scope3->show();
+    QVERIFY(scope3->hasFocus());
+    scope1->hide();
+    QVERIFY(!scope3->hasFocus());
+    scope1->show();
+    QVERIFY(scope3->hasFocus());
+    scope3->clearFocus();
+    QVERIFY(scope2->hasFocus());
+    scope2->clearFocus();
+    QVERIFY(scope1->hasFocus());
+    scope2->hide();
+    scope2->show();
+    QVERIFY(!scope2->hasFocus());
+    QVERIFY(scope3->hasFocus());
+
+    QGraphicsRectItem *rect4 = new QGraphicsRectItem;
+    rect4->setData(0, "rect4");
+    rect4->setParentItem(scope3);
+
+    QGraphicsRectItem *rect5 = new QGraphicsRectItem;
+    rect5->setData(0, "rect5");
+    rect5->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
+    rect5->setFocus();
+    rect5->setParentItem(rect4);
+    QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)rect5);
+    QVERIFY(!rect5->hasFocus());
+
+    rect4->setParentItem(0);
+    QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
+    QVERIFY(scope3->hasFocus());
+
+    QGraphicsRectItem *rectA = new QGraphicsRectItem;
+    QGraphicsRectItem *scopeA = new QGraphicsRectItem(rectA);
+    scopeA->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
+    scopeA->setFocus();
+    QGraphicsRectItem *scopeB = new QGraphicsRectItem(scopeA);
+    scopeB->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
+    scopeB->setFocus();
+
+    scene.addItem(rectA);
+    QVERIFY(!rect5->hasFocus());
+    QVERIFY(!scopeB->hasFocus());
+
+    scopeA->setFocus();
+    QVERIFY(scopeB->hasFocus());
+    QCOMPARE(scopeB->focusItem(), (QGraphicsItem *)scopeB);
+}
+
+void tst_QGraphicsItem::stackBefore()
+{
+    QGraphicsRectItem parent;
+    QGraphicsRectItem *child1 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
+    QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
+    QGraphicsRectItem *child3 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
+    QGraphicsRectItem *child4 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
+    child1->setData(0, "child1");
+    child2->setData(0, "child2");
+    child3->setData(0, "child3");
+    child4->setData(0, "child4");
+
+    // Remove and append
+    child2->setParentItem(0);
+    child2->setParentItem(&parent);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
+
+    // Move child2 before child1
+    child2->stackBefore(child1);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child2->stackBefore(child2);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child1->setZValue(1);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
+    child1->stackBefore(child2); // no effect
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
+    child1->setZValue(0);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child4->stackBefore(child1);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child4 << child1 << child3));
+    child4->setZValue(1);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child3->stackBefore(child1);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child1 << child4));
+    child4->setZValue(0);
+    QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child4 << child3 << child1));
+
+    // Make them all toplevels
+    child1->setParentItem(0);
+    child2->setParentItem(0);
+    child3->setParentItem(0);
+    child4->setParentItem(0);
+
+    QGraphicsScene scene;
+    scene.addItem(child1);
+    scene.addItem(child2);
+    scene.addItem(child3);
+    scene.addItem(child4);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder),
+             (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
+
+    // Remove and append
+    scene.removeItem(child2);
+    scene.addItem(child2);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
+
+    // Move child2 before child1
+    child2->stackBefore(child1);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child2->stackBefore(child2);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child1->setZValue(1);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
+    child1->stackBefore(child2); // no effect
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
+    child1->setZValue(0);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child4->stackBefore(child1);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child4 << child1 << child3));
+    child4->setZValue(1);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
+    child3->stackBefore(child1);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child1 << child4));
+    child4->setZValue(0);
+    QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child4 << child3 << child1));
+}
+
+void tst_QGraphicsItem::QTBUG_4233_updateCachedWithSceneRect()
+{
+    EventTester *tester = new EventTester;
+    tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+
+    QGraphicsScene scene;
+    scene.addItem(tester);
+    scene.setSceneRect(-100, -100, 200, 200); // contains the tester item
+
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
+
+    QTRY_COMPARE(tester->repaints, 1);
+
+    scene.update(); // triggers "updateAll" optimization
+    qApp->processEvents();
+    qApp->processEvents(); // in 4.6 only one processEvents is necessary
+
+    QCOMPARE(tester->repaints, 1);
+
+    scene.update(); // triggers "updateAll" optimization
+    tester->update();
+    qApp->processEvents();
+    qApp->processEvents(); // in 4.6 only one processEvents is necessary
+
+    QCOMPARE(tester->repaints, 2);
+}
+
+void tst_QGraphicsItem::sceneModality()
+{
+    // 1) Test mouse events (delivery/propagation/redirection)
+    // 2) Test hover events (incl. leave on block, enter on unblock)
+    // 3) Test cursor stuff (incl. unset on block, set on unblock)
+    // 4) Test clickfocus
+    // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
+    // 6) ### modality for non-panels is unsupported for now
+    QGraphicsScene scene;
+
+    QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
+    bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
+    bottomItem->setBrush(Qt::yellow);
+
+    QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
+    leftParent->setFlag(QGraphicsItem::ItemIsPanel);
+    leftParent->setBrush(Qt::blue);
+
+    QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
+    leftChild->setFlag(QGraphicsItem::ItemIsPanel);
+    leftChild->setBrush(Qt::green);
+    leftChild->setParentItem(leftParent);
+
+    QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
+    rightParent->setFlag(QGraphicsItem::ItemIsPanel);
+    rightParent->setBrush(Qt::red);
+    QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
+    rightChild->setFlag(QGraphicsItem::ItemIsPanel);
+    rightChild->setBrush(Qt::gray);
+    rightChild->setParentItem(rightParent);
+
+    leftParent->setPos(-75, 0);
+    rightParent->setPos(75, 0);
+
+    bottomItem->setData(0, "bottomItem");
+    leftParent->setData(0, "leftParent");
+    leftChild->setData(0, "leftChild");
+    rightParent->setData(0, "rightParent");
+    rightChild->setData(0, "rightChild");
+
+    scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
+
+    EventSpy2 leftParentSpy(&scene, leftParent);
+    EventSpy2 leftChildSpy(&scene, leftChild);
+    EventSpy2 rightParentSpy(&scene, rightParent);
+    EventSpy2 rightChildSpy(&scene, rightChild);
+    EventSpy2 bottomItemSpy(&scene, bottomItem);
+
+    // Scene modality, also test multiple scene modal items
+    leftChild->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // not a panel
+
+    // Click inside left child
+    sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+
+    // Click on left parent, event goes to modal child
+    sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+
+    // Click on all other items and outside the items
+    sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
+    sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
+    sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
+    sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+
+    leftChildSpy.counts.clear();
+    rightChildSpy.counts.clear();
+    leftParentSpy.counts.clear();
+    rightParentSpy.counts.clear();
+    bottomItemSpy.counts.clear();
+
+    leftChild->setPanelModality(QGraphicsItem::NonModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
+
+    // Left parent enters scene modality.
+    leftParent->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
+
+    // Click inside left child.
+    sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // panel stops propagation
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+
+   // Click on left parent.
+    sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
+
+    // Click on all other items and outside the items
+    sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 2);
+    sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 3);
+    sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 4);
+    sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 5);
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
+
+    leftChildSpy.counts.clear();
+    rightChildSpy.counts.clear();
+    leftParentSpy.counts.clear();
+    rightParentSpy.counts.clear();
+    bottomItemSpy.counts.clear();
+
+    // Now both left parent and child are scene modal. Left parent is blocked.
+    leftChild->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
+
+    // Click inside left child
+    sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+
+    // Click on left parent, event goes to modal child
+    sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+
+    // Click on all other items and outside the items
+    sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
+    sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
+    sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
+    sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
+    QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
+    QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+    QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
+
+    leftChildSpy.counts.clear();
+    rightChildSpy.counts.clear();
+    leftParentSpy.counts.clear();
+    rightParentSpy.counts.clear();
+    bottomItemSpy.counts.clear();
+
+    // Right child enters scene modality, only left child is blocked.
+    rightChild->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
+}
+
+void tst_QGraphicsItem::panelModality()
+{
+    // 1) Test mouse events (delivery/propagation/redirection)
+    // 2) Test hover events (incl. leave on block, enter on unblock)
+    // 3) Test cursor stuff (incl. unset on block, set on unblock)
+    // 4) Test clickfocus
+    // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
+    // 6) ### modality for non-panels is unsupported for now
+    QGraphicsScene scene;
+
+    QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
+    bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
+    bottomItem->setBrush(Qt::yellow);
+
+    QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
+    leftParent->setFlag(QGraphicsItem::ItemIsPanel);
+    leftParent->setBrush(Qt::blue);
+
+    QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
+    leftChild->setFlag(QGraphicsItem::ItemIsPanel);
+    leftChild->setBrush(Qt::green);
+    leftChild->setParentItem(leftParent);
+
+    QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
+    rightParent->setFlag(QGraphicsItem::ItemIsPanel);
+    rightParent->setBrush(Qt::red);
+    QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
+    rightChild->setFlag(QGraphicsItem::ItemIsPanel);
+    rightChild->setBrush(Qt::gray);
+    rightChild->setParentItem(rightParent);
+
+    leftParent->setPos(-75, 0);
+    rightParent->setPos(75, 0);
+
+    bottomItem->setData(0, "bottomItem");
+    leftParent->setData(0, "leftParent");
+    leftChild->setData(0, "leftChild");
+    rightParent->setData(0, "rightParent");
+    rightChild->setData(0, "rightChild");
+
+    scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
+
+    EventSpy2 leftParentSpy(&scene, leftParent);
+    EventSpy2 leftChildSpy(&scene, leftChild);
+    EventSpy2 rightParentSpy(&scene, rightParent);
+    EventSpy2 rightChildSpy(&scene, rightChild);
+    EventSpy2 bottomItemSpy(&scene, bottomItem);
+
+    // Left Child enters panel modality, only left parent is blocked.
+    leftChild->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
+
+    leftChild->setPanelModality(QGraphicsItem::NonModal);
+    leftChildSpy.counts.clear();
+    rightChildSpy.counts.clear();
+    leftParentSpy.counts.clear();
+    rightParentSpy.counts.clear();
+    bottomItemSpy.counts.clear();
+
+    // Left parent enter panel modality, nothing is blocked.
+    leftParent->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
+
+    // Left child enters panel modality, left parent is blocked again.
+    leftChild->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
+
+    leftChildSpy.counts.clear();
+    rightChildSpy.counts.clear();
+    leftParentSpy.counts.clear();
+    rightParentSpy.counts.clear();
+    bottomItemSpy.counts.clear();
+
+    leftChild->setPanelModality(QGraphicsItem::NonModal);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
+    leftParent->setPanelModality(QGraphicsItem::NonModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
+
+    leftChildSpy.counts.clear();
+    rightChildSpy.counts.clear();
+    leftParentSpy.counts.clear();
+    rightParentSpy.counts.clear();
+    bottomItemSpy.counts.clear();
+
+    // Left and right child enter panel modality, both parents are blocked.
+    rightChild->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    leftChild->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+}
+
+void tst_QGraphicsItem::mixedModality()
+{
+    // 1) Test mouse events (delivery/propagation/redirection)
+    // 2) Test hover events (incl. leave on block, enter on unblock)
+    // 3) Test cursor stuff (incl. unset on block, set on unblock)
+    // 4) Test clickfocus
+    // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
+    // 6) ### modality for non-panels is unsupported for now
+    QGraphicsScene scene;
+
+    QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
+    bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
+    bottomItem->setBrush(Qt::yellow);
+
+    QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
+    leftParent->setFlag(QGraphicsItem::ItemIsPanel);
+    leftParent->setBrush(Qt::blue);
+
+    QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
+    leftChild->setFlag(QGraphicsItem::ItemIsPanel);
+    leftChild->setBrush(Qt::green);
+    leftChild->setParentItem(leftParent);
+
+    QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
+    rightParent->setFlag(QGraphicsItem::ItemIsPanel);
+    rightParent->setBrush(Qt::red);
+    QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
+    rightChild->setFlag(QGraphicsItem::ItemIsPanel);
+    rightChild->setBrush(Qt::gray);
+    rightChild->setParentItem(rightParent);
+
+    leftParent->setPos(-75, 0);
+    rightParent->setPos(75, 0);
+
+    bottomItem->setData(0, "bottomItem");
+    leftParent->setData(0, "leftParent");
+    leftChild->setData(0, "leftChild");
+    rightParent->setData(0, "rightParent");
+    rightChild->setData(0, "rightChild");
+
+    scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
+
+    EventSpy2 leftParentSpy(&scene, leftParent);
+    EventSpy2 leftChildSpy(&scene, leftChild);
+    EventSpy2 rightParentSpy(&scene, rightParent);
+    EventSpy2 rightChildSpy(&scene, rightChild);
+    EventSpy2 bottomItemSpy(&scene, bottomItem);
+
+    // Left Child enters panel modality, only left parent is blocked.
+    leftChild->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
+
+    // Left parent enters scene modality, which blocks everything except the child.
+    leftParent->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
+
+    // Right child enters panel modality (changes nothing).
+    rightChild->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
+
+    // Left parent leaves modality. Right child is unblocked.
+    leftParent->setPanelModality(QGraphicsItem::NonModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
+
+    // Right child "upgrades" its modality to scene modal. Left child is blocked.
+    // Right parent is unaffected.
+    rightChild->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
+
+    // "downgrade" right child back to panel modal, left child is unblocked
+    rightChild->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
+    QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
+}
+
+void tst_QGraphicsItem::modality_hover()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
+    rect1->setFlag(QGraphicsItem::ItemIsPanel);
+    rect1->setAcceptHoverEvents(true);
+    rect1->setData(0, "rect1");
+
+    QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
+    rect2->setParentItem(rect1);
+    rect2->setFlag(QGraphicsItem::ItemIsPanel);
+    rect2->setAcceptHoverEvents(true);
+    rect2->setPos(50, 50);
+    rect2->setPanelModality(QGraphicsItem::SceneModal);
+    rect2->setData(0, "rect2");
+
+    EventSpy2 rect1Spy(&scene, rect1);
+    EventSpy2 rect2Spy(&scene, rect2);
+
+    sendMouseMove(&scene, QPointF(-25, -25));
+
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
+
+    sendMouseMove(&scene, QPointF(75, 75));
+
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
+
+    sendMouseMove(&scene, QPointF(-25, -25));
+
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
+
+    rect2->setPanelModality(QGraphicsItem::NonModal);
+
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
+
+    sendMouseMove(&scene, QPointF(75, 75));
+
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
+
+    rect2->setPanelModality(QGraphicsItem::SceneModal);
+
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
+    // changing modality causes a spurious GraphicsSceneHoveMove, even though the mouse didn't
+    // actually move
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
+
+    sendMouseMove(&scene, QPointF(-25, -25));
+
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
+
+    rect2->setPanelModality(QGraphicsItem::PanelModal);
+
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
+
+    rect2->setPanelModality(QGraphicsItem::NonModal);
+
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
+    QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
+    QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
+}
+
+void tst_QGraphicsItem::modality_mouseGrabber()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
+    rect1->setFlag(QGraphicsItem::ItemIsPanel);
+    rect1->setFlag(QGraphicsItem::ItemIsMovable);
+    rect1->setData(0, "rect1");
+
+    QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
+    rect2->setParentItem(rect1);
+    rect2->setFlag(QGraphicsItem::ItemIsPanel);
+    rect2->setFlag(QGraphicsItem::ItemIsMovable);
+    rect2->setPos(50, 50);
+    rect2->setData(0, "rect2");
+
+    EventSpy2 rect1Spy(&scene, rect1);
+    EventSpy2 rect2Spy(&scene, rect2);
+
+    {
+        // pressing mouse on rect1 starts implicit grab
+        sendMousePress(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
+
+        // grab lost when rect1 is modally shadowed
+        rect2->setPanelModality(QGraphicsItem::SceneModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // releasing goes nowhere
+        sendMouseRelease(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
+        sendMouseClick(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+
+        // pressing mouse on rect1 starts implicit grab
+        sendMousePress(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
+
+        // grab lost to rect2 when rect1 is modally shadowed
+        rect2->setPanelModality(QGraphicsItem::SceneModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // rect1 does *not* re-grab when rect2 is no longer modal
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // release goes nowhere
+        sendMouseRelease(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+    }
+    {
+        // repeat the test using PanelModal
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+        rect1Spy.counts.clear();
+        rect2Spy.counts.clear();
+
+        // pressing mouse on rect1 starts implicit grab
+        sendMousePress(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
+
+        // grab lost when rect1 is modally shadowed
+        rect2->setPanelModality(QGraphicsItem::PanelModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // releasing goes nowhere
+        sendMouseRelease(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
+        sendMouseClick(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+
+        // pressing mouse on rect1 starts implicit grab
+        sendMousePress(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
+
+        // grab lost to rect2 when rect1 is modally shadowed
+        rect2->setPanelModality(QGraphicsItem::PanelModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // rect1 does *not* re-grab when rect2 is no longer modal
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        // release goes nowhere
+        sendMouseRelease(&scene, QPoint(-25, -25));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+    }
+
+    {
+        // repeat the PanelModal tests, but this time the mouse events will be on a non-modal item,
+        // meaning normal grabbing should work
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+        rect1Spy.counts.clear();
+        rect2Spy.counts.clear();
+
+        QGraphicsRectItem *rect3 = scene.addRect(-50, -50, 100, 100);
+        rect3->setFlag(QGraphicsItem::ItemIsPanel);
+        rect3->setFlag(QGraphicsItem::ItemIsMovable);
+        rect3->setPos(150, 50);
+        rect3->setData(0, "rect3");
+
+        EventSpy2 rect3Spy(&scene, rect3);
+
+        // pressing mouse on rect3 starts implicit grab
+        sendMousePress(&scene, QPoint(150, 50));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMousePress], 1);
+        QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
+
+        // grab is *not* lost when rect1 is modally shadowed by rect2
+        rect2->setPanelModality(QGraphicsItem::PanelModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
+
+        // releasing goes to rect3
+        sendMouseRelease(&scene, QPoint(150, 50));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
+        QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
+        QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+
+        // pressing mouse on rect3 starts implicit grab
+        sendMousePress(&scene, QPoint(150, 50));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
+
+        // grab is not lost
+        rect2->setPanelModality(QGraphicsItem::PanelModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
+
+        // grab stays on rect3
+        rect2->setPanelModality(QGraphicsItem::NonModal);
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
+
+        // release goes to rect3
+        sendMouseRelease(&scene, QPoint(150, 50));
+        QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
+        QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
+        QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
+        QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 2);
+        QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
+    }
+}
+
+void tst_QGraphicsItem::modality_clickFocus()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
+    rect1->setFlag(QGraphicsItem::ItemIsPanel);
+    rect1->setFlag(QGraphicsItem::ItemIsFocusable);
+    rect1->setData(0, "rect1");
+
+    QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
+    rect2->setParentItem(rect1);
+    rect2->setFlag(QGraphicsItem::ItemIsPanel);
+    rect2->setFlag(QGraphicsItem::ItemIsFocusable);
+    rect2->setPos(50, 50);
+    rect2->setData(0, "rect2");
+
+    QEvent windowActivateEvent(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &windowActivateEvent);
+
+    EventSpy2 rect1Spy(&scene, rect1);
+    EventSpy2 rect2Spy(&scene, rect2);
+
+    // activate rect1, it should not get focus
+    rect1->setActive(true);
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
+
+    // focus stays unset when rect2 becomes modal
+    rect2->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
+
+    // clicking on rect1 should not set it's focus item
+    sendMouseClick(&scene, QPointF(-25, -25));
+    QCOMPARE(rect1->focusItem(), (QGraphicsItem *) 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
+
+    // clicking on rect2 gives it focus
+    rect2->setActive(true);
+    sendMouseClick(&scene, QPointF(75, 75));
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect2);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
+
+    // clicking on rect1 does *not* give it focus
+    rect1->setActive(true);
+    sendMouseClick(&scene, QPointF(-25, -25));
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
+
+    // focus doesn't change when leaving modality either
+    rect2->setPanelModality(QGraphicsItem::NonModal);
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
+
+    // click on rect1, it should get focus now
+    sendMouseClick(&scene, QPointF(-25, -25));
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
+}
+
+void tst_QGraphicsItem::modality_keyEvents()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
+    rect1->setFlag(QGraphicsItem::ItemIsPanel);
+    rect1->setFlag(QGraphicsItem::ItemIsFocusable);
+    rect1->setData(0, "rect1");
+
+    QGraphicsRectItem *rect1child = scene.addRect(-10, -10, 20, 20);
+    rect1child->setParentItem(rect1);
+    rect1child->setFlag(QGraphicsItem::ItemIsFocusable);
+    rect1child->setData(0, "rect1child1");
+
+    QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
+    rect2->setParentItem(rect1);
+    rect2->setFlag(QGraphicsItem::ItemIsPanel);
+    rect2->setFlag(QGraphicsItem::ItemIsFocusable);
+    rect2->setPos(50, 50);
+    rect2->setData(0, "rect2");
+
+    QGraphicsRectItem *rect2child = scene.addRect(-10, -10, 20, 20);
+    rect2child->setParentItem(rect2);
+    rect2child->setFlag(QGraphicsItem::ItemIsFocusable);
+    rect2child->setData(0, "rect2child1");
+
+    QEvent windowActivateEvent(QEvent::WindowActivate);
+    QApplication::sendEvent(&scene, &windowActivateEvent);
+
+    EventSpy2 rect1Spy(&scene, rect1);
+    EventSpy2 rect1childSpy(&scene, rect1child);
+    EventSpy2 rect2Spy(&scene, rect2);
+    EventSpy2 rect2childSpy(&scene, rect2child);
+
+    // activate rect1 and give it rect1child focus
+    rect1->setActive(true);
+    rect1child->setFocus();
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
+
+    // focus stays on rect1child when rect2 becomes modal
+    rect2->setPanelModality(QGraphicsItem::SceneModal);
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
+
+    // but key events to rect1child should be neither delivered nor propagated
+    sendKeyClick(&scene, Qt::Key_A);
+    sendKeyClick(&scene, Qt::Key_S);
+    sendKeyClick(&scene, Qt::Key_D);
+    sendKeyClick(&scene, Qt::Key_F);
+    QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
+    QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
+
+    // change to panel modality, rect1child1 keeps focus
+    rect2->setPanelModality(QGraphicsItem::PanelModal);
+    QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
+
+    // still no key events
+    sendKeyClick(&scene, Qt::Key_J);
+    sendKeyClick(&scene, Qt::Key_K);
+    sendKeyClick(&scene, Qt::Key_L);
+    sendKeyClick(&scene, Qt::Key_Semicolon);
+    QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
+    QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
+    QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
+}
+
+void tst_QGraphicsItem::itemIsInFront()
+{
+    QGraphicsScene scene;
+    QGraphicsRectItem *rect1 = new QGraphicsRectItem;
+    rect1->setData(0, "rect1");
+    scene.addItem(rect1);
+
+    QGraphicsRectItem *rect1child1 = new QGraphicsRectItem(rect1);
+    rect1child1->setZValue(1);
+    rect1child1->setData(0, "rect1child1");
+
+    QGraphicsRectItem *rect1child2 = new QGraphicsRectItem(rect1);
+    rect1child2->setParentItem(rect1);
+    rect1child2->setData(0, "rect1child2");
+
+    QGraphicsRectItem *rect1child1_1 = new QGraphicsRectItem(rect1child1);
+    rect1child1_1->setData(0, "rect1child1_1");
+
+    QGraphicsRectItem *rect1child1_2 = new QGraphicsRectItem(rect1child1);
+    rect1child1_2->setFlag(QGraphicsItem::ItemStacksBehindParent);
+    rect1child1_2->setData(0, "rect1child1_2");
+
+    QGraphicsRectItem *rect2 = new QGraphicsRectItem;
+    rect2->setData(0, "rect2");
+    scene.addItem(rect2);
+
+    QGraphicsRectItem *rect2child1 = new QGraphicsRectItem(rect2);
+    rect2child1->setData(0, "rect2child1");
+
+    QCOMPARE(qt_closestItemFirst(rect1, rect1), false);
+    QCOMPARE(qt_closestItemFirst(rect1, rect2), false);
+    QCOMPARE(qt_closestItemFirst(rect1child1, rect2child1), false);
+    QCOMPARE(qt_closestItemFirst(rect1child1, rect1child2), true);
+    QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child2), true);
+    QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child1), true);
+    QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child2), true);
+    QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child1), false);
+    QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1), true);
+    QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2), false);
+    QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2child1), false);
+}
+
+QTEST_MAIN(tst_QGraphicsItem)
+#include "tst_qgraphicsitem.moc"