tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,3509 @@
+/****************************************************************************
+**
+** 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 <QtGui>
+#include "../../shared/util.h"
+#include <private/qlayoutengine_p.h>    // qSmartMin functions...
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+#include <QMacStyle>
+#endif
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#endif
+
+static void sendMouseMove(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::NoButton)
+{
+    QMouseEvent event(QEvent::MouseMove, point, widget->mapToGlobal(point), button, button, 0);
+    QApplication::sendEvent(widget, &event);
+}
+
+
+#ifndef QT_NO_STYLE_CLEANLOOKS
+/*
+    Notes:
+
+    1) The proxy and the widget geometries are linked.
+       proxy resize => widget resize => stop (no livelock)
+       widget resize => proxy resize => stop (no livelock)
+
+    2) As far as possible, the properties are linked.
+       proxy enable => widget enable => stop
+       widget disabled => proxy disabled => stop
+
+    3) Windowed state is linked
+       Windowed proxy state => windowed widget state => stop
+       Windowed widget state => windowed proxy state => stop
+*/
+
+class EventSpy : public QObject
+{
+public:
+    EventSpy(QObject *receiver)
+    {
+        receiver->installEventFilter(this);
+    }
+
+    QMap<QEvent::Type, int> counts;
+
+protected:
+    bool eventFilter(QObject *, QEvent *event)
+    {
+        ++counts[event->type()];
+        return false;
+    }
+};
+
+class tst_QGraphicsProxyWidget : public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+
+private slots:
+    void qgraphicsproxywidget_data();
+    void qgraphicsproxywidget();
+    void paint();
+    void paint_2();
+    void setWidget_data();
+    void setWidget();
+    void eventFilter_data();
+    void eventFilter();
+    void focusInEvent_data();
+    void focusInEvent();
+    void focusInEventNoWidget();
+    void focusNextPrevChild_data();
+    void focusNextPrevChild();
+    void focusOutEvent_data();
+    void focusOutEvent();
+    void hoverEnterLeaveEvent_data();
+    void hoverEnterLeaveEvent();
+    void hoverMoveEvent_data();
+    void hoverMoveEvent();
+    void keyPressEvent_data();
+    void keyPressEvent();
+    void keyReleaseEvent_data();
+    void keyReleaseEvent();
+    void mouseDoubleClickEvent_data();
+    void mouseDoubleClickEvent();
+    void mousePressReleaseEvent_data();
+    void mousePressReleaseEvent();
+    void resizeEvent_data();
+    void resizeEvent();
+    void paintEvent();
+    void wheelEvent();
+    void sizeHint_data();
+    void sizeHint();
+    void sizePolicy();
+    void minimumSize();
+    void maximumSize();
+    void scrollUpdate();
+    void setWidget_simple();
+    void setWidget_ownership();
+    void resize_simple_data();
+    void resize_simple();
+    void symmetricMove();
+    void symmetricResize();
+    void symmetricEnabled();
+    void symmetricVisible();
+    void tabFocus_simpleWidget();
+    void tabFocus_simpleTwoWidgets();
+    void tabFocus_complexWidget();
+    void tabFocus_complexTwoWidgets();
+    void setFocus_simpleWidget();
+    void setFocus_simpleTwoWidgets();
+    void setFocus_complexTwoWidgets();
+    void popup_basic();
+    void popup_subwidget();
+    void changingCursor_basic();
+    void tooltip_basic();
+    void childPos_data();
+    void childPos();
+    void autoShow();
+    void windowOpacity();
+    void stylePropagation();
+    void palettePropagation();
+    void fontPropagation();
+    void dontCrashWhenDie();
+    void createProxyForChildWidget();
+    void actionsContextMenu();
+    void actionsContextMenu_data();
+    void deleteProxyForChildWidget();
+    void bypassGraphicsProxyWidget_data();
+    void bypassGraphicsProxyWidget();
+    void dragDrop();
+    void windowFlags_data();
+    void windowFlags();
+    void comboboxWindowFlags();
+    void updateAndDelete();
+    void inputMethod();
+    void clickFocus();
+};
+
+// Subclass that exposes the protected functions.
+class SubQGraphicsProxyWidget : public QGraphicsProxyWidget
+{
+
+public:
+    SubQGraphicsProxyWidget(QGraphicsItem *parent = 0) : QGraphicsProxyWidget(parent),
+    paintCount(0), keyPress(0), focusOut(0)
+        {}
+
+    bool call_eventFilter(QObject* object, QEvent* event)
+        { return SubQGraphicsProxyWidget::eventFilter(object, event); }
+
+    void call_focusInEvent(QFocusEvent* event)
+        { return SubQGraphicsProxyWidget::focusInEvent(event); }
+
+    bool call_focusNextPrevChild(bool next)
+        { return SubQGraphicsProxyWidget::focusNextPrevChild(next); }
+
+    void call_focusOutEvent(QFocusEvent* event)
+        { return SubQGraphicsProxyWidget::focusOutEvent(event); }
+
+    void call_hideEvent(QHideEvent* event)
+        { return SubQGraphicsProxyWidget::hideEvent(event); }
+
+    void call_hoverEnterEvent(QGraphicsSceneHoverEvent* event)
+        { return SubQGraphicsProxyWidget::hoverEnterEvent(event); }
+
+    void call_hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
+        { return SubQGraphicsProxyWidget::hoverLeaveEvent(event); }
+
+    void call_hoverMoveEvent(QGraphicsSceneHoverEvent* event)
+        { return SubQGraphicsProxyWidget::hoverMoveEvent(event); }
+
+    void call_keyPressEvent(QKeyEvent* event)
+        { return SubQGraphicsProxyWidget::keyPressEvent(event); }
+
+    void call_keyReleaseEvent(QKeyEvent* event)
+        { return SubQGraphicsProxyWidget::keyReleaseEvent(event); }
+
+    void call_mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
+        { return SubQGraphicsProxyWidget::mouseDoubleClickEvent(event); }
+
+    void call_mouseMoveEvent(QGraphicsSceneMouseEvent* event)
+        { return SubQGraphicsProxyWidget::mouseMoveEvent(event); }
+
+    void call_mousePressEvent(QGraphicsSceneMouseEvent* event)
+        { return SubQGraphicsProxyWidget::mousePressEvent(event); }
+
+    void call_mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
+        { return SubQGraphicsProxyWidget::mouseReleaseEvent(event); }
+
+    void call_resizeEvent(QGraphicsSceneResizeEvent* event)
+        { return SubQGraphicsProxyWidget::resizeEvent(event); }
+
+    QSizeF call_sizeHint(Qt::SizeHint which, QSizeF const& constraint = QSizeF()) const
+        { return SubQGraphicsProxyWidget::sizeHint(which, constraint); }
+
+    void call_showEvent(QShowEvent* event)
+        { return SubQGraphicsProxyWidget::showEvent(event); }
+
+    void paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)    {
+        paintCount++;
+        QGraphicsProxyWidget::paint(painter, option, widget);
+    }
+
+    void focusOutEvent(QFocusEvent *event)
+    {
+        focusOut++;
+        QGraphicsProxyWidget::focusOutEvent(event);
+    }
+
+    bool eventFilter(QObject *object, QEvent *event) {
+        if (event->type() == QEvent::KeyPress && object == widget())
+            keyPress++;
+        return QGraphicsProxyWidget::eventFilter(object, event);
+    }
+    int paintCount;
+    int keyPress;
+    int focusOut;
+};
+
+class WheelWidget : public QWidget
+{
+public:
+    WheelWidget() : wheelEventCalled(false) { setFocusPolicy(Qt::WheelFocus); }
+
+    virtual void wheelEvent(QWheelEvent *event) { event->accept(); wheelEventCalled = true; }
+
+    bool wheelEventCalled;
+};
+
+// This will be called before the first test function is executed.
+// It is only called once.
+void tst_QGraphicsProxyWidget::initTestCase()
+{
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+    qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+// This will be called after the last test function is executed.
+// It is only called once.
+void tst_QGraphicsProxyWidget::cleanupTestCase()
+{
+}
+
+// This will be called before each test function is executed.
+void tst_QGraphicsProxyWidget::init()
+{
+}
+
+// This will be called after every test function.
+void tst_QGraphicsProxyWidget::cleanup()
+{
+}
+
+void tst_QGraphicsProxyWidget::qgraphicsproxywidget_data()
+{
+}
+
+void tst_QGraphicsProxyWidget::qgraphicsproxywidget()
+{
+    SubQGraphicsProxyWidget proxy;
+    proxy.paint(0, 0, 0);
+    proxy.setWidget(0);
+    QVERIFY(proxy.type() == QGraphicsProxyWidget::Type);
+    QVERIFY(!proxy.widget());
+    QEvent event(QEvent::None);
+    proxy.call_eventFilter(0, &event);
+    QFocusEvent focusEvent(QEvent::FocusIn);
+    focusEvent.ignore();
+    proxy.call_focusInEvent(&focusEvent);
+    QCOMPARE(focusEvent.isAccepted(), false);
+    QCOMPARE(proxy.call_focusNextPrevChild(false), false);
+    QCOMPARE(proxy.call_focusNextPrevChild(true), false);
+    proxy.call_focusOutEvent(&focusEvent);
+    QHideEvent hideEvent;
+    proxy.call_hideEvent(&hideEvent);
+    QGraphicsSceneHoverEvent hoverEvent;
+    proxy.call_hoverEnterEvent(&hoverEvent);
+    proxy.call_hoverLeaveEvent(&hoverEvent);
+    proxy.call_hoverMoveEvent(&hoverEvent);
+    QKeyEvent keyEvent(QEvent::KeyPress, 0, Qt::NoModifier);
+    proxy.call_keyPressEvent(&keyEvent);
+    proxy.call_keyReleaseEvent(&keyEvent);
+    QGraphicsSceneMouseEvent mouseEvent;
+    proxy.call_mouseDoubleClickEvent(&mouseEvent);
+    proxy.call_mouseMoveEvent(&mouseEvent);
+    proxy.call_mousePressEvent(&mouseEvent);
+    proxy.call_mouseReleaseEvent(&mouseEvent);
+    QGraphicsSceneResizeEvent resizeEvent;
+    proxy.call_resizeEvent(&resizeEvent);
+    QShowEvent showEvent;
+    proxy.call_showEvent(&showEvent);
+    proxy.call_sizeHint(Qt::PreferredSize, QSizeF());
+}
+
+// public void paint(QPainter* painter, QStyleOptionGraphicsItem const* option, QWidget* widget)
+void tst_QGraphicsProxyWidget::paint()
+{
+    SubQGraphicsProxyWidget proxy;
+    proxy.paint(0, 0, 0);
+}
+
+class MyProxyWidget : public QGraphicsProxyWidget
+{
+public:
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+    {
+        // Make sure QGraphicsProxyWidget::paint does not modify the render hints set on the painter.
+        painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform
+                                | QPainter::NonCosmeticDefaultPen | QPainter::TextAntialiasing);
+        const QPainter::RenderHints oldRenderHints = painter->renderHints();
+        QGraphicsProxyWidget::paint(painter, option, widget);
+        QCOMPARE(painter->renderHints(), oldRenderHints);
+    }
+};
+
+void tst_QGraphicsProxyWidget::paint_2()
+{
+    MyProxyWidget *proxyWidget = new MyProxyWidget;
+    proxyWidget->setWidget(new QLineEdit);
+
+    QGraphicsScene scene;
+    scene.addItem(proxyWidget);
+    scene.setSceneRect(scene.itemsBoundingRect());
+
+    // Trigger repaint.
+    QPixmap pixmap(scene.sceneRect().toRect().size());
+    QPainter painter(&pixmap);
+    scene.render(&painter);
+}
+
+void tst_QGraphicsProxyWidget::setWidget_data()
+{
+    QTest::addColumn<bool>("widgetExists");
+    QTest::addColumn<bool>("insertWidget");
+    QTest::addColumn<bool>("hasParent");
+    QTest::addColumn<bool>("proxyHasParent");
+
+    QTest::newRow("setWidget(0)") << false << false << false << false;
+    QTest::newRow("setWidget(widget)") << false << true << false << false;
+    QTest::newRow("setWidget(widgetWParent)") << false << true << true << false;
+    QTest::newRow("setWidget(1), setWidget(0)") << true << false << false << false;
+    QTest::newRow("setWidget(1), setWidget(widget)") << true << true << false << false;
+    QTest::newRow("setWidget(1), setWidget(widgetWParent)") << true << true << true << false;
+    QTest::newRow("p setWidget(0)") << false << false << false << true;
+    QTest::newRow("p setWidget(widget)") << false << true << false << true;
+    QTest::newRow("p setWidget(widgetWParent)") << false << true << true << true;
+    QTest::newRow("p setWidget(1), setWidget(0)") << true << false << false << true;
+    QTest::newRow("p setWidget(1), setWidget(widget)") << true << true << false << true;
+    QTest::newRow("p setWidget(1), setWidget(widgetWParent)") << true << true << true << true;
+}
+
+// public void setWidget(QWidget* widget)
+void tst_QGraphicsProxyWidget::setWidget()
+{
+    QFETCH(bool, widgetExists);
+    QFETCH(bool, insertWidget);
+    QFETCH(bool, hasParent);
+    QFETCH(bool, proxyHasParent);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QPointer<SubQGraphicsProxyWidget> proxy = new SubQGraphicsProxyWidget;
+    SubQGraphicsProxyWidget parentProxy;
+    scene.addItem(proxy);
+    scene.addItem(&parentProxy);
+    if (proxyHasParent)
+        proxy->setParent(&parentProxy);
+    QPointer<QWidget> existingSubWidget = new QWidget;
+    proxy->setVisible(false);
+    proxy->setEnabled(false);
+
+    if (widgetExists) {
+        existingSubWidget->setAttribute(Qt::WA_QuitOnClose, true);
+        proxy->setWidget(existingSubWidget);
+    }
+
+    QWidget *widget = new QWidget;
+#ifndef QT_NO_CURSOR
+    widget->setCursor(Qt::IBeamCursor);
+#endif
+    widget->setPalette(QPalette(Qt::magenta));
+    widget->setLayoutDirection(Qt::RightToLeft);
+    QCleanlooksStyle cleanlooksStyle;
+    widget->setStyle(&cleanlooksStyle);
+    widget->setFont(QFont("Times"));
+    widget->setVisible(true);
+    QApplication::setActiveWindow(widget);
+    widget->activateWindow();
+    widget->setEnabled(true);
+    widget->resize(325, 241);
+    widget->setMinimumSize(100, 200);
+    widget->setMaximumSize(1000, 2000);
+    widget->setFocusPolicy(Qt::TabFocus);
+    widget->setContentsMargins(10, 29, 19, 81);
+    widget->setFocus(Qt::TabFocusReason);
+    widget->setAcceptDrops(true);
+    QTRY_VERIFY(widget->hasFocus());
+    QVERIFY(widget->isActiveWindow());
+
+    QWidget parentWidget;
+    if (hasParent)
+        widget->setParent(&parentWidget);
+
+    QWidget *subWidget = insertWidget ? widget : 0;
+    bool shouldBeInsertable = !hasParent && subWidget;
+    if (shouldBeInsertable)
+        subWidget->setAttribute(Qt::WA_QuitOnClose, true);
+
+    proxy->setWidget(subWidget);
+
+    if (shouldBeInsertable) {
+        QCOMPARE(proxy->widget(), subWidget);
+        QVERIFY(subWidget->testAttribute(Qt::WA_DontShowOnScreen));
+        QVERIFY(!subWidget->testAttribute(Qt::WA_QuitOnClose));
+        QCOMPARE(proxy->acceptHoverEvents(), true);
+#ifndef QT_NO_CURSOR
+        QVERIFY(proxy->hasCursor());
+
+        // These should match
+        QCOMPARE(proxy->cursor().shape(), widget->cursor().shape());
+#endif
+        //###QCOMPARE(proxy->palette(), widget->palette());
+        QCOMPARE(proxy->layoutDirection(), widget->layoutDirection());
+        QCOMPARE(proxy->style(), widget->style());
+        QCOMPARE(proxy->isVisible(), widget->isVisible());
+        QCOMPARE(proxy->isEnabled(), widget->isEnabled());
+        QVERIFY(proxy->flags() & QGraphicsItem::ItemIsFocusable);
+        QCOMPARE(proxy->effectiveSizeHint(Qt::MinimumSize).toSize(),
+            qSmartMinSize(widget));
+        QCOMPARE(proxy->minimumSize().toSize(),
+                 qSmartMinSize(widget) );
+        QCOMPARE(proxy->maximumSize().toSize(), QSize(1000, 2000));
+        QCOMPARE(proxy->effectiveSizeHint(Qt::PreferredSize).toSize(),
+                qSmartMinSize(widget));
+        QCOMPARE(proxy->size().toSize(), widget->size());
+        QCOMPARE(proxy->rect().toRect(), widget->rect());
+        QCOMPARE(proxy->focusPolicy(), Qt::WheelFocus);
+        QVERIFY(proxy->acceptDrops());
+        QCOMPARE(proxy->acceptsHoverEvents(), true); // to get widget enter events
+        int left, top, right, bottom;
+        widget->getContentsMargins(&left, &top, &right, &bottom);
+        qreal rleft, rtop, rright, rbottom;
+        proxy->getContentsMargins(&rleft, &rtop, &rright, &rbottom);
+        QCOMPARE((qreal)left, rleft);
+        QCOMPARE((qreal)top, rtop);
+        QCOMPARE((qreal)right, rright);
+        QCOMPARE((qreal)bottom, rbottom);
+    } else {
+        // proxy shouldn't mess with the widget if it can't insert it.
+        QCOMPARE(proxy->widget(), (QWidget*)0);
+        QCOMPARE(proxy->acceptHoverEvents(), false);
+        if (subWidget) {
+            QVERIFY(!subWidget->testAttribute(Qt::WA_DontShowOnScreen));
+            QVERIFY(subWidget->testAttribute(Qt::WA_QuitOnClose));
+            // reset
+            subWidget->setAttribute(Qt::WA_QuitOnClose, false);
+        }
+    }
+
+    if (widgetExists) {
+        QCOMPARE(existingSubWidget->parent(), static_cast<QObject*>(0));
+        QVERIFY(!existingSubWidget->testAttribute(Qt::WA_DontShowOnScreen));
+        QVERIFY(!existingSubWidget->testAttribute(Qt::WA_QuitOnClose));
+    }
+
+    if (hasParent)
+        widget->setParent(0);
+
+    delete widget;
+    if (shouldBeInsertable)
+        QVERIFY(!proxy);
+    delete existingSubWidget;
+    if (!shouldBeInsertable) {
+        QVERIFY(proxy);
+        delete proxy;
+    }
+    QVERIFY(!proxy);
+}
+
+Q_DECLARE_METATYPE(QEvent::Type)
+void tst_QGraphicsProxyWidget::eventFilter_data()
+{
+    QTest::addColumn<QEvent::Type>("eventType");
+    QTest::addColumn<bool>("fromObject"); // big grin evil
+    QTest::newRow("none") << QEvent::None << false;
+    for (int i = 0; i < 2; ++i) {
+        bool fromObject = (i == 0);
+        QTest::newRow(QString("resize %1").arg(fromObject).toLatin1()) << QEvent::Resize << fromObject;
+        QTest::newRow(QString("move %1").arg(fromObject).toLatin1()) << QEvent::Move << fromObject;
+        QTest::newRow(QString("hide %1").arg(fromObject).toLatin1()) << QEvent::Hide << fromObject;
+        QTest::newRow(QString("show %1").arg(fromObject).toLatin1()) << QEvent::Show << fromObject;
+        QTest::newRow(QString("enabled %1").arg(fromObject).toLatin1()) << QEvent::EnabledChange << fromObject;
+        QTest::newRow(QString("focusIn %1").arg(fromObject).toLatin1()) << QEvent::FocusIn << fromObject;
+        QTest::newRow(QString("focusOut %1").arg(fromObject).toLatin1()) << QEvent::FocusOut << fromObject;
+        QTest::newRow(QString("keyPress %1").arg(fromObject).toLatin1()) << QEvent::KeyPress << fromObject;
+    }
+}
+
+// protected bool eventFilter(QObject* object, QEvent* event)
+void tst_QGraphicsProxyWidget::eventFilter()
+{
+    QFETCH(QEvent::Type, eventType);
+    QFETCH(bool, fromObject);
+
+    QGraphicsScene scene;
+    QEvent windowActivate(QEvent::WindowActivate);
+    qApp->sendEvent(&scene, &windowActivate);
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    scene.addItem(proxy);
+
+    QWidget *widget = new QWidget(0, Qt::FramelessWindowHint);
+    widget->setFocusPolicy(Qt::TabFocus);
+    widget->resize(10, 10);
+    widget->show();
+    proxy->setWidget(widget);
+    proxy->show();
+
+    // mirror whatever is happening to the widget
+    // don't get in a loop
+    switch (eventType) {
+    case QEvent::None: {
+        QEvent event(QEvent::None);
+        proxy->call_eventFilter(widget, &event);
+        break;
+                       }
+    case QEvent::Resize: {
+        QSize oldSize = widget->size();
+        QSize newSize = QSize(100, 100);
+        if (fromObject) {
+            widget->resize(newSize);
+        } else {
+            proxy->resize(newSize);
+        }
+        QCOMPARE(proxy->size().toSize(), newSize);
+        QCOMPARE(widget->size(), newSize);
+        break;
+                         }
+    case QEvent::Move: {
+        QPoint oldPoint = widget->pos();
+        QPoint newPoint = QPoint(100, 100);
+        if (fromObject) {
+            widget->move(newPoint);
+        } else {
+            proxy->setPos(newPoint);
+        }
+        QCOMPARE(proxy->pos().toPoint(), newPoint);
+        QCOMPARE(widget->pos(), newPoint);
+        break;
+                         }
+    case QEvent::Hide: {
+        // A hide event can only come from a widget
+        if (fromObject) {
+            widget->setFocus(Qt::TabFocusReason);
+            widget->hide();
+        } else {
+            QHideEvent event;
+            proxy->call_eventFilter(widget, &event);
+        }
+        QCOMPARE(proxy->isVisible(), false);
+        break;
+                         }
+    case QEvent::Show: {
+        // A show event can either come from a widget or somewhere else
+        widget->hide();
+        if (fromObject) {
+            widget->show();
+        } else {
+            QShowEvent event;
+            proxy->call_eventFilter(widget, &event);
+        }
+        QCOMPARE(proxy->isVisible(), true);
+        break;
+                         }
+    case QEvent::EnabledChange: {
+        widget->setEnabled(false);
+        proxy->setEnabled(false);
+        if (fromObject) {
+            widget->setEnabled(true);
+            QCOMPARE(proxy->isEnabled(), true);
+            widget->setEnabled(false);
+            QCOMPARE(proxy->isEnabled(), false);
+        } else {
+            QEvent event(QEvent::EnabledChange);
+            proxy->call_eventFilter(widget, &event);
+            // match the widget not the event
+            QCOMPARE(proxy->isEnabled(), false);
+        }
+        break;
+                         }
+    case QEvent::FocusIn: {
+        if (fromObject) {
+            widget->setFocus(Qt::TabFocusReason);
+            QVERIFY(proxy->hasFocus());
+        }
+        break;
+                         }
+    case QEvent::FocusOut: {
+        widget->setFocus(Qt::TabFocusReason);
+        QVERIFY(proxy->hasFocus());
+        QVERIFY(widget->hasFocus());
+        if (fromObject) {
+            widget->clearFocus();
+            QVERIFY(!proxy->hasFocus());
+        }
+        break;
+                         }
+    case QEvent::KeyPress: {
+        if (fromObject) {
+            QTest::keyPress(widget, Qt::Key_A, Qt::NoModifier);
+        } else {
+            QKeyEvent event(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
+            proxy->call_eventFilter(widget, &event);
+        }
+        QCOMPARE(proxy->keyPress, 1);
+        break;
+                         }
+    default:
+        break;
+    }
+}
+
+void tst_QGraphicsProxyWidget::focusInEvent_data()
+{
+    QTest::addColumn<bool>("widgetHasFocus");
+    QTest::addColumn<bool>("widgetCanHaveFocus");
+    QTest::newRow("no focus, can't get") << false << false;
+    QTest::newRow("no focus, can get") << false << true;
+    QTest::newRow("has focus, can't get") << true << false;
+    QTest::newRow("has focus, can get") << true << true;
+    // ### add test for widget having a focusNextPrevChild
+}
+
+// protected void focusInEvent(QFocusEvent* event)
+void tst_QGraphicsProxyWidget::focusInEvent()
+{
+    // ### This test is just plain old broken
+    QFETCH(bool, widgetHasFocus);
+    QFETCH(bool, widgetCanHaveFocus);
+
+    QGraphicsScene scene;
+    QEvent windowActivate(QEvent::WindowActivate);
+    qApp->sendEvent(&scene, &windowActivate);
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    proxy->setEnabled(true);
+    scene.addItem(proxy);
+    proxy->setVisible(true);
+
+    QWidget *widget = new QWidget;
+    widget->resize(100, 100);
+    if (widgetCanHaveFocus)
+        widget->setFocusPolicy(Qt::WheelFocus);
+    widget->show();
+
+    if (widgetHasFocus)
+        widget->setFocus(Qt::TabFocusReason);
+
+    proxy->setWidget(widget);
+    proxy->setFlag(QGraphicsItem::ItemIsFocusable, true); // <- shouldn't need to do this
+
+    // ### This test is just plain old broken - sending a focus in event
+    // does not cause items to gain input focus. The widget has focus
+    // because the proxy has focus, not because it got this event.
+
+    QFocusEvent event(QEvent::FocusIn, Qt::TabFocusReason);
+    event.ignore();
+    proxy->call_focusInEvent(&event);
+    QTRY_COMPARE(widget->hasFocus(), widgetCanHaveFocus);
+}
+
+void tst_QGraphicsProxyWidget::focusInEventNoWidget()
+{
+    QGraphicsView view;
+    QGraphicsScene scene(&view);
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    proxy->setEnabled(true);
+    scene.addItem(proxy);
+    proxy->setVisible(true);
+    view.show();
+
+    proxy->setFlag(QGraphicsItem::ItemIsFocusable, true); // <- shouldn't need to do this
+    QFocusEvent event(QEvent::FocusIn, Qt::TabFocusReason);
+    event.ignore();
+    //should not crash
+    proxy->call_focusInEvent(&event);
+}
+
+void tst_QGraphicsProxyWidget::focusNextPrevChild_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::addColumn<bool>("hasScene");
+    QTest::addColumn<bool>("next");
+    QTest::addColumn<bool>("focusNextPrevChild");
+
+    for (int i = 0; i < 2; ++i) {
+        for (int j = 0; j < 2; ++j) {
+            for (int k = 0; k < 2; ++k) {
+                bool next = (i == 0);
+                bool hasWidget = (j == 0);
+                bool hasScene = (k == 0);
+                bool result = hasScene && hasWidget;
+                QString name = QString("Forward: %1, hasWidget: %2, hasScene: %3, result: %4").arg(next).arg(hasWidget).arg(hasScene).arg(result);
+                QTest::newRow(name.toLatin1()) << hasWidget << hasScene << next << result;
+            }
+        }
+    }
+}
+
+// protected bool focusNextPrevChild(bool next)
+void tst_QGraphicsProxyWidget::focusNextPrevChild()
+{
+    QFETCH(bool, next);
+    QFETCH(bool, focusNextPrevChild);
+    QFETCH(bool, hasWidget);
+    QFETCH(bool, hasScene);
+
+    // If a widget has its own focusNextPrevChild we need to respect it
+    // otherwise respect the scene
+    // Respect the widget over the scene!
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+
+    QLabel *widget = new QLabel;
+    // I can't believe designer adds this much junk!
+    widget->setText("<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\"> p, li { white-space: pre-wrap; } </style></head><body style=\" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;\"> <p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><a href=\"http://www.slashdot.org\"><span style=\" text-decoration: underline; color:#0000ff;\">old</span></a> foo <a href=\"http://www.reddit.org\"><span style=\" text-decoration: underline; color:#0000ff;\">new</span></a></p></body></html>");
+    widget->setTextInteractionFlags(Qt::TextBrowserInteraction);
+
+    if (hasWidget)
+        proxy->setWidget(widget);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+    QApplication::setActiveWindow(&view);
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+    QTRY_COMPARE(QApplication::activeWindow(), &view);
+    if (hasScene) {
+        scene.addItem(proxy);
+        proxy->show();
+
+        // widget should take precedence over scene so make scene.focusNextPrevChild return false
+        // so we know that a true can only come from the widget
+        if (!(hasWidget && hasScene)) {
+            QGraphicsTextItem *item = new QGraphicsTextItem("Foo");
+            item->setTextInteractionFlags(Qt::TextBrowserInteraction);
+            scene.addItem(item);
+            item->setPos(50, 40);
+        }
+        scene.setFocusItem(proxy);
+        QVERIFY(proxy->hasFocus());
+    }
+
+    QCOMPARE(proxy->call_focusNextPrevChild(next), focusNextPrevChild);
+
+    if (!hasScene)
+        delete proxy;
+}
+
+void tst_QGraphicsProxyWidget::focusOutEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::addColumn<bool>("call");
+    QTest::newRow("no widget, focus to other widget") << false << false;
+    QTest::newRow("no widget, focusOutCalled") << false << true;
+    QTest::newRow("widget, focus to other widget") << true << false;
+    QTest::newRow("widget, focusOutCalled") << true << true;
+}
+
+// protected void focusOutEvent(QFocusEvent* event)
+void tst_QGraphicsProxyWidget::focusOutEvent()
+{
+    QFETCH(bool, hasWidget);
+    QFETCH(bool, call);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    scene.addItem(proxy);
+    view.show();
+    QApplication::setActiveWindow(&view);
+    view.activateWindow();
+    view.setFocus();
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+    QTRY_VERIFY(view.isVisible());
+    QTRY_COMPARE(QApplication::activeWindow(), &view);
+
+    QWidget *widget = new QWidget;
+    widget->setFocusPolicy(Qt::WheelFocus);
+    if (hasWidget)
+        proxy->setWidget(widget);
+    proxy->show();
+    proxy->setFocus();
+    QVERIFY(proxy->hasFocus());
+    QEXPECT_FAIL("widget, focus to other widget", "Widget should have focus but doesn't", Continue);
+    QEXPECT_FAIL("widget, focusOutCalled", "Widget should have focus but doesn't", Continue);
+    QCOMPARE(widget->hasFocus(), hasWidget);
+
+    if (!call) {
+        QWidget *other = new QLineEdit(&view);
+        other->show();
+        QApplication::processEvents();
+        QTRY_VERIFY(other->isVisible());
+        other->setFocus();
+        QTRY_VERIFY(other->hasFocus());
+        qApp->processEvents();
+        QTRY_COMPARE(proxy->hasFocus(), false);
+        QVERIFY(proxy->focusOut);
+        QCOMPARE(widget->hasFocus(), false);
+    } else {
+        {
+            /*
+            ### Test doesn't make sense
+            QFocusEvent focusEvent(QEvent::FocusOut);
+            proxy->call_focusOutEvent(&focusEvent);
+            QCOMPARE(focusEvent.isAccepted(), hasWidget);
+            qApp->processEvents();
+            QCOMPARE(proxy->paintCount, hasWidget ? 1 : 0);
+            */
+        }
+        {
+            /*
+            ### Test doesn't make sense
+            proxy->setFlag(QGraphicsItem::ItemIsFocusable, false);
+            QFocusEvent focusEvent(QEvent::FocusOut);
+            proxy->call_focusOutEvent(&focusEvent);
+            QCOMPARE(focusEvent.isAccepted(), hasWidget);
+            qApp->processEvents();
+            QCOMPARE(proxy->paintCount, 0);
+            */
+        }
+    }
+}
+
+class EventLogger : public QWidget
+{
+public:
+    EventLogger() : QWidget(), enterCount(0), leaveCount(0), moveCount(0),
+        hoverEnter(0), hoverLeave(0), hoverMove(0)
+    {
+        installEventFilter(this);
+    }
+
+    void enterEvent(QEvent *event)
+    {
+        enterCount++;
+        QWidget::enterEvent(event);
+    }
+
+    void leaveEvent(QEvent *event )
+    {
+        leaveCount++;
+        QWidget::leaveEvent(event);
+    }
+
+    void mouseMoveEvent(QMouseEvent *event)
+    {
+        event->setAccepted(true);
+        moveCount++;
+        QWidget::mouseMoveEvent(event);
+    }
+
+    int enterCount;
+    int leaveCount;
+    int moveCount;
+
+    int hoverEnter;
+    int hoverLeave;
+    int hoverMove;
+protected:
+    bool eventFilter(QObject *object, QEvent *event)
+    {
+        switch (event->type()) {
+        case QEvent::HoverEnter:
+             hoverEnter++;
+             break;
+        case QEvent::HoverLeave:
+             hoverLeave++;
+             break;
+        case QEvent::HoverMove:
+             hoverMove++;
+             break;
+        default:
+             break;
+        }
+        return QWidget::eventFilter(object, event);
+    }
+};
+
+void tst_QGraphicsProxyWidget::hoverEnterLeaveEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::addColumn<bool>("hoverEnabled");
+    QTest::newRow("widget, no hover") << true << false;
+    QTest::newRow("no widget, no hover") << false << false;
+    QTest::newRow("widget, hover") << true << true;
+    QTest::newRow("no widget, hover") << false << true;
+}
+
+// protected void hoverEnterEvent(QGraphicsSceneHoverEvent* event)
+void tst_QGraphicsProxyWidget::hoverEnterLeaveEvent()
+{
+    QFETCH(bool, hasWidget);
+    QFETCH(bool, hoverEnabled);
+
+#if defined(Q_OS_WINCE) && (!defined(GWES_ICONCURS) || defined(QT_NO_CURSOR))
+    QSKIP("hover events not supported on this platform", SkipAll);
+#endif
+
+    // proxy should translate this into events that the widget would expect
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    //do not let the window manager move the window while we are moving the mouse on it
+    view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    EventLogger *widget = new EventLogger;
+    widget->resize(50, 50);
+    widget->setAttribute(Qt::WA_Hover, hoverEnabled);
+    widget->setMouseTracking(true);
+    view.resize(100, 100);
+    if (hasWidget)
+        proxy->setWidget(widget);
+    proxy->setPos(50, 0);
+    scene.addItem(proxy);
+    QTest::qWait(30);
+    QTest::mouseMove(&view, QPoint(10, 10));
+    QTest::qWait(30);
+
+    // in
+    QTest::mouseMove(&view, QPoint(50, 50));
+    QTest::qWait(25);
+    QTRY_COMPARE(widget->testAttribute(Qt::WA_UnderMouse), hasWidget ? true : false);
+    // ### this attribute isn't supported
+    QCOMPARE(widget->enterCount, hasWidget ? 1 : 0);
+    QCOMPARE(widget->hoverEnter, (hasWidget && hoverEnabled) ? 1 : 0);
+    // does not work on all platforms
+    //QCOMPARE(widget->moveCount, 0);
+
+    // out
+    QTest::mouseMove(&view, QPoint(10, 10));
+    QTest::qWait(25);
+    // QTRY_COMPARE(widget->testAttribute(Qt::WA_UnderMouse), false);
+    // ### this attribute isn't supported
+    QCOMPARE(widget->leaveCount, hasWidget ? 1 : 0);
+    QCOMPARE(widget->hoverLeave, (hasWidget && hoverEnabled) ? 1 : 0);
+    // does not work on all platforms
+    //QCOMPARE(widget->moveCount, 0);
+
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::hoverMoveEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::addColumn<bool>("hoverEnabled");
+    QTest::addColumn<bool>("mouseTracking");
+    QTest::addColumn<bool>("mouseDown");
+    for (int i = 0; i < 2; ++i) {
+        for (int j = 0; j < 2; ++j) {
+            for (int k = 0; k < 2; ++k) {
+                for (int l = 0; l < 2; ++l) {
+                    bool hasWidget = (i == 0);
+                    bool hoverEnabled = (j == 0);
+                    bool mouseTracking = (k == 0);
+                    bool mouseDown = (l == 0);
+                    QString name = QString("hasWidget:%1, hover:%2, mouseTracking:%3, mouseDown: %4").arg(hasWidget).arg(hoverEnabled).arg(mouseTracking).arg(mouseDown);
+                    QTest::newRow(name.toLatin1()) << hasWidget << hoverEnabled << mouseTracking << mouseDown;
+                }
+            }
+        }
+    }
+}
+
+// protected void hoverMoveEvent(QGraphicsSceneHoverEvent* event)
+void tst_QGraphicsProxyWidget::hoverMoveEvent()
+{
+    QFETCH(bool, hasWidget);
+    QFETCH(bool, hoverEnabled);
+    QFETCH(bool, mouseTracking);
+    QFETCH(bool, mouseDown);
+
+    QSKIP("Ambiguous test...", SkipAll);
+
+    // proxy should translate the move events to what the widget would expect
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    proxy->setFlag(QGraphicsItem::ItemIsFocusable, true); // ### remove me!!!
+    EventLogger *widget = new EventLogger;
+    widget->resize(50, 50);
+    widget->setAttribute(Qt::WA_Hover, hoverEnabled);
+    if (mouseTracking)
+        widget->setMouseTracking(true);
+    view.resize(100, 100);
+    if (hasWidget)
+        proxy->setWidget(widget);
+    proxy->setPos(50, 0);
+    scene.addItem(proxy);
+
+    // in
+    QTest::mouseMove(&view, QPoint(50, 50));
+    QTest::qWait(12);
+
+    if (mouseDown)
+        QTest::mousePress(view.viewport(), Qt::LeftButton);
+
+    // move a little bit
+    QTest::mouseMove(&view, QPoint(60, 60));
+    QTest::qWait(12);
+    QTRY_COMPARE(widget->hoverEnter, (hasWidget && hoverEnabled) ? 1 : 0);
+    QCOMPARE(widget->moveCount, (hasWidget && mouseTracking) || (hasWidget && mouseDown) ? 1 : 0);
+
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::keyPressEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::newRow("widget") << true;
+    QTest::newRow("no widget") << false;
+}
+
+// protected void keyPressEvent(QKeyEvent* event)
+void tst_QGraphicsProxyWidget::keyPressEvent()
+{
+    QFETCH(bool, hasWidget);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+    view.viewport()->setFocus();
+    QApplication::setActiveWindow(&view);
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+    QTRY_COMPARE(QApplication::activeWindow(), &view);
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    proxy->setFlag(QGraphicsItem::ItemIsFocusable, true); // ### remove me!!!
+
+    QLineEdit *widget = new QLineEdit;
+    widget->resize(50, 50);
+    view.resize(100, 100);
+    if (hasWidget) {
+        proxy->setWidget(widget);
+        proxy->show();
+    }
+    proxy->setPos(50, 0);
+    scene.addItem(proxy);
+    proxy->setFocus();
+
+    QTest::keyPress(view.viewport(), 'x');
+
+    QTRY_COMPARE(widget->text(), hasWidget ? QString("x") : QString());
+
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::keyReleaseEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::newRow("widget") << true;
+    QTest::newRow("no widget") << false;
+}
+
+// protected void keyReleaseEvent(QKeyEvent* event)
+void tst_QGraphicsProxyWidget::keyReleaseEvent()
+{
+    QFETCH(bool, hasWidget);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+    QApplication::setActiveWindow(&view);
+    QTest::qWaitForWindowShown(&view);
+    QTRY_COMPARE(QApplication::activeWindow(), &view);
+
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    proxy->setFlag(QGraphicsItem::ItemIsFocusable, true); // ### remove me!!!
+    QPushButton *widget = new QPushButton;
+    QSignalSpy spy(widget, SIGNAL(clicked()));
+    widget->resize(50, 50);
+    view.resize(100, 100);
+    if (hasWidget) {
+        proxy->setWidget(widget);
+        proxy->show();
+    }
+    proxy->setPos(50, 0);
+    scene.addItem(proxy);
+    proxy->setFocus();
+
+    QTest::keyPress(view.viewport(), Qt::Key_Space);
+    QTRY_COMPARE(spy.count(), 0);
+    QTest::keyRelease(view.viewport(), Qt::Key_Space);
+    QTRY_COMPARE(spy.count(), (hasWidget) ? 1 : 0);
+
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::mouseDoubleClickEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::newRow("widget") << true;
+    QTest::newRow("no widget") << false;
+}
+
+// protected void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
+void tst_QGraphicsProxyWidget::mouseDoubleClickEvent()
+{
+    QFETCH(bool, hasWidget);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+
+    QApplication::setActiveWindow(&view);
+    QTest::qWaitForWindowShown(&view);
+    QTRY_COMPARE(QApplication::activeWindow(), &view);
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    proxy->setFlag(QGraphicsItem::ItemIsFocusable, true); // ### remove me!!!
+    QLineEdit *widget = new QLineEdit;
+    widget->setText("foo");
+    widget->resize(50, 50);
+    view.resize(100, 100);
+    if (hasWidget) {
+        proxy->setWidget(widget);
+        proxy->show();
+    }
+    proxy->setPos(50, 0);
+    scene.addItem(proxy);
+    proxy->setFocus();
+
+    QTest::mouseMove(view.viewport(), view.mapFromScene(proxy->mapToScene(15, proxy->boundingRect().center().y())));
+    QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(proxy->mapToScene(15, proxy->boundingRect().center().y())));
+    QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(proxy->mapToScene(15, proxy->boundingRect().center().y())));
+    QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(proxy->mapToScene(15, proxy->boundingRect().center().y())));
+    QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(proxy->mapToScene(15, proxy->boundingRect().center().y())));
+
+    QTRY_COMPARE(widget->selectedText(), hasWidget ? QString("foo") : QString());
+
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::mousePressReleaseEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::newRow("widget") << true;
+    QTest::newRow("no widget") << false;
+}
+
+// protected void mousePressEvent(QGraphicsSceneMouseEvent* event)
+void tst_QGraphicsProxyWidget::mousePressReleaseEvent()
+{
+    QFETCH(bool, hasWidget);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    proxy->setFlag(QGraphicsItem::ItemIsFocusable, true); // ### remove me!!!
+    QPushButton *widget = new QPushButton;
+    QSignalSpy spy(widget, SIGNAL(clicked()));
+    widget->resize(50, 50);
+    view.resize(100, 100);
+    if (hasWidget) {
+        proxy->setWidget(widget);
+	proxy->show();
+    }
+    proxy->setPos(50, 0);
+    scene.addItem(proxy);
+    proxy->setFocus();
+
+    QTest::mousePress(view.viewport(), Qt::LeftButton, 0,
+		      view.mapFromScene(proxy->mapToScene(proxy->boundingRect().center())));
+    QTRY_COMPARE(spy.count(), 0);
+    QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0,
+		      view.mapFromScene(proxy->mapToScene(proxy->boundingRect().center())));
+    QTRY_COMPARE(spy.count(), (hasWidget) ? 1 : 0);
+
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::resizeEvent_data()
+{
+    QTest::addColumn<bool>("hasWidget");
+    QTest::newRow("widget") << true;
+    QTest::newRow("no widget") << false;
+}
+
+// protected void resizeEvent(QGraphicsSceneResizeEvent* event)
+void tst_QGraphicsProxyWidget::resizeEvent()
+{
+    QFETCH(bool, hasWidget);
+
+    SubQGraphicsProxyWidget proxy;
+    QWidget *widget = new QWidget;
+    if (hasWidget)
+        proxy.setWidget(widget);
+
+    QSize newSize(100, 100);
+    QGraphicsSceneResizeEvent event;
+    event.setOldSize(QSize(10, 10));
+    event.setNewSize(newSize);
+    proxy.call_resizeEvent(&event);
+    if (hasWidget)
+        QCOMPARE(widget->size(), newSize);
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::paintEvent()
+{
+    //we test that calling update on a widget inside a QGraphicsView is triggering a repaint
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(70);
+
+    SubQGraphicsProxyWidget proxy;
+
+    QWidget *w = new QWidget;
+    //showing the widget here seems to create a bug in Graphics View
+    //this bug prevents the widget from being updated
+
+    w->show();
+    QTest::qWaitForWindowShown(w);
+    QApplication::processEvents();
+    QTest::qWait(100);
+    proxy.setWidget(w);
+    scene.addItem(&proxy);
+
+    //make sure we flush all the paint events
+    QTest::qWait(70);
+    QTRY_VERIFY(proxy.paintCount > 1);
+    QTest::qWait(110);
+    proxy.paintCount = 0;
+
+    w->update();
+    QTest::qWait(30);
+    QTRY_COMPARE(proxy.paintCount, 1); //the widget should have been painted now
+}
+
+
+void tst_QGraphicsProxyWidget::wheelEvent()
+{
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+
+    WheelWidget *wheelWidget = new WheelWidget();
+    wheelWidget->setFixedSize(400, 400);
+
+    QGraphicsProxyWidget *proxy = scene.addWidget(wheelWidget);
+    proxy->setVisible(true);
+
+    QGraphicsSceneWheelEvent event(QEvent::GraphicsSceneWheel);
+    event.setScenePos(QPoint(50, 50));
+    event.setAccepted(false);
+    wheelWidget->wheelEventCalled = false;
+
+    QApplication::sendEvent(&scene, &event);
+
+    QVERIFY(event.isAccepted());
+    QVERIFY(wheelWidget->wheelEventCalled);
+}
+
+Q_DECLARE_METATYPE(Qt::SizeHint)
+void tst_QGraphicsProxyWidget::sizeHint_data()
+{
+    QTest::addColumn<Qt::SizeHint>("which");
+    QTest::addColumn<QSizeF>("constraint");
+    QTest::addColumn<QSizeF>("sizeHint");
+    QTest::addColumn<bool>("hasWidget");
+
+    for (int i = 0; i < 2; ++i) {
+        bool hasWidget = (i == 0);
+        // ### What should these do?
+        QTest::newRow("min") << Qt::MinimumSize << QSizeF() << QSizeF() << hasWidget;
+        QTest::newRow("pre") << Qt::PreferredSize << QSizeF() << QSizeF() << hasWidget;
+        QTest::newRow("max") << Qt::MaximumSize << QSizeF() << QSizeF() << hasWidget;
+        QTest::newRow("mindes") << Qt::MinimumDescent << QSizeF() << QSizeF() << hasWidget;
+        QTest::newRow("nsize") << Qt::NSizeHints << QSizeF() << QSizeF() << hasWidget;
+    }
+}
+
+// protected QSizeF sizeHint(Qt::SizeHint which, QSizeF const& constraint = QSizeF()) const
+void tst_QGraphicsProxyWidget::sizeHint()
+{
+    QFETCH(Qt::SizeHint, which);
+    QFETCH(QSizeF, constraint);
+    QFETCH(QSizeF, sizeHint);
+    QFETCH(bool, hasWidget);
+    QSKIP("Broken test", SkipAll);
+    SubQGraphicsProxyWidget proxy;
+    QWidget *widget = new QWidget;
+    if (hasWidget)
+        proxy.setWidget(widget);
+    QCOMPARE(proxy.call_sizeHint(which, constraint), sizeHint);
+    if (!hasWidget)
+        delete widget;
+}
+
+void tst_QGraphicsProxyWidget::sizePolicy()
+{
+    for (int p = 0; p < 2; ++p) {
+        bool hasWidget = (p == 0 ? true : false);
+        SubQGraphicsProxyWidget proxy;
+        QWidget *widget = new QWidget;
+        QSizePolicy proxyPol(QSizePolicy::Maximum, QSizePolicy::Expanding);
+        proxy.setSizePolicy(proxyPol);
+        QSizePolicy widgetPol(QSizePolicy::Fixed, QSizePolicy::Minimum);
+        widget->setSizePolicy(widgetPol);
+
+        QCOMPARE(proxy.sizePolicy(), proxyPol);
+        QCOMPARE(widget->sizePolicy(), widgetPol);
+        if (hasWidget) {
+            proxy.setWidget(widget);
+            QCOMPARE(proxy.sizePolicy(), widgetPol);
+        } else {
+            QCOMPARE(proxy.sizePolicy(), proxyPol);
+        }
+        QCOMPARE(widget->sizePolicy(), widgetPol);
+
+        proxy.setSizePolicy(widgetPol);
+        widget->setSizePolicy(proxyPol);
+        if (hasWidget)
+            QCOMPARE(proxy.sizePolicy(), proxyPol);
+        else
+            QCOMPARE(proxy.sizePolicy(), widgetPol);
+    }
+}
+
+void tst_QGraphicsProxyWidget::minimumSize()
+{
+    SubQGraphicsProxyWidget proxy;
+    QWidget *widget = new QWidget;
+    QSize minSize(50, 50);
+    widget->setMinimumSize(minSize);
+    proxy.resize(30, 30);
+    widget->resize(30,30);
+    QCOMPARE(proxy.size(), QSizeF(30, 30));
+    proxy.setWidget(widget);
+    QCOMPARE(proxy.size().toSize(), minSize);
+    QCOMPARE(proxy.minimumSize().toSize(), minSize);
+    widget->setMinimumSize(70, 70);
+    QCOMPARE(proxy.minimumSize(), QSizeF(70, 70));
+    QCOMPARE(proxy.size(), QSizeF(70, 70));
+}
+
+void tst_QGraphicsProxyWidget::maximumSize()
+{
+    SubQGraphicsProxyWidget proxy;
+    QWidget *widget = new QWidget;
+    QSize maxSize(150, 150);
+    widget->setMaximumSize(maxSize);
+    proxy.resize(200, 200);
+    widget->resize(200,200);
+    QCOMPARE(proxy.size(), QSizeF(200, 200));
+    proxy.setWidget(widget);
+    QCOMPARE(proxy.size().toSize(), maxSize);
+    QCOMPARE(proxy.maximumSize().toSize(), maxSize);
+    widget->setMaximumSize(70, 70);
+    QCOMPARE(proxy.maximumSize(), QSizeF(70, 70));
+    QCOMPARE(proxy.size(), QSizeF(70, 70));
+}
+
+class View : public QGraphicsView
+{
+public:
+    View(QGraphicsScene *scene, QWidget *parent = 0)
+	: QGraphicsView(scene, parent), npaints(0)
+    { }
+    QRegion paintEventRegion;
+    int npaints;
+protected:
+    void paintEvent(QPaintEvent *event)
+    {
+	++npaints;
+	paintEventRegion += event->region();
+	QGraphicsView::paintEvent(event);
+    }
+};
+
+class ScrollWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    ScrollWidget() : npaints(0)
+    {
+	resize(200, 200);
+    }
+    QRegion paintEventRegion;
+    int npaints;
+
+public slots:
+    void updateScroll()
+    {
+	update(0, 0, 200, 10);
+	scroll(0, 10, QRect(0, 0, 100, 20));
+    }
+
+protected:
+    void paintEvent(QPaintEvent *event)
+    {
+	++npaints;
+	paintEventRegion += event->region();
+	QPainter painter(this);
+	painter.fillRect(event->rect(), Qt::blue);
+    }
+};
+
+void tst_QGraphicsProxyWidget::scrollUpdate()
+{
+    ScrollWidget *widget = new ScrollWidget;
+
+    QGraphicsScene scene;
+    scene.addWidget(widget);
+
+    View view(&scene);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QTRY_VERIFY(view.npaints >= 1);
+    QTest::qWait(20);
+    widget->paintEventRegion = QRegion();
+    widget->npaints = 0;
+    view.paintEventRegion = QRegion();
+    view.npaints = 0;
+    QTimer::singleShot(0, widget, SLOT(updateScroll()));
+    QTest::qWait(50);
+    QTRY_COMPARE(view.npaints, 2);
+    // QRect(0, 0, 200, 12) is the first update, expanded (-2, -2, 2, 2)
+    // QRect(0, 12, 102, 10) is the scroll update, expanded (-2, -2, 2, 2),
+    // intersected with the above update.
+    QCOMPARE(view.paintEventRegion.rects(),
+	     QVector<QRect>() << QRect(0, 0, 200, 12) << QRect(0, 12, 102, 10));
+    QCOMPARE(widget->npaints, 2);
+    QCOMPARE(widget->paintEventRegion.rects(),
+             QVector<QRect>() << QRect(0, 0, 200, 12) << QRect(0, 12, 102, 10));
+}
+
+void tst_QGraphicsProxyWidget::setWidget_simple()
+{
+    QGraphicsProxyWidget proxy;
+    QLineEdit *lineEdit = new QLineEdit;
+    proxy.setWidget(lineEdit);
+
+    QVERIFY(lineEdit->testAttribute(Qt::WA_DontShowOnScreen));
+    // Size hints
+    // ### size hints are tested in a different test
+    // QCOMPARE(proxy.effectiveSizeHint(Qt::MinimumSize).toSize(), lineEdit->minimumSizeHint());
+    // QCOMPARE(proxy.effectiveSizeHint(Qt::MaximumSize).toSize(), lineEdit->maximumSize());
+    // QCOMPARE(proxy.effectiveSizeHint(Qt::PreferredSize).toSize(), lineEdit->sizeHint());
+    QCOMPARE(proxy.size().toSize(), lineEdit->minimumSizeHint().expandedTo(lineEdit->size()));
+    QRect rect = lineEdit->rect();
+    rect.setSize(rect.size().expandedTo(lineEdit->minimumSizeHint()));
+    QCOMPARE(proxy.rect().toRect(), rect);
+
+    // Properties
+    // QCOMPARE(proxy.focusPolicy(), lineEdit->focusPolicy());
+    // QCOMPARE(proxy.palette(), lineEdit->palette());
+#ifndef QT_NO_CURSOR
+    QCOMPARE(proxy.cursor().shape(), lineEdit->cursor().shape());
+#endif
+    QCOMPARE(proxy.layoutDirection(), lineEdit->layoutDirection());
+    QCOMPARE(proxy.style(), lineEdit->style());
+    QCOMPARE(proxy.font(), lineEdit->font());
+    QCOMPARE(proxy.isEnabled(), lineEdit->isEnabled());
+    QCOMPARE(proxy.isVisible(), lineEdit->isVisible());
+}
+
+void tst_QGraphicsProxyWidget::setWidget_ownership()
+{
+    QPointer<QLineEdit> lineEdit = new QLineEdit;
+    QPointer<QLineEdit> lineEdit2 = new QLineEdit;
+    QVERIFY(lineEdit);
+    {
+        // Create a proxy and transfer ownership to it
+        QGraphicsProxyWidget proxy;
+        proxy.setWidget(lineEdit);
+        QCOMPARE(proxy.widget(), (QWidget *)lineEdit);
+
+        // Remove the widget without destroying it.
+        proxy.setWidget(0);
+        QVERIFY(!proxy.widget());
+        QVERIFY(lineEdit);
+
+        // Assign the widget again and switch to another widget.
+        proxy.setWidget(lineEdit);
+        proxy.setWidget(lineEdit2);
+        QCOMPARE(proxy.widget(), (QWidget *)lineEdit2);
+
+        // Assign the first widget, and destroy the proxy.
+        proxy.setWidget(lineEdit);
+    }
+    QVERIFY(!lineEdit);
+    QVERIFY(lineEdit2);
+
+    QGraphicsScene scene;
+    QPointer<QGraphicsProxyWidget> proxy = scene.addWidget(lineEdit2);
+
+    delete lineEdit2;
+    QVERIFY(!proxy);
+}
+
+void tst_QGraphicsProxyWidget::resize_simple_data()
+{
+    QTest::addColumn<QSizeF>("size");
+
+    QTest::newRow("200, 200") << QSizeF(200, 200);
+#if !defined(QT_ARCH_ARM) && !defined(Q_OS_WINCE)
+    QTest::newRow("1000, 1000") << QSizeF(1000, 1000);
+    // Since 4.5, 10000x10000 runs out of memory.
+    // QTest::newRow("10000, 10000") << QSizeF(10000, 10000);
+#endif
+}
+
+void tst_QGraphicsProxyWidget::resize_simple()
+{
+    QFETCH(QSizeF, size);
+
+    QGraphicsProxyWidget proxy;
+    QWidget *widget = new QWidget;
+    widget->setGeometry(0, 0, (int)size.width(), (int)size.height());
+    proxy.setWidget(widget);
+    widget->show();
+    QCOMPARE(widget->pos(), QPoint());
+
+    // The proxy resizes itself, the line edit follows
+    proxy.resize(size);
+    QCOMPARE(proxy.size(), size);
+    QCOMPARE(proxy.size().toSize(), widget->size());
+
+    // The line edit resizes itself, the proxy follows (no loopback/live lock)
+    QSize doubleSize = size.toSize() * 2;
+    widget->resize(doubleSize);
+    QCOMPARE(widget->size(), doubleSize);
+    QCOMPARE(widget->size(), proxy.size().toSize());
+}
+
+void tst_QGraphicsProxyWidget::symmetricMove()
+{
+    QGraphicsProxyWidget proxy;
+    QLineEdit *lineEdit = new QLineEdit;
+    proxy.setWidget(lineEdit);
+    lineEdit->show();
+
+    proxy.setPos(10, 10);
+    QCOMPARE(proxy.pos(), QPointF(10, 10));
+    QCOMPARE(lineEdit->pos(), QPoint(10, 10));
+
+    lineEdit->move(5, 5);
+    QCOMPARE(proxy.pos(), QPointF(5, 5));
+    QCOMPARE(lineEdit->pos(), QPoint(5, 5));
+}
+
+void tst_QGraphicsProxyWidget::symmetricResize()
+{
+    QGraphicsProxyWidget proxy;
+    QLineEdit *lineEdit = new QLineEdit;
+    proxy.setWidget(lineEdit);
+    lineEdit->show();
+
+    proxy.resize(256, 256);
+    QCOMPARE(proxy.size(), QSizeF(256, 256));
+    QCOMPARE(lineEdit->size(), QSize(256, 256));
+
+    lineEdit->resize(512, 512);
+    QCOMPARE(proxy.size(), QSizeF(512, 512));
+    QCOMPARE(lineEdit->size(), QSize(512, 512));
+}
+
+void tst_QGraphicsProxyWidget::symmetricVisible()
+{
+    QGraphicsProxyWidget proxy;
+    QLineEdit *lineEdit = new QLineEdit;
+    proxy.setWidget(lineEdit);
+    lineEdit->show();
+
+    QCOMPARE(proxy.isVisible(), lineEdit->isVisible());
+
+    proxy.hide();
+    QCOMPARE(proxy.isVisible(), lineEdit->isVisible());
+    proxy.show();
+    QCOMPARE(proxy.isVisible(), lineEdit->isVisible());
+    lineEdit->hide();
+    QCOMPARE(proxy.isVisible(), lineEdit->isVisible());
+    lineEdit->show();
+    QCOMPARE(proxy.isVisible(), lineEdit->isVisible());
+ }
+
+void tst_QGraphicsProxyWidget::symmetricEnabled()
+{
+    QGraphicsProxyWidget proxy;
+    QLineEdit *lineEdit = new QLineEdit;
+    proxy.setWidget(lineEdit);
+    lineEdit->show();
+
+    QCOMPARE(proxy.isEnabled(), lineEdit->isEnabled());
+    proxy.setEnabled(false);
+    QCOMPARE(proxy.isEnabled(), lineEdit->isEnabled());
+    proxy.setEnabled(true);
+    QCOMPARE(proxy.isEnabled(), lineEdit->isEnabled());
+    lineEdit->setEnabled(false);
+    QCOMPARE(proxy.isEnabled(), lineEdit->isEnabled());
+    lineEdit->setEnabled(true);
+    QCOMPARE(proxy.isEnabled(), lineEdit->isEnabled());
+}
+
+void tst_QGraphicsProxyWidget::tabFocus_simpleWidget()
+{
+    QGraphicsScene scene;
+    QLineEdit *edit = new QLineEdit;
+    QGraphicsProxyWidget *editProxy = scene.addWidget(edit);
+    editProxy->show();
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(view);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    window.show();
+    QApplication::setActiveWindow(&window);
+    window.activateWindow();
+    QTest::qWaitForWindowShown(&window);
+
+    leftDial->setFocus();
+    QApplication::processEvents();
+    QTRY_VERIFY(leftDial->hasFocus());
+
+    EventSpy eventSpy(edit);
+
+    // Tab into line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QTRY_VERIFY(!leftDial->hasFocus());
+    QTRY_VERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QVERIFY(scene.hasFocus());
+    QVERIFY(editProxy->hasFocus());
+    QVERIFY(edit->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 0);
+
+    // Tab into right dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QTRY_VERIFY(!view->hasFocus());
+    QVERIFY(!view->viewport()->hasFocus());
+    QVERIFY(!scene.hasFocus());
+    QVERIFY(!editProxy->hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QTRY_VERIFY(rightDial->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+
+    // Backtab into line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QTRY_VERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QTRY_VERIFY(scene.hasFocus());
+    QVERIFY(editProxy->hasFocus());
+    QVERIFY(edit->hasFocus());
+    QVERIFY(!rightDial->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+
+    // Backtab into left dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QTRY_VERIFY(!view->hasFocus());
+    QVERIFY(!view->viewport()->hasFocus());
+    QVERIFY(!scene.hasFocus());
+    QVERIFY(!editProxy->hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QTRY_VERIFY(leftDial->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 2);
+
+    delete view;
+}
+
+void tst_QGraphicsProxyWidget::tabFocus_simpleTwoWidgets()
+{
+    QGraphicsScene scene;
+    QLineEdit *edit = new QLineEdit;
+    QLineEdit *edit2 = new QLineEdit;
+    QGraphicsProxyWidget *editProxy = scene.addWidget(edit);
+    editProxy->show();
+    QGraphicsProxyWidget *editProxy2 = scene.addWidget(edit2);
+    editProxy2->show();
+    editProxy2->setPos(0, editProxy->rect().height() * 1.1);
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(view);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    window.show();
+    QApplication::setActiveWindow(&window);
+    window.activateWindow();
+    QTest::qWaitForWindowShown(&window);
+
+    leftDial->setFocus();
+    QApplication::processEvents();
+    QTRY_VERIFY(leftDial->hasFocus());
+
+    EventSpy eventSpy(edit);
+    EventSpy eventSpy2(edit2);
+
+    // Tab into line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!leftDial->hasFocus());
+    QVERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QVERIFY(scene.hasFocus());
+    QVERIFY(editProxy->hasFocus());
+    QVERIFY(edit->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 0);
+
+    // Tab into second line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QVERIFY(scene.hasFocus());
+    QVERIFY(!editProxy->hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QVERIFY(editProxy2->hasFocus());
+    QVERIFY(edit2->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 0);
+
+    // Tab into right dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!view->hasFocus());
+    QVERIFY(!view->viewport()->hasFocus());
+    QVERIFY(!scene.hasFocus());
+    QVERIFY(!editProxy->hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QVERIFY(!editProxy2->hasFocus());
+    QVERIFY(!edit2->hasFocus());
+    QVERIFY(rightDial->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 1);
+
+    // Backtab into line edit 2
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QVERIFY(scene.hasFocus());
+    QVERIFY(!editProxy->hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QVERIFY(editProxy2->hasFocus());
+    QVERIFY(edit2->hasFocus());
+    QVERIFY(!rightDial->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 1);
+
+    // Backtab into line edit 1
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QVERIFY(scene.hasFocus());
+    QVERIFY(editProxy->hasFocus());
+    QVERIFY(edit->hasFocus());
+    QVERIFY(!editProxy2->hasFocus());
+    QVERIFY(!edit2->hasFocus());
+    QVERIFY(!rightDial->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 2);
+
+    // Backtab into left dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!view->hasFocus());
+    QVERIFY(!view->viewport()->hasFocus());
+    QVERIFY(!scene.hasFocus());
+    QVERIFY(!editProxy->hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QVERIFY(leftDial->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 2);
+
+    delete view;
+}
+
+void tst_QGraphicsProxyWidget::tabFocus_complexWidget()
+{
+    QGraphicsScene scene;
+
+    QLineEdit *edit1 = new QLineEdit;
+    edit1->setText("QLineEdit 1");
+    QLineEdit *edit2 = new QLineEdit;
+    edit2->setText("QLineEdit 2");
+    QVBoxLayout *vlayout = new QVBoxLayout;
+    vlayout->addWidget(edit1);
+    vlayout->addWidget(edit2);
+
+    QGroupBox *box = new QGroupBox("QGroupBox");
+    box->setCheckable(true);
+    box->setChecked(true);
+    box->setLayout(vlayout);
+
+    QGraphicsProxyWidget *proxy = scene.addWidget(box);
+    proxy->show();
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(view);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    window.show();
+    QApplication::setActiveWindow(&window);
+    window.activateWindow();
+    QTest::qWaitForWindowShown(&window);
+
+    leftDial->setFocus();
+    QApplication::processEvents();
+    QTRY_VERIFY(leftDial->hasFocus());
+
+    EventSpy eventSpy(edit1);
+    EventSpy eventSpy2(edit2);
+    EventSpy eventSpyBox(box);
+
+    // Tab into group box
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!leftDial->hasFocus());
+    QVERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QVERIFY(scene.hasFocus());
+    QVERIFY(proxy->hasFocus());
+    QVERIFY(box->hasFocus());
+
+    // Tab into line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    edit1->hasFocus();
+    QVERIFY(!box->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 0);
+
+    // Tab into line edit 2
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    edit2->hasFocus();
+    QVERIFY(!edit1->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 0);
+
+    // Tab into right dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!edit2->hasFocus());
+    rightDial->hasFocus();
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 1);
+
+    // Backtab into line edit 2
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!rightDial->hasFocus());
+    edit2->hasFocus();
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 1);
+
+    // Backtab into line edit 1
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!edit2->hasFocus());
+    edit1->hasFocus();
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 2);
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 2);
+
+    // Backtab into line box
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!edit1->hasFocus());
+    box->hasFocus();
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 2);
+
+    // Backtab into left dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!box->hasFocus());
+    leftDial->hasFocus();
+
+    delete view;
+}
+
+void tst_QGraphicsProxyWidget::tabFocus_complexTwoWidgets()
+{
+    // ### add event spies to this test.
+    QGraphicsScene scene;
+
+    QLineEdit *edit1 = new QLineEdit;
+    edit1->setText("QLineEdit 1");
+    QLineEdit *edit2 = new QLineEdit;
+    edit2->setText("QLineEdit 2");
+    QFontComboBox *fontComboBox = new QFontComboBox;
+    QVBoxLayout *vlayout = new QVBoxLayout;
+    vlayout->addWidget(edit1);
+    vlayout->addWidget(fontComboBox);
+    vlayout->addWidget(edit2);
+
+    QGroupBox *box = new QGroupBox("QGroupBox");
+    box->setCheckable(true);
+    box->setChecked(true);
+    box->setLayout(vlayout);
+
+    QLineEdit *edit1_2 = new QLineEdit;
+    edit1_2->setText("QLineEdit 1_2");
+    QLineEdit *edit2_2 = new QLineEdit;
+    edit2_2->setText("QLineEdit 2_2");
+    QFontComboBox *fontComboBox2 = new QFontComboBox;
+    vlayout = new QVBoxLayout;
+    vlayout->addWidget(edit1_2);
+    vlayout->addWidget(fontComboBox2);
+    vlayout->addWidget(edit2_2);
+
+    QGroupBox *box_2 = new QGroupBox("QGroupBox 2");
+    box_2->setCheckable(true);
+    box_2->setChecked(true);
+    box_2->setLayout(vlayout);
+
+    QGraphicsProxyWidget *proxy = scene.addWidget(box);
+    proxy->show();
+
+    QGraphicsProxyWidget *proxy_2 = scene.addWidget(box_2);
+    proxy_2->setPos(proxy->boundingRect().width() * 1.2, 0);
+    proxy_2->show();
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+    view->setRenderHint(QPainter::Antialiasing);
+    view->rotate(45);
+    view->scale(0.5, 0.5);
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(view);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    window.show();
+    QApplication::setActiveWindow(&window);
+    window.activateWindow();
+    QTest::qWaitForWindowShown(&window);
+    QTRY_COMPARE(QApplication::activeWindow(), &window);
+
+    leftDial->setFocus();
+    QApplication::processEvents();
+    QTRY_VERIFY(leftDial->hasFocus());
+
+    EventSpy eventSpy(edit1);
+    EventSpy eventSpy2(edit2);
+    EventSpy eventSpy3(fontComboBox);
+    EventSpy eventSpy1_2(edit1_2);
+    EventSpy eventSpy2_2(edit2_2);
+    EventSpy eventSpy2_3(fontComboBox2);
+    EventSpy eventSpyBox(box);
+
+    // Tab into group box
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!leftDial->hasFocus());
+    QVERIFY(view->hasFocus());
+    QVERIFY(view->viewport()->hasFocus());
+    QVERIFY(scene.hasFocus());
+    QVERIFY(proxy->hasFocus());
+    QVERIFY(box->hasFocus());
+
+    // Tab into line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    edit1->hasFocus();
+    QVERIFY(!box->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 0);
+
+    // Tab to the font combobox
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    fontComboBox->hasFocus();
+    QVERIFY(!edit2->hasFocus());
+    QCOMPARE(eventSpy3.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy3.counts[QEvent::FocusOut], 0);
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+
+    // Tab into line edit 2
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    edit2->hasFocus();
+    QVERIFY(!edit1->hasFocus());
+    QCOMPARE(eventSpy2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2.counts[QEvent::FocusOut], 0);
+    QCOMPARE(eventSpy3.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+
+    // Tab into right box
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!edit2->hasFocus());
+    box_2->hasFocus();
+
+    // Tab into right top line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!box_2->hasFocus());
+    edit1_2->hasFocus();
+    QCOMPARE(eventSpy1_2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy1_2.counts[QEvent::FocusOut], 0);
+
+    // Tab into right font combobox
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!edit1_2->hasFocus());
+    fontComboBox2->hasFocus();
+    QCOMPARE(eventSpy1_2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy1_2.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2_3.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2_3.counts[QEvent::FocusOut], 0);
+
+    // Tab into right bottom line edit
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!edit1_2->hasFocus());
+    edit2_2->hasFocus();
+    QCOMPARE(eventSpy1_2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy1_2.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2_3.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2_3.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusOut], 0);
+
+    // Tab into right dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+    QApplication::processEvents();
+    QVERIFY(!edit2->hasFocus());
+    rightDial->hasFocus();
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusOut], 1);
+
+    // Backtab into line edit 2
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!rightDial->hasFocus());
+    edit2_2->hasFocus();
+
+    // Backtab into the right font combobox
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!edit2_2->hasFocus());
+    fontComboBox2->hasFocus();
+
+    // Backtab into line edit 1
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!edit2_2->hasFocus());
+    edit1_2->hasFocus();
+
+    // Backtab into line box
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!edit1_2->hasFocus());
+    box_2->hasFocus();
+
+    // Backtab into line edit 2
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!rightDial->hasFocus());
+    edit2->hasFocus();
+
+    // Backtab into the font combobox
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!edit2->hasFocus());
+    fontComboBox->hasFocus();
+
+    // Backtab into line edit 1
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!fontComboBox->hasFocus());
+    edit1->hasFocus();
+
+    // Backtab into line box
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!edit1->hasFocus());
+    box->hasFocus();
+
+    // Backtab into left dial
+    QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+    QApplication::processEvents();
+    QVERIFY(!box->hasFocus());
+    leftDial->hasFocus();
+
+    delete view;
+}
+
+void tst_QGraphicsProxyWidget::setFocus_simpleWidget()
+{
+    QGraphicsScene scene;
+    QLineEdit *edit = new QLineEdit;
+    QGraphicsProxyWidget *editProxy = scene.addWidget(edit);
+    editProxy->show();
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(view);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    window.show();
+    QApplication::setActiveWindow(&window);
+    window.activateWindow();
+    QTest::qWaitForWindowShown(&window);
+    QTRY_COMPARE(QApplication::activeWindow(), &window);
+
+    leftDial->setFocus();
+    QApplication::processEvents();
+    QTRY_VERIFY(leftDial->hasFocus());
+
+    EventSpy eventSpy(edit);
+
+    // Calling setFocus for the line edit when the view doesn't have input
+    // focus does not steal focus from the dial. The edit, proxy and scene
+    // have focus but only in their own little space.
+    edit->setFocus();
+    QVERIFY(scene.hasFocus());
+    QVERIFY(edit->hasFocus());
+    QVERIFY(!view->hasFocus());
+    QVERIFY(!view->viewport()->hasFocus());
+    QVERIFY(leftDial->hasFocus());
+
+    // Clearing focus is a local operation.
+    edit->clearFocus();
+    QVERIFY(scene.hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QVERIFY(!view->hasFocus());
+    QVERIFY(leftDial->hasFocus());
+
+    view->setFocus();
+    QVERIFY(scene.hasFocus());
+    QVERIFY(view->hasFocus());
+    QVERIFY(!leftDial->hasFocus());
+    QVERIFY(!edit->hasFocus());
+
+    scene.clearFocus();
+    QVERIFY(!scene.hasFocus());
+
+    edit->setFocus();
+    QVERIFY(scene.hasFocus());
+    QVERIFY(edit->hasFocus());
+    QVERIFY(editProxy->hasFocus());
+
+    // Symmetry
+    editProxy->clearFocus();
+    QVERIFY(!edit->hasFocus());
+
+    delete view;
+}
+
+void tst_QGraphicsProxyWidget::setFocus_simpleTwoWidgets()
+{
+    QGraphicsScene scene;
+    QLineEdit *edit = new QLineEdit;
+    QGraphicsProxyWidget *editProxy = scene.addWidget(edit);
+    editProxy->show();
+    QLineEdit *edit2 = new QLineEdit;
+    QGraphicsProxyWidget *edit2Proxy = scene.addWidget(edit2);
+    edit2Proxy->show();
+    edit2Proxy->setPos(editProxy->boundingRect().width() * 1.01, 0);
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(view);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    window.show();
+    QApplication::setActiveWindow(&window);
+    window.activateWindow();
+    QTest::qWaitForWindowShown(&window);
+    QTRY_COMPARE(QApplication::activeWindow(), &window);
+
+    leftDial->setFocus();
+    QApplication::processEvents();
+    QTRY_VERIFY(leftDial->hasFocus());
+
+    EventSpy eventSpy(edit);
+
+    view->setFocus();
+    QVERIFY(!edit->hasFocus());
+
+    edit->setFocus();
+    QVERIFY(scene.hasFocus());
+    QVERIFY(edit->hasFocus());
+    QVERIFY(editProxy->hasFocus());
+
+    edit2->setFocus();
+    QVERIFY(scene.hasFocus());
+    QVERIFY(!edit->hasFocus());
+    QVERIFY(!editProxy->hasFocus());
+    QVERIFY(edit2->hasFocus());
+    QVERIFY(edit2Proxy->hasFocus());
+
+    delete view;
+}
+
+void tst_QGraphicsProxyWidget::setFocus_complexTwoWidgets()
+{
+    // ### add event spies to this test.
+    QGraphicsScene scene;
+
+    QLineEdit *edit1 = new QLineEdit;
+    edit1->setText("QLineEdit 1");
+    QLineEdit *edit2 = new QLineEdit;
+    edit2->setText("QLineEdit 2");
+    QVBoxLayout *vlayout = new QVBoxLayout;
+    vlayout->addWidget(edit1);
+    vlayout->addWidget(edit2);
+
+    QGroupBox *box = new QGroupBox("QGroupBox");
+    box->setCheckable(true);
+    box->setChecked(true);
+    box->setLayout(vlayout);
+
+    QLineEdit *edit1_2 = new QLineEdit;
+    edit1_2->setText("QLineEdit 1_2");
+    QLineEdit *edit2_2 = new QLineEdit;
+    edit2_2->setText("QLineEdit 2_2");
+    vlayout = new QVBoxLayout;
+    vlayout->addWidget(edit1_2);
+    vlayout->addWidget(edit2_2);
+
+    QGroupBox *box_2 = new QGroupBox("QGroupBox 2");
+    box_2->setCheckable(true);
+    box_2->setChecked(true);
+    box_2->setLayout(vlayout);
+
+    QGraphicsProxyWidget *proxy = scene.addWidget(box);
+    proxy->show();
+
+    QGraphicsProxyWidget *proxy_2 = scene.addWidget(box_2);
+    proxy_2->setPos(proxy->boundingRect().width() * 1.2, 0);
+    proxy_2->show();
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+    QGraphicsView *view = new QGraphicsView(&scene);
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(view);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    window.show();
+    QApplication::setActiveWindow(&window);
+    window.activateWindow();
+    QTest::qWaitForWindowShown(&window);
+    QTRY_COMPARE(QApplication::activeWindow(), &window);
+
+    leftDial->setFocus();
+    QApplication::processEvents();
+    QTRY_VERIFY(leftDial->hasFocus());
+
+    EventSpy eventSpy(edit1);
+    EventSpy eventSpy2(edit2);
+    EventSpy eventSpyBox(box);
+    EventSpy eventSpy_2(edit1_2);
+    EventSpy eventSpy2_2(edit2_2);
+    EventSpy eventSpyBox_2(box_2);
+
+    view->setFocus();
+
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 0);
+
+    edit1->setFocus();
+    QApplication::processEvents();
+    QVERIFY(scene.hasFocus());
+    QVERIFY(edit1->hasFocus());
+    QVERIFY(!box->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpyBox.counts[QEvent::FocusIn], 0);
+
+    edit2_2->setFocus();
+    QApplication::processEvents();
+    QVERIFY(!edit1->hasFocus());
+    QVERIFY(!box_2->hasFocus());
+    QVERIFY(edit2_2->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpyBox.counts[QEvent::FocusIn], 0);
+    QCOMPARE(eventSpyBox_2.counts[QEvent::FocusIn], 0);
+
+    box->setFocus();
+    QApplication::processEvents();
+    QVERIFY(!edit2_2->hasFocus());
+    QVERIFY(!edit1->hasFocus());
+    QVERIFY(box->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpyBox.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpyBox.counts[QEvent::FocusOut], 0);
+    QCOMPARE(eventSpyBox_2.counts[QEvent::FocusIn], 0);
+    QCOMPARE(eventSpyBox_2.counts[QEvent::FocusOut], 0);
+
+    edit2_2->setFocus();
+    QApplication::processEvents();
+    QVERIFY(edit2_2->hasFocus());
+    QVERIFY(!edit1->hasFocus());
+    QVERIFY(!box->hasFocus());
+    QVERIFY(!box_2->hasFocus());
+    QCOMPARE(eventSpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusIn], 2);
+    QCOMPARE(eventSpy2_2.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpyBox.counts[QEvent::FocusIn], 1);
+    QCOMPARE(eventSpyBox.counts[QEvent::FocusOut], 1);
+    QCOMPARE(eventSpyBox_2.counts[QEvent::FocusIn], 0);
+    QCOMPARE(eventSpyBox_2.counts[QEvent::FocusOut], 0);
+
+    delete view;
+}
+
+void tst_QGraphicsProxyWidget::popup_basic()
+{
+    // ProxyWidget should automatically create proxy's when the widget creates a child
+    QGraphicsScene *scene = new QGraphicsScene;
+    QGraphicsView view(scene);
+    view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
+    view.setGeometry(0, 100, 480, 500);
+    view.show();
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    QComboBox *box = new QComboBox;
+    box->setGeometry(0, 0, 320, 40);
+    box->addItems(QStringList() << "monday" << "tuesday" << "wednesday"
+		  << "thursday" << "saturday" << "sunday");
+    QCOMPARE(proxy->childItems().count(), 0);
+    proxy->setWidget(box);
+    proxy->show();
+    scene->addItem(proxy);
+
+    QCOMPARE(box->pos(), QPoint());
+    QCOMPARE(proxy->pos(), QPointF());
+
+    QTest::qWaitForWindowShown(&view);
+    QTest::qWait(125);
+    QApplication::processEvents();
+
+    QTest::mousePress(view.viewport(), Qt::LeftButton, 0,
+		      view.mapFromScene(proxy->mapToScene(proxy->boundingRect().center())));
+
+    QTest::qWait(12);
+
+    QCOMPARE(box->pos(), QPoint());
+
+    QCOMPARE(proxy->childItems().count(), 1);
+    QGraphicsProxyWidget *child = (QGraphicsProxyWidget*)(proxy->childItems())[0];
+    QVERIFY(child->isWidget());
+    QVERIFY(child->widget());
+    QStyleOptionComboBox opt;
+    opt.initFrom(box);
+    opt.editable = box->isEditable();
+    if (box->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt))
+        QSKIP("Does not work due to SH_Combobox_Popup", SkipAll);
+    QCOMPARE(child->widget()->parent(), static_cast<QObject*>(box));
+
+    QTest::qWait(12);
+    QTRY_COMPARE(proxy->pos(), QPointF(box->pos()));
+    QCOMPARE(child->x(), qreal(box->x()));
+    QCOMPARE(child->y(), qreal(box->rect().bottom()));
+#ifndef Q_OS_WIN
+    // The popup's coordinates on Windows are in global space,
+    // regardless.
+    QCOMPARE(child->widget()->x(), box->x());
+    QCOMPARE(child->widget()->y(), box->rect().bottom());
+    QCOMPARE(child->geometry().toRect(), child->widget()->geometry());
+#endif
+    QTest::qWait(12);
+}
+
+void tst_QGraphicsProxyWidget::popup_subwidget()
+{
+    QGroupBox *groupBox = new QGroupBox;
+    groupBox->setTitle("GroupBox");
+    groupBox->setCheckable(true);
+
+    QComboBox *box = new QComboBox;
+    box->addItems(QStringList() << "monday" << "tuesday" << "wednesday"
+		  << "thursday" << "saturday" << "sunday");
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->addWidget(new QLineEdit("QLineEdit"));
+    layout->addWidget(box);
+    layout->addWidget(new QLineEdit("QLineEdit"));
+    groupBox->setLayout(layout);
+
+    QGraphicsScene scene;
+    QGraphicsProxyWidget *groupBoxProxy = scene.addWidget(groupBox);
+    groupBox->show();
+    groupBox->move(10000, 10000);
+    QCOMPARE(groupBox->pos(), QPoint(10000, 10000));
+    QCOMPARE(groupBoxProxy->pos(), QPointF(10000, 10000));
+
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+
+    box->showPopup();
+
+    QVERIFY(!groupBoxProxy->childItems().isEmpty());
+
+    QStyleOptionComboBox opt;
+    opt.initFrom(box);
+    opt.editable = box->isEditable();
+    if (box->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt))
+        QSKIP("Does not work due to SH_Combobox_Popup", SkipAll);
+    QGraphicsProxyWidget *child = (QGraphicsProxyWidget*)(groupBoxProxy->childItems())[0];
+    QWidget *popup = child->widget();
+    QCOMPARE(popup->parent(), static_cast<QObject*>(box));
+    QCOMPARE(popup->x(), box->mapToGlobal(QPoint()).x());
+    QCOMPARE(popup->y(), QRect(box->mapToGlobal(QPoint()), box->size()).bottom());
+    QCOMPARE(popup->size(), child->size().toSize());
+}
+
+void tst_QGraphicsProxyWidget::changingCursor_basic()
+{
+#if defined(Q_OS_WINCE) && (!defined(GWES_ICONCURS) || defined(QT_NO_CURSOR))
+    QSKIP("hover events not supported on this platform", SkipAll);
+#endif
+#ifndef QT_NO_CURSOR
+    // Confirm that mouse events are working properly by checking that
+    // when moving the mouse over a line edit it will change the cursor into the I
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    QLineEdit *widget = new QLineEdit;
+    proxy->setWidget(widget);
+    proxy->show();
+    scene.addItem(proxy);
+    QTest::qWaitForWindowShown(&view);
+    QApplication::processEvents();
+
+    // in
+    QTest::mouseMove(view.viewport(), view.mapFromScene(proxy->mapToScene(proxy->boundingRect().center())));
+    sendMouseMove(view.viewport(), view.mapFromScene(proxy->mapToScene(proxy->boundingRect().center())));
+    QTest::qWait(125);
+    QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
+
+    // out
+    QTest::mouseMove(view.viewport(), QPoint(1, 1));
+    sendMouseMove(view.viewport(), QPoint(1, 1));
+    QTest::qWait(125);
+    QCOMPARE(view.viewport()->cursor().shape(), Qt::ArrowCursor);
+#endif
+}
+
+void tst_QGraphicsProxyWidget::tooltip_basic()
+{
+    // Confirm that mouse events are working properly by checking that
+    // when moving the mouse over a label with a tooptip the tooltip appears
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+
+    QSKIP("Tooltips don't work yet", SkipAll);
+
+    SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
+    QLabel *widget = new QLabel;
+    widget->setText("If it ain't tested it's broken");
+    widget->setToolTip("When in doubt, test");
+    proxy->setWidget(widget);
+    widget->show();
+    scene.addItem(proxy);
+    QTest::qWait(125);
+
+    // in
+    QTest::mouseMove(view.viewport(), view.mapFromScene(proxy->mapToScene(proxy->boundingRect().center())));
+    QTest::qWait(3000);
+
+    QCOMPARE(proxy->childItems().count(), 1);
+    QGraphicsProxyWidget *child = (QGraphicsProxyWidget*)(proxy->childItems())[0];
+    QVERIFY(child->isWidget());
+    QVERIFY(child->widget());
+    QCOMPARE(child->widget()->parent(), static_cast<QObject*>(widget));
+    QCOMPARE(child->widget()->x(), widget->x()); // ### ???
+    QCOMPARE(child->widget()->y(), widget->y() + widget->height()); // ### ???
+}
+
+void tst_QGraphicsProxyWidget::childPos_data()
+{
+    QTest::addColumn<bool>("moveCombo");
+    QTest::addColumn<QPoint>("comboPos");
+    QTest::addColumn<QPointF>("proxyPos");
+    QTest::addColumn<QPointF>("menuPos");
+
+    QTest::newRow("0") << true << QPoint() << QPointF() << QPointF();
+    QTest::newRow("1") << true << QPoint(10, 0) << QPointF(10, 0) << QPointF();
+    QTest::newRow("2") << true << QPoint(100, 0) << QPointF(100, 0) << QPointF();
+    QTest::newRow("3") << true << QPoint(1000, 0) << QPointF(1000, 0) << QPointF();
+    QTest::newRow("4") << true << QPoint(10000, 0) << QPointF(10000, 0) << QPointF();
+    QTest::newRow("5") << true << QPoint(-10000, 0) << QPointF(-10000, 0) << QPointF();
+    QTest::newRow("6") << true << QPoint(-1000, 0) << QPointF(-1000, 0) << QPointF();
+    QTest::newRow("7") << true << QPoint(-100, 0) << QPointF(-100, 0) << QPointF();
+    QTest::newRow("8") << true << QPoint(-10, 0) << QPointF(-10, 0) << QPointF();
+    QTest::newRow("0-") << false << QPoint() << QPointF() << QPointF();
+    QTest::newRow("1-") << false << QPoint(10, 0) << QPointF(10, 0) << QPointF();
+    QTest::newRow("2-") << false << QPoint(100, 0) << QPointF(100, 0) << QPointF();
+    QTest::newRow("3-") << false << QPoint(1000, 0) << QPointF(1000, 0) << QPointF();
+    QTest::newRow("4-") << false << QPoint(10000, 0) << QPointF(10000, 0) << QPointF();
+    QTest::newRow("5-") << false << QPoint(-10000, 0) << QPointF(-10000, 0) << QPointF();
+    QTest::newRow("6-") << false << QPoint(-1000, 0) << QPointF(-1000, 0) << QPointF();
+    QTest::newRow("7-") << false << QPoint(-100, 0) << QPointF(-100, 0) << QPointF();
+    QTest::newRow("8-") << false << QPoint(-10, 0) << QPointF(-10, 0) << QPointF();
+}
+
+void tst_QGraphicsProxyWidget::childPos()
+{
+#ifdef Q_OS_IRIX
+    QSKIP("This test is not reliable on IRIX.", SkipAll);
+#endif
+    QFETCH(bool, moveCombo);
+    QFETCH(QPoint, comboPos);
+    QFETCH(QPointF, proxyPos);
+    QFETCH(QPointF, menuPos);
+
+    QGraphicsScene scene;
+
+    QComboBox *box = new QComboBox;
+    box->addItem("Item 1");
+    box->addItem("Item 2");
+    box->addItem("Item 3");
+    box->addItem("Item 4");
+
+    if (moveCombo)
+        box->move(comboPos);
+
+    QGraphicsProxyWidget *proxy = scene.addWidget(box);
+    proxy->show();
+    QVERIFY(proxy->isVisible());
+    QVERIFY(box->isVisible());
+
+    if (!moveCombo)
+        proxy->setPos(proxyPos);
+
+    QCOMPARE(proxy->pos(), proxyPos);
+    QCOMPARE(box->pos(), comboPos);
+
+    for (int i = 0; i < 2; ++i) {
+        box->showPopup();
+        QApplication::processEvents();
+        QApplication::processEvents();
+
+        QWidget *menu = 0;
+        foreach (QObject *child, box->children()) {
+            if ((menu = qobject_cast<QWidget *>(child)))
+                break;
+        }
+        QVERIFY(menu);
+        QVERIFY(menu->isVisible());
+        QVERIFY(menu->testAttribute(Qt::WA_DontShowOnScreen));
+
+        QCOMPARE(proxy->childItems().size(), 1);
+        QGraphicsProxyWidget *proxyChild = 0;
+        foreach (QGraphicsItem *child, proxy->childItems()) {
+            if (child->isWidget() && (proxyChild = qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(child))))
+                break;
+        }
+        QVERIFY(proxyChild);
+        QVERIFY(proxyChild->isVisible());
+        qreal expectedXPosition = 0.0;
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+        // The Mac style wants the popup to show up at QPoint(4 - 11, 1).
+        // See QMacStyle::subControlRect SC_ComboBoxListBoxPopup.
+        if (qobject_cast<QMacStyle *>(QApplication::style()))
+            expectedXPosition = qreal(4 - 11);
+#endif
+        QCOMPARE(proxyChild->pos().x(), expectedXPosition);
+        menu->hide();
+    }
+}
+
+void tst_QGraphicsProxyWidget::autoShow()
+{
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+
+    QGraphicsProxyWidget *proxy1 = scene.addWidget(new QPushButton("Button1"));
+
+    QPushButton *button2 = new QPushButton("Button2");
+    button2->hide();
+    QGraphicsProxyWidget *proxy2 = new QGraphicsProxyWidget();
+    proxy2->setWidget(button2);
+    scene.addItem(proxy2);
+
+    view.show();
+    QApplication::processEvents();
+
+    QCOMPARE(proxy1->isVisible(), true);
+    QCOMPARE(proxy2->isVisible(), false);
+
+}
+
+Q_DECLARE_METATYPE(QList<QRectF>)
+void tst_QGraphicsProxyWidget::windowOpacity()
+{
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+
+    QWidget *widget = new QWidget;
+    widget->resize(100, 100);
+    QGraphicsProxyWidget *proxy = scene.addWidget(widget);
+    proxy->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    QApplication::sendPostedEvents();
+    QTest::qWait(150);
+
+    qRegisterMetaType<QList<QRectF> >("QList<QRectF>");
+    QSignalSpy signalSpy(&scene, SIGNAL(changed(const QList<QRectF> &)));
+
+    EventSpy eventSpy(widget);
+    QVERIFY(widget->isVisible());
+
+    widget->setWindowOpacity(0.5);
+    QApplication::processEvents();
+
+    // Make sure setWindowOpacity triggers an update on the scene,
+    // and not on the widget or the proxy itself. The entire proxy needs an update
+    // in case it has a window decoration. Update: QGraphicsItem::CacheMode is
+    // disabled on platforms without alpha channel support in QPixmap (e.g.,
+    // X11 without XRender).
+    int paints = 0;
+#ifdef Q_WS_X11
+    paints = !X11->use_xrender;
+#endif
+    QTRY_COMPARE(eventSpy.counts[QEvent::UpdateRequest], 0);
+    QTRY_COMPARE(eventSpy.counts[QEvent::Paint], paints);
+
+    QCOMPARE(signalSpy.count(), 1);
+    const QList<QVariant> arguments = signalSpy.takeFirst();
+    const QList<QRectF> updateRects = qvariant_cast<QList<QRectF> >(arguments.at(0));
+    QCOMPARE(updateRects.size(), 1);
+    QCOMPARE(updateRects.at(0), proxy->sceneBoundingRect());
+}
+
+void tst_QGraphicsProxyWidget::stylePropagation()
+{
+    QPointer<QWindowsStyle> windowsStyle = new QWindowsStyle;
+
+    QLineEdit *edit = new QLineEdit;
+    QGraphicsProxyWidget proxy;
+    proxy.setWidget(edit);
+
+    EventSpy editSpy(edit);
+    EventSpy proxySpy(&proxy);
+
+    // Widget to proxy
+    QCOMPARE(proxy.style(), QApplication::style());
+    edit->setStyle(windowsStyle);
+    QCOMPARE(editSpy.counts[QEvent::StyleChange], 1);
+    QCOMPARE(proxySpy.counts[QEvent::StyleChange], 1);
+    QCOMPARE(proxy.style(), (QStyle *)windowsStyle);
+    edit->setStyle(0);
+    QCOMPARE(editSpy.counts[QEvent::StyleChange], 2);
+    QCOMPARE(proxySpy.counts[QEvent::StyleChange], 2);
+    QCOMPARE(proxy.style(), QApplication::style());
+    QCOMPARE(edit->style(), QApplication::style());
+    QVERIFY(windowsStyle); // not deleted
+
+    // Proxy to widget
+    proxy.setStyle(windowsStyle);
+    QCOMPARE(editSpy.counts[QEvent::StyleChange], 3);
+    QCOMPARE(proxySpy.counts[QEvent::StyleChange], 3);
+    QCOMPARE(edit->style(), (QStyle *)windowsStyle);
+    proxy.setStyle(0);
+    QCOMPARE(editSpy.counts[QEvent::StyleChange], 4);
+    QCOMPARE(proxySpy.counts[QEvent::StyleChange], 4);
+    QCOMPARE(proxy.style(), QApplication::style());
+    QCOMPARE(edit->style(), QApplication::style());
+    QVERIFY(windowsStyle); // not deleted
+
+    delete windowsStyle;
+}
+
+void tst_QGraphicsProxyWidget::palettePropagation()
+{
+    // Construct a palette with an unlikely setup
+    QPalette lineEditPalette = QApplication::palette("QLineEdit");
+    QPalette palette = lineEditPalette;
+    palette.setBrush(QPalette::Text, Qt::red);
+
+    QLineEdit *edit = new QLineEdit;
+    QGraphicsProxyWidget proxy;
+    proxy.setWidget(edit);
+
+    EventSpy editSpy(edit);
+    EventSpy proxySpy(&proxy);
+
+    // Widget to proxy (no change)
+    QVERIFY(!edit->testAttribute(Qt::WA_SetPalette));
+    edit->setPalette(palette);
+    QCOMPARE(editSpy.counts[QEvent::PaletteChange], 1);
+    QCOMPARE(proxySpy.counts[QEvent::PaletteChange], 0);
+    QVERIFY(edit->testAttribute(Qt::WA_SetPalette));
+    QVERIFY(!proxy.testAttribute(Qt::WA_SetPalette));
+    QCOMPARE(proxy.palette(), QPalette());
+    edit->setPalette(QPalette());
+    QCOMPARE(editSpy.counts[QEvent::PaletteChange], 2);
+    QCOMPARE(proxySpy.counts[QEvent::PaletteChange], 0);
+    QVERIFY(!edit->testAttribute(Qt::WA_SetPalette));
+    QVERIFY(!proxy.testAttribute(Qt::WA_SetPalette));
+    QCOMPARE(proxy.palette(), QPalette());
+
+    // Proxy to widget
+    proxy.setPalette(palette);
+    QVERIFY(proxy.testAttribute(Qt::WA_SetPalette));
+    QCOMPARE(editSpy.counts[QEvent::PaletteChange], 3);
+    QCOMPARE(proxySpy.counts[QEvent::PaletteChange], 1);
+    QVERIFY(!edit->testAttribute(Qt::WA_SetPalette));
+    QCOMPARE(edit->palette(), palette);
+    QCOMPARE(edit->palette(), proxy.palette());
+    QCOMPARE(edit->palette().color(QPalette::Text), QColor(Qt::red));
+    proxy.setPalette(QPalette());
+    QVERIFY(!proxy.testAttribute(Qt::WA_SetPalette));
+    QVERIFY(!edit->testAttribute(Qt::WA_SetPalette));
+    QCOMPARE(editSpy.counts[QEvent::PaletteChange], 4);
+    QCOMPARE(proxySpy.counts[QEvent::PaletteChange], 2);
+    QCOMPARE(edit->palette(), lineEditPalette);
+}
+
+void tst_QGraphicsProxyWidget::fontPropagation()
+{
+    // Construct a font with an unlikely setup
+    QGraphicsScene scene;
+    QFont lineEditFont = QApplication::font("QLineEdit");
+    QFont font = lineEditFont;
+    font.setPointSize(43);
+
+    QLineEdit *edit = new QLineEdit;
+    QGraphicsProxyWidget proxy;
+    proxy.setWidget(edit);
+
+    scene.addItem(&proxy);
+    EventSpy editSpy(edit);
+    EventSpy proxySpy(&proxy);
+
+    // Widget to proxy (no change)
+    QVERIFY(!edit->testAttribute(Qt::WA_SetFont));
+    edit->setFont(font);
+    QCOMPARE(editSpy.counts[QEvent::FontChange], 1);
+    QCOMPARE(proxySpy.counts[QEvent::FontChange], 0);
+    QVERIFY(edit->testAttribute(Qt::WA_SetFont));
+    QVERIFY(!proxy.testAttribute(Qt::WA_SetFont));
+    QCOMPARE(proxy.font(), lineEditFont);
+    edit->setFont(QFont());
+    QCOMPARE(editSpy.counts[QEvent::FontChange], 2);
+    QCOMPARE(proxySpy.counts[QEvent::FontChange], 0);
+    QVERIFY(!edit->testAttribute(Qt::WA_SetFont));
+    QVERIFY(!proxy.testAttribute(Qt::WA_SetFont));
+    QCOMPARE(proxy.font(), lineEditFont);
+
+    // Proxy to widget
+    proxy.setFont(font);
+    QApplication::processEvents();  // wait for QEvent::Polish
+    QVERIFY(proxy.testAttribute(Qt::WA_SetFont));
+    QCOMPARE(editSpy.counts[QEvent::FontChange], 3);
+    QCOMPARE(proxySpy.counts[QEvent::FontChange], 1);
+    QVERIFY(!edit->testAttribute(Qt::WA_SetFont));
+    QCOMPARE(edit->font(), font);
+    QCOMPARE(edit->font(), proxy.font());
+    QCOMPARE(edit->font().pointSize(), 43);
+    proxy.setFont(QFont());
+    QVERIFY(!proxy.testAttribute(Qt::WA_SetFont));
+    QVERIFY(!edit->testAttribute(Qt::WA_SetFont));
+    QCOMPARE(editSpy.counts[QEvent::FontChange], 4);
+    QCOMPARE(proxySpy.counts[QEvent::FontChange], 2);
+    QCOMPARE(edit->font(), lineEditFont);
+
+    proxy.setFont(font);
+    QLineEdit *edit2 = new QLineEdit;
+    proxy.setWidget(edit2);
+    delete edit;
+    QCOMPARE(edit2->font().pointSize(), 43);
+}
+
+class MainWidget : public QMainWindow
+{
+Q_OBJECT
+public:
+    MainWidget() : QMainWindow() {
+      view = new QGraphicsView(this);
+      scene = new QGraphicsScene(this);
+      item = new QGraphicsWidget();
+      widget = new QGraphicsProxyWidget(item);
+      layout = new QGraphicsLinearLayout(item);
+      layout->addItem(widget);
+      item->setLayout(layout);
+      button = new QPushButton("Push me");
+      widget->setWidget(button);
+      setCentralWidget(view);
+      scene->addItem(item);
+      view->setScene(scene);
+      scene->setFocusItem(item);
+      layout->activate();
+    }
+    QGraphicsView* view;
+    QGraphicsScene* scene;
+    QGraphicsWidget * item;
+    QGraphicsLinearLayout * layout;
+    QGraphicsProxyWidget * widget;
+    QPushButton * button;
+};
+
+void tst_QGraphicsProxyWidget::dontCrashWhenDie()
+{
+    MainWidget *w = new MainWidget();
+    w->show();
+    QTest::qWaitForWindowShown(w);
+    QTest::qWait(100);
+    QTest::mouseMove(w->view->viewport(), w->view->mapFromScene(w->widget->mapToScene(w->widget->boundingRect().center())));
+    delete w->item;
+
+    QApplication::processEvents();
+    delete w;
+}
+
+void tst_QGraphicsProxyWidget::createProxyForChildWidget()
+{
+    QGraphicsScene scene;
+
+    QLineEdit *edit1 = new QLineEdit;
+    edit1->setText("QLineEdit 1");
+    QLineEdit *edit2 = new QLineEdit;
+    edit2->setText("QLineEdit 2");
+    QCheckBox *checkbox = new QCheckBox("QCheckBox");
+    QVBoxLayout *vlayout = new QVBoxLayout;
+
+    vlayout->addWidget(edit1);
+    vlayout->addWidget(edit2);
+    vlayout->addWidget(checkbox);
+    vlayout->insertStretch(-1);
+
+    QGroupBox *box = new QGroupBox("QGroupBox");
+    box->setCheckable(true);
+    box->setChecked(true);
+    box->setLayout(vlayout);
+
+    QDial *leftDial = new QDial;
+    QDial *rightDial = new QDial;
+
+    QWidget window;
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->addWidget(leftDial);
+    layout->addWidget(box);
+    layout->addWidget(rightDial);
+    window.setLayout(layout);
+
+    QVERIFY(window.graphicsProxyWidget() == 0);
+    QVERIFY(checkbox->graphicsProxyWidget() == 0);
+
+    QGraphicsProxyWidget *windowProxy = scene.addWidget(&window);
+    QGraphicsView view(&scene);
+    view.show();
+    view.resize(500,500);
+
+    QVERIFY(window.graphicsProxyWidget() == windowProxy);
+    QVERIFY(box->graphicsProxyWidget() == 0);
+    QVERIFY(checkbox->graphicsProxyWidget() == 0);
+
+    QPointer<QGraphicsProxyWidget> checkboxProxy = windowProxy->createProxyForChildWidget(checkbox);
+
+    QGraphicsProxyWidget *boxProxy = box->graphicsProxyWidget();
+
+    QVERIFY(boxProxy);
+    QVERIFY(checkbox->graphicsProxyWidget() == checkboxProxy);
+    QVERIFY(checkboxProxy->parentItem() == boxProxy);
+    QVERIFY(boxProxy->parentItem() == windowProxy);
+
+    QVERIFY(checkboxProxy->mapToScene(QPointF()) == checkbox->mapTo(&window, QPoint()));
+    QVERIFY(checkboxProxy->size() == checkbox->size());
+    QVERIFY(boxProxy->size() == box->size());
+
+    window.resize(500,500);
+    QVERIFY(windowProxy->size() == QSize(500,500));
+    QVERIFY(checkboxProxy->mapToScene(QPointF()) == checkbox->mapTo(&window, QPoint()));
+    QVERIFY(checkboxProxy->size() == checkbox->size());
+    QVERIFY(boxProxy->size() == box->size());
+
+    QTest::qWait(10);
+
+
+    QSignalSpy spy(checkbox, SIGNAL(clicked()));
+
+    QTest::mousePress(view.viewport(), Qt::LeftButton, 0,
+                      view.mapFromScene(checkboxProxy->mapToScene(QPointF(8,8))));
+    QTRY_COMPARE(spy.count(), 0);
+    QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0,
+                        view.mapFromScene(checkboxProxy->mapToScene(QPointF(8,8))));
+    QTRY_COMPARE(spy.count(), 1);
+
+
+
+    boxProxy->setWidget(0);
+
+    QVERIFY(checkbox->graphicsProxyWidget() == 0);
+    QVERIFY(box->graphicsProxyWidget() == 0);
+    QVERIFY(checkboxProxy == 0);
+
+    delete boxProxy;
+}
+
+class ContextMenuWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    ContextMenuWidget()
+        : embeddedPopup(false),
+          gotContextMenuEvent(false)
+    { }
+    bool embeddedPopup;
+    bool gotContextMenuEvent;
+protected:
+    bool event(QEvent *event)
+    {
+        if (event->type() == QEvent::ContextMenu)
+            QTimer::singleShot(0, this, SLOT(checkMenu()));
+        return QWidget::event(event);
+    }
+    void contextMenuEvent(QContextMenuEvent *)
+    {
+        gotContextMenuEvent = true;
+    }
+
+private slots:
+    void checkMenu()
+    {
+        if (qFindChild<QMenu *>(this))
+            embeddedPopup = true;
+        hide();
+    }
+};
+
+void tst_QGraphicsProxyWidget::actionsContextMenu_data()
+{
+    QTest::addColumn<bool>("actionsContextMenu");
+    QTest::addColumn<bool>("hasFocus");
+
+    QTest::newRow("without actionsContextMenu and with focus") << false << true;
+    QTest::newRow("without actionsContextMenu and without focus") << false << false;
+    QTest::newRow("with actionsContextMenu and focus") << true << true;
+    QTest::newRow("with actionsContextMenu without focus") << true << false;
+}
+
+void tst_QGraphicsProxyWidget::actionsContextMenu()
+{
+    QFETCH(bool, hasFocus);
+    QFETCH(bool, actionsContextMenu);
+
+    ContextMenuWidget *widget = new ContextMenuWidget;
+    if (actionsContextMenu) {
+        widget->addAction(new QAction("item 1", widget));
+        widget->addAction(new QAction("item 2", widget));
+        widget->addAction(new QAction("item 3", widget));
+        widget->setContextMenuPolicy(Qt::ActionsContextMenu);
+    }
+    QGraphicsScene scene;
+
+    QGraphicsView view(&scene);
+    view.show();
+    QApplication::setActiveWindow(&view);
+    QTest::qWaitForWindowShown(&view);
+    view.setFocus();
+    QTRY_VERIFY(view.hasFocus());
+
+    if (hasFocus)
+        scene.addWidget(widget)->setFocus();
+    else
+        scene.addWidget(widget)->clearFocus();
+
+    QApplication::processEvents();
+
+    QContextMenuEvent contextMenuEvent(QContextMenuEvent::Mouse,
+                                       view.viewport()->rect().center(),
+                                       view.viewport()->mapToGlobal(view.viewport()->rect().center()));
+    contextMenuEvent.accept();
+    qApp->sendEvent(view.viewport(), &contextMenuEvent);
+
+    if (hasFocus) {
+        if (actionsContextMenu) {
+            //actionsContextMenu embedded popup but no contextMenuEvent (widget has focus)
+            QVERIFY(widget->embeddedPopup);
+            QVERIFY(!widget->gotContextMenuEvent);
+        } else {
+            //no embedded popup but contextMenuEvent (widget has focus)
+            QVERIFY(!widget->embeddedPopup);
+            QVERIFY(widget->gotContextMenuEvent);
+        }
+    } else {
+        //qgraphicsproxywidget doesn't have the focus, the widget must not receive any contextMenuEvent and must not create any QMenu
+        QVERIFY(!widget->embeddedPopup);
+        QVERIFY(!widget->gotContextMenuEvent);
+    }
+
+}
+
+
+void tst_QGraphicsProxyWidget::deleteProxyForChildWidget()
+{
+    QDialog dialog;
+    dialog.resize(320, 120);
+    dialog.move(80, 40);
+
+    QGraphicsScene scene;
+    scene.setSceneRect(QRectF(0, 0, 640, 480));
+    QGraphicsView view(&scene);
+    QComboBox *combo = new QComboBox;
+    combo->addItems(QStringList() << "red" << "green" << "blue" << "white" << "black" << "yellow" << "cyan" << "magenta");
+    dialog.setLayout(new QVBoxLayout);
+    dialog.layout()->addWidget(combo);
+
+    QGraphicsProxyWidget *proxy = scene.addWidget(&dialog);
+    view.show();
+
+    proxy->setWidget(0);
+    //just don't crash
+    QApplication::processEvents();
+    delete combo;
+}
+
+void tst_QGraphicsProxyWidget::bypassGraphicsProxyWidget_data()
+{
+    QTest::addColumn<bool>("bypass");
+
+    QTest::newRow("autoembed") << false;
+    QTest::newRow("bypass") << true;
+}
+
+void tst_QGraphicsProxyWidget::bypassGraphicsProxyWidget()
+{
+    QFETCH(bool, bypass);
+
+    QWidget *widget = new QWidget;
+    widget->resize(100, 100);
+
+    QGraphicsScene scene;
+    QGraphicsView view(&scene);
+    view.show();
+
+    QGraphicsProxyWidget *proxy = scene.addWidget(widget);
+
+    QCOMPARE(proxy->widget(), widget);
+    QVERIFY(proxy->childItems().isEmpty());
+
+    Qt::WindowFlags flags;
+    flags |= Qt::Dialog;
+    if (bypass)
+        flags |= Qt::BypassGraphicsProxyWidget;
+    QFileDialog *dialog = new QFileDialog(widget, flags);
+    dialog->setOption(QFileDialog::DontUseNativeDialog, true);
+    dialog->show();
+
+    QCOMPARE(proxy->childItems().size(), bypass ? 0 : 1);
+    if (!bypass)
+        QCOMPARE(((QGraphicsProxyWidget *)proxy->childItems().first())->widget(), (QWidget *)dialog);
+
+    dialog->hide();
+    QApplication::processEvents();
+    delete dialog;
+    delete widget;
+}
+
+static void makeDndEvent(QGraphicsSceneDragDropEvent *event, QGraphicsView *view, const QPointF &pos)
+{
+    event->setScenePos(pos);
+    event->setScreenPos(view->mapToGlobal(view->mapFromScene(pos)));
+    event->setButtons(Qt::LeftButton);
+    event->setModifiers(0);
+    event->setPossibleActions(Qt::CopyAction);
+    event->setProposedAction(Qt::CopyAction);
+    event->setDropAction(Qt::CopyAction);
+    event->setWidget(view->viewport());
+    event->setSource(view->viewport());
+    event->ignore();
+}
+
+void tst_QGraphicsProxyWidget::dragDrop()
+{
+    QPushButton *button = new QPushButton; // acceptDrops(false)
+    QLineEdit *edit = new QLineEdit; // acceptDrops(true)
+
+    QGraphicsScene scene;
+    QGraphicsProxyWidget *buttonProxy = scene.addWidget(button);
+    QGraphicsProxyWidget *editProxy = scene.addWidget(edit);
+    QVERIFY(buttonProxy->acceptDrops());
+    QVERIFY(editProxy->acceptDrops());
+
+    button->setGeometry(0, 0, 100, 50);
+    edit->setGeometry(0, 60, 100, 50);
+
+    QGraphicsView view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+
+    QMimeData data;
+    data.setText("hei");
+    {
+        QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragEnter);
+        makeDndEvent(&event, &view, QPointF(50, 25));
+        event.setMimeData(&data);
+        qApp->sendEvent(&scene, &event);
+        QVERIFY(event.isAccepted());
+    }
+    {
+        QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragMove);
+        makeDndEvent(&event, &view, QPointF(50, 25));
+        event.setMimeData(&data);
+        qApp->sendEvent(&scene, &event);
+        QVERIFY(!event.isAccepted());
+    }
+    {
+        QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragMove);
+        makeDndEvent(&event, &view, QPointF(50, 75));
+        event.setMimeData(&data);
+        qApp->sendEvent(&scene, &event);
+        QVERIFY(event.isAccepted());
+    }
+    {
+        QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDrop);
+        makeDndEvent(&event, &view, QPointF(50, 75));
+        event.setMimeData(&data);
+        qApp->sendEvent(&scene, &event);
+        QVERIFY(event.isAccepted());
+    }
+    QCOMPARE(edit->text(), QString("hei"));
+}
+
+void tst_QGraphicsProxyWidget::windowFlags_data()
+{
+    QTest::addColumn<int>("proxyFlags");
+    QTest::addColumn<int>("widgetFlags");
+    QTest::addColumn<int>("resultingProxyFlags");
+    QTest::addColumn<int>("resultingWidgetFlags");
+
+    QTest::newRow("proxy(0) widget(0)") << 0 << 0 << 0 << int(Qt::Window);
+    QTest::newRow("proxy(window)") << int(Qt::Window) << 0 << int(Qt::Window) << int(Qt::Window);
+    QTest::newRow("proxy(window) widget(window)") << int(Qt::Window) << int(Qt::Window) << int(Qt::Window) << int(Qt::Window);
+    QTest::newRow("proxy(0) widget(window)") << int(0) << int(Qt::Window) << int(0) << int(Qt::Window);
+}
+
+void tst_QGraphicsProxyWidget::windowFlags()
+{
+    QFETCH(int, proxyFlags);
+    QFETCH(int, widgetFlags);
+    QFETCH(int, resultingProxyFlags);
+    QFETCH(int, resultingWidgetFlags);
+    Qt::WindowFlags proxyWFlags = Qt::WindowFlags(proxyFlags);
+    Qt::WindowFlags widgetWFlags = Qt::WindowFlags(widgetFlags);
+    Qt::WindowFlags resultingProxyWFlags = Qt::WindowFlags(resultingProxyFlags);
+    Qt::WindowFlags resultingWidgetWFlags = Qt::WindowFlags(resultingWidgetFlags);
+
+    QGraphicsProxyWidget proxy(0, proxyWFlags);
+    QVERIFY((proxy.windowFlags() & proxyWFlags) == proxyWFlags);
+
+    QWidget *widget = new QWidget(0, widgetWFlags);
+    QVERIFY((widget->windowFlags() & widgetWFlags) == widgetWFlags);
+
+    proxy.setWidget(widget);
+
+    if (resultingProxyFlags == 0)
+        QVERIFY(!proxy.windowFlags());
+    else
+        QVERIFY((proxy.windowFlags() & resultingProxyWFlags) == resultingProxyWFlags);
+    QVERIFY((widget->windowFlags() & resultingWidgetWFlags) == resultingWidgetWFlags);
+}
+
+void tst_QGraphicsProxyWidget::comboboxWindowFlags()
+{
+    QComboBox *comboBox = new QComboBox;
+    comboBox->addItem("Item 1");
+    comboBox->addItem("Item 2");
+    comboBox->addItem("Item 3");
+    QWidget *embedWidget = comboBox;
+
+    QGraphicsScene scene;
+    QGraphicsProxyWidget *proxy = scene.addWidget(embedWidget);
+    proxy->setWindowFlags(Qt::Window);
+    QVERIFY(embedWidget->isWindow());
+    QVERIFY(proxy->isWindow());
+
+    comboBox->showPopup();
+
+    QCOMPARE(proxy->childItems().size(), 1);
+    QGraphicsItem *popupProxy = proxy->childItems().first();
+    QVERIFY(popupProxy->isWindow());
+    QVERIFY((static_cast<QGraphicsWidget *>(popupProxy)->windowFlags() & Qt::Popup) == Qt::Popup);
+}
+
+void tst_QGraphicsProxyWidget::updateAndDelete()
+{
+    QGraphicsScene scene;
+    QGraphicsProxyWidget *proxy = scene.addWidget(new QPushButton("Hello World"));
+    View view(&scene);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(20);
+    QTRY_VERIFY(view.npaints > 0);
+
+    const QRect itemDeviceBoundingRect = proxy->deviceTransform(view.viewportTransform())
+                                         .mapRect(proxy->boundingRect()).toRect();
+    const QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
+
+    view.npaints = 0;
+    view.paintEventRegion = QRegion();
+
+    // Update and hide.
+    proxy->update();
+    proxy->hide();
+    QTest::qWait(50);
+    QCOMPARE(view.npaints, 1);
+    QCOMPARE(view.paintEventRegion, expectedRegion);
+
+    proxy->show();
+    QTest::qWait(50);
+    view.npaints = 0;
+    view.paintEventRegion = QRegion();
+
+    // Update and delete.
+    proxy->update();
+    delete proxy;
+    QTest::qWait(50);
+    QCOMPARE(view.npaints, 1);
+    QCOMPARE(view.paintEventRegion, expectedRegion);
+}
+
+class InputMethod_LineEdit : public QLineEdit
+{
+    bool event(QEvent *e)
+    {
+        if (e->type() == QEvent::InputMethod)
+            ++inputMethodEvents;
+        return QLineEdit::event(e);
+    }
+public:
+    int inputMethodEvents;
+};
+
+void tst_QGraphicsProxyWidget::inputMethod()
+{
+    QGraphicsScene scene;
+
+    // check that the proxy is initialized with the correct input method sensitivity
+    for (int i = 0; i < 2; ++i)
+    {
+        QLineEdit *lineEdit = new QLineEdit;
+        lineEdit->setAttribute(Qt::WA_InputMethodEnabled, !!i);
+        QGraphicsProxyWidget *proxy = scene.addWidget(lineEdit);
+        QCOMPARE(!!(proxy->flags() & QGraphicsItem::ItemAcceptsInputMethod), !!i);
+    }
+
+    // check that input method events are only forwarded to widgets with focus
+    for (int i = 0; i < 2; ++i)
+    {
+        InputMethod_LineEdit *lineEdit = new InputMethod_LineEdit;
+        lineEdit->setAttribute(Qt::WA_InputMethodEnabled, true);
+        QGraphicsProxyWidget *proxy = scene.addWidget(lineEdit);
+
+        if (i)
+            lineEdit->setFocus();
+
+        lineEdit->inputMethodEvents = 0;
+        QInputMethodEvent event;
+        qApp->sendEvent(proxy, &event);
+        QCOMPARE(lineEdit->inputMethodEvents, i);
+    }
+}
+
+void tst_QGraphicsProxyWidget::clickFocus()
+{
+    QGraphicsScene scene;
+    scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+    QGraphicsProxyWidget *proxy = scene.addWidget(new QLineEdit);
+
+    EventSpy proxySpy(proxy);
+    EventSpy widgetSpy(proxy->widget());
+
+    QGraphicsView view(&scene);
+    view.setFrameStyle(0);
+    view.resize(300, 300);
+    view.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QApplication::setActiveWindow(&view);
+    QTest::qWait(25);
+    QTRY_COMPARE(QApplication::activeWindow(), &view);
+
+    QVERIFY(!proxy->hasFocus());
+    QVERIFY(!proxy->widget()->hasFocus());
+
+    QCOMPARE(proxySpy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(proxySpy.counts[QEvent::FocusOut], 0);
+    QCOMPARE(widgetSpy.counts[QEvent::FocusIn], 0);
+    QCOMPARE(widgetSpy.counts[QEvent::FocusOut], 0);
+
+    QPointF lineEditCenter = proxy->mapToScene(proxy->boundingRect().center());
+    // Spontaneous mouse click sets focus on a clickable widget.
+    for (int retry = 0; retry < 50 && !proxy->hasFocus(); retry++)
+        QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(lineEditCenter));
+    QVERIFY(proxy->hasFocus());
+    QVERIFY(proxy->widget()->hasFocus());
+    QCOMPARE(proxySpy.counts[QEvent::FocusIn], 1);
+    QCOMPARE(widgetSpy.counts[QEvent::FocusIn], 1);
+
+    scene.setFocusItem(0);
+    QVERIFY(!proxy->hasFocus());
+    QVERIFY(!proxy->widget()->hasFocus());
+    QCOMPARE(proxySpy.counts[QEvent::FocusOut], 1);
+    QCOMPARE(widgetSpy.counts[QEvent::FocusOut], 1);
+
+    // Non-spontaneous mouse click sets focus if the widget has been clicked before
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+        event.setScenePos(lineEditCenter);
+        event.setButton(Qt::LeftButton);
+        qApp->sendEvent(&scene, &event);
+        QVERIFY(proxy->hasFocus());
+        QVERIFY(proxy->widget()->hasFocus());
+        QCOMPARE(proxySpy.counts[QEvent::FocusIn], 2);
+        QCOMPARE(widgetSpy.counts[QEvent::FocusIn], 2);
+    }
+
+    scene.setFocusItem(0);
+    proxy->setWidget(new QLineEdit); // resets focusWidget
+    QVERIFY(!proxy->hasFocus());
+    QVERIFY(!proxy->widget()->hasFocus());
+    QCOMPARE(proxySpy.counts[QEvent::FocusOut], 2);
+    QCOMPARE(widgetSpy.counts[QEvent::FocusOut], 2);
+
+    // Non-spontaneous mouse click does not set focus on the embedded widget.
+    {
+        QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+        event.setScenePos(lineEditCenter);
+        event.setButton(Qt::LeftButton);
+        qApp->sendEvent(&scene, &event);
+        QVERIFY(!proxy->hasFocus());
+        QVERIFY(!proxy->widget()->hasFocus());
+        QCOMPARE(proxySpy.counts[QEvent::FocusIn], 2);
+        QCOMPARE(widgetSpy.counts[QEvent::FocusIn], 2);
+    }
+
+    scene.setFocusItem(0);
+    QVERIFY(!proxy->hasFocus());
+    QVERIFY(!proxy->widget()->hasFocus());
+    QCOMPARE(proxySpy.counts[QEvent::FocusOut], 2);
+    QCOMPARE(widgetSpy.counts[QEvent::FocusOut], 2);
+
+    // Spontaneous click on non-clickable widget does not give focus.
+    proxy->widget()->setFocusPolicy(Qt::NoFocus);
+    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(lineEditCenter));
+    QVERIFY(!proxy->hasFocus());
+    QVERIFY(!proxy->widget()->hasFocus());
+}
+
+QTEST_MAIN(tst_QGraphicsProxyWidget)
+#include "tst_qgraphicsproxywidget.moc"
+
+#else // QT_NO_STYLE_CLEANLOOKS
+QTEST_NOOP_MAIN
+#endif