summaryrefslogtreecommitdiffstats
path: root/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp')
-rw-r--r--tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp4715
1 files changed, 4715 insertions, 0 deletions
diff --git a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp
new file mode 100644
index 0000000000..9ff086c425
--- /dev/null
+++ b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp
@@ -0,0 +1,4715 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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>
+#if defined(Q_OS_WINCE)
+#include <ceconfig.h>
+#endif
+
+#include <QtGui>
+#include <private/qgraphicsscene_p.h>
+#include <private/qgraphicssceneindex_p.h>
+#include <math.h>
+#include "../../shared/util.h"
+#include "../qpathclipper/pathcompare.h"
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+#include <windows.h>
+#define Q_CHECK_PAINTEVENTS \
+ if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \
+ QSKIP("The Graphics View doesn't get the paint events", SkipSingle);
+#else
+#define Q_CHECK_PAINTEVENTS
+#endif
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+// Current path (C:\private\<UID>) contains only ascii chars
+#define SRCDIR QDir::currentPath().append("\\").toAscii()
+#endif
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<QRectF>)
+Q_DECLARE_METATYPE(QMatrix)
+Q_DECLARE_METATYPE(QPainterPath)
+Q_DECLARE_METATYPE(QPointF)
+Q_DECLARE_METATYPE(QRectF)
+Q_DECLARE_METATYPE(Qt::AspectRatioMode)
+Q_DECLARE_METATYPE(Qt::ItemSelectionMode)
+
+static const int randomX[] = {276, 40, 250, 864, -56, 426, 855, 825, 184, 955, -798, -804, 773,
+ 282, 489, 686, 780, -220, 50, 749, -856, -205, 81, 492, -819, 518,
+ 895, 57, -559, 788, -965, 68, -442, -247, -339, -648, 292, 891,
+ -865, 462, 864, 673, 640, 523, 194, 500, -727, 307, -243, 320,
+ -545, 415, 448, 341, -619, 652, 892, -16, -14, -659, -101, -934,
+ 532, 356, 824, 132, 160, 130, 104, 886, -179, -174, 543, -644, 60,
+ -470, -354, -728, 689, 682, -587, -694, -221, -741, 37, 372, -289,
+ 741, -300, 858, -320, 729, -602, -956, -544, -403, 203, 398, 284,
+ -972, -572, -946, 81, 51, -403, -580, 867, 546, 565, -580, -484,
+ 659, 982, -518, -976, 423, -800, 659, -297, 712, 938, -19, -16,
+ 824, -252, 197, 321, -837, 824, 136, 226, -980, -909, -826, -479,
+ -835, -503, -828, -901, -810, -641, -548, -179, 194, 749, -296, 539,
+ -37, -599, -235, 121, 35, -230, -915, 789, 764, -622, -382, -90, -701,
+ 676, -407, 998, 267, 913, 817, -748, -370, -162, -797, 19, -556, 933,
+ -670, -101, -765, -941, -17, 360, 31, 960, 509, 933, -35, 974, -924,
+ -734, 589, 963, 724, 794, 843, 16, -272, -811, 721, 99, -122, 216,
+ -404, 158, 787, -443, -437, -337, 383, -342, 538, -641, 791, 637,
+ -848, 397, 820, 109, 11, 45, 809, 591, 933, 961, 625, -140, -592,
+ -694, -969, 317, 293, 777, -18, -282, 835, -455, -708, -407, -204,
+ 748, 347, -501, -545, 292, -362, 176, 546, -573, -38, -854, -395,
+ 560, -624, -940, -971, 66, -910, 782, 985};
+
+static const int randomY[] = {603, 70, -318, 843, 450, -637, 199, -527, 407, 964, -54, 620, -207,
+ -736, -700, -476, -706, -142, 837, 621, 522, -98, 232, 292, -267, 900,
+ 615, -356, -415, 783, 290, 462, -857, -314, 677, 36, 772, 424, -72,
+ -121, 547, -533, 537, -656, 289, 508, 914, 601, 434, 588, -779, -714,
+ -368, 628, -276, 432, -1, -929, 638, -36, 253, -922, -943, 979, -34,
+ -268, -193, 601, 686, -330, 165, 98, 75, -691, -605, 617, 773, 617,
+ 619, 238, -42, -405, 17, 384, -472, -846, 520, 110, 591, -217, 936,
+ -373, 731, 734, 810, 961, 881, 939, 379, -905, -137, 437, 298, 688,
+ -71, -204, 573, -120, -821, 489, -722, -926, 529, -113, -243, 543,
+ 868, -301, -781, -549, -842, -489, -80, -910, -928, 51, -91, 324,
+ 204, -92, 867, 723, 248, 709, -357, 591, -365, -379, 266, -649, -95,
+ 205, 551, 355, -631, 79, -186, 795, -7, -225, 46, -410, 665, -874,
+ -618, 845, -548, 443, 471, -644, 606, -607, 59, -619, 288, -244, 529,
+ 690, 349, -738, -611, -879, -642, 801, -178, 823, -748, -552, -247,
+ -223, -408, 651, -62, 949, -795, 171, -107, -210, -207, -842, -86,
+ 436, 528, 366, -178, 245, -695, 665, 613, -948, 667, -620, -979, -949,
+ 905, 181, -412, -467, -437, -774, 750, -10, 54, 205, -674, -290, -924,
+ -361, -463, 912, -702, 622, -542, 220, 115, 832, 451, -38, -952, -230,
+ -588, 864, 234, 225, -303, 493, 246, 153, 338, -378, 377, -819, 140, 136,
+ 467, -849, -326, -533, 166, 252, -994, -699, 904, -566, 621, -752};
+
+class HoverItem : public QGraphicsRectItem
+{
+public:
+ HoverItem()
+ : QGraphicsRectItem(QRectF(-10, -10, 20, 20)), isHovered(false)
+ { setAcceptsHoverEvents(true); }
+
+ bool isHovered;
+
+protected:
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
+ {
+ isHovered = (option->state & QStyle::State_MouseOver);
+
+ painter->setOpacity(0.75);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(Qt::darkGray);
+ painter->drawRoundRect(boundingRect().adjusted(3, 3, -3, -3), Qt::darkGray);
+ painter->setPen(Qt::black);
+ if (isHovered) {
+ painter->setBrush(QColor(Qt::blue).light(120));
+ } else {
+ painter->setBrush(Qt::gray);
+ }
+ painter->drawRoundRect(boundingRect().adjusted(0, 0, -5, -5));
+ }
+};
+
+class EventSpy : public QGraphicsWidget
+{
+ Q_OBJECT
+public:
+ EventSpy(QObject *watched, QEvent::Type type)
+ : _count(0), spied(type)
+ {
+ watched->installEventFilter(this);
+ }
+
+ EventSpy(QGraphicsScene *scene, QGraphicsItem *watched, QEvent::Type type)
+ : _count(0), spied(type)
+ {
+ scene->addItem(this);
+ watched->installSceneEventFilter(this);
+ }
+
+ int count() const { return _count; }
+
+protected:
+ bool eventFilter(QObject *watched, QEvent *event)
+ {
+ Q_UNUSED(watched);
+ if (event->type() == spied)
+ ++_count;
+ return false;
+ }
+
+ bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+ {
+ Q_UNUSED(watched);
+ if (event->type() == spied)
+ ++_count;
+ return false;
+ }
+
+ int _count;
+ QEvent::Type spied;
+};
+
+class tst_QGraphicsScene : public QObject
+{
+ Q_OBJECT
+public slots:
+ void initTestCase();
+
+private slots:
+ void construction();
+ void sceneRect();
+ void itemIndexMethod();
+ void bspTreeDepth();
+ void itemsBoundingRect_data();
+ void itemsBoundingRect();
+ void items();
+ void items_QPointF_data();
+ void items_QPointF();
+ void items_QRectF();
+ void items_QRectF_2_data();
+ void items_QRectF_2();
+ void items_QPolygonF();
+ void items_QPolygonF_2();
+ void items_QPainterPath();
+ void items_QPainterPath_2();
+ void selection();
+ void selectionChanged();
+ void selectionChanged2();
+ void addItem();
+ void addEllipse();
+ void addLine();
+ void addPath();
+ void addPixmap();
+ void addRect();
+ void addText();
+ void removeItem();
+ void clear();
+ void focusItem();
+ void focusItemLostFocus();
+ void setFocusItem();
+ void setFocusItem_inactive();
+ void mouseGrabberItem();
+ void hoverEvents_siblings();
+ void hoverEvents_parentChild();
+ void createItemGroup();
+ void mouseEventPropagation();
+ void mouseEventPropagation_ignore();
+ void mouseEventPropagation_focus();
+ void mouseEventPropagation_doubleclick();
+ void mouseEventPropagation_mouseMove();
+#ifndef QT_NO_DRAGANDDROP
+ void dragAndDrop_simple();
+ void dragAndDrop_disabledOrInvisible();
+ void dragAndDrop_propagate();
+#endif
+ void render_data();
+ void render();
+ void renderItemsWithNegativeWidthOrHeight();
+ void contextMenuEvent();
+ void contextMenuEvent_ItemIgnoresTransformations();
+ void update();
+ void update2();
+ void views();
+ void event();
+ void eventsToDisabledItems();
+ void exposedRect();
+ void tabFocus_emptyScene();
+ void tabFocus_sceneWithFocusableItems();
+ void tabFocus_sceneWithFocusWidgets();
+ void tabFocus_sceneWithNestedFocusWidgets();
+ void style();
+ void sorting_data();
+ void sorting();
+ void changedSignal_data();
+ void changedSignal();
+ void stickyFocus_data();
+ void stickyFocus();
+ void sendEvent();
+ void inputMethod_data();
+ void inputMethod();
+ void dispatchHoverOnPress();
+ void initialFocus_data();
+ void initialFocus();
+ void polishItems();
+ void polishItems2();
+ void isActive();
+ void siblingIndexAlwaysValid();
+ void removeFullyTransparentItem();
+ void zeroScale();
+
+ // task specific tests below me
+ void task139710_bspTreeCrash();
+ void task139782_containsItemBoundingRect();
+ void task176178_itemIndexMethodBreaksSceneRect();
+ void task160653_selectionChanged();
+ void task250680_childClip();
+ void taskQTBUG_5904_crashWithDeviceCoordinateCache();
+ void taskQT657_paintIntoCacheWithTransparentParts();
+ void taskQTBUG_7863_paintIntoCacheWithTransparentParts();
+ void taskQT_3674_doNotCrash();
+ void taskQTBUG_15977_renderWithDeviceCoordinateCache();
+ void taskQTBUG_16401_focusItem();
+};
+
+void tst_QGraphicsScene::initTestCase()
+{
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+ qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+void tst_QGraphicsScene::construction()
+{
+ QGraphicsScene scene;
+ QCOMPARE(scene.itemsBoundingRect(), QRectF());
+ QVERIFY(scene.items().isEmpty());
+ QVERIFY(scene.items(QPointF()).isEmpty());
+ QVERIFY(scene.items(QRectF()).isEmpty());
+ QVERIFY(scene.items(QPolygonF()).isEmpty());
+ QVERIFY(scene.items(QPainterPath()).isEmpty());
+ QTest::ignoreMessage(QtWarningMsg, "QGraphicsScene::collidingItems: cannot find collisions for null item");
+ QVERIFY(scene.collidingItems(0).isEmpty());
+ QVERIFY(!scene.itemAt(QPointF()));
+ QVERIFY(scene.selectedItems().isEmpty());
+ QVERIFY(!scene.focusItem());
+}
+
+void tst_QGraphicsScene::sceneRect()
+{
+ QGraphicsScene scene;
+ QSignalSpy sceneRectChanged(&scene, SIGNAL(sceneRectChanged(QRectF)));
+ QCOMPARE(scene.sceneRect(), QRectF());
+ QCOMPARE(sceneRectChanged.count(), 0);
+
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10));
+ item->setPos(-5, -5);
+ QCOMPARE(sceneRectChanged.count(), 0);
+
+ QCOMPARE(scene.itemAt(0, 0), item);
+ QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
+ QCOMPARE(sceneRectChanged.count(), 0);
+ QCOMPARE(scene.sceneRect(), QRectF(-5, -5, 10, 10));
+ QCOMPARE(sceneRectChanged.count(), 1);
+ QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect());
+
+ item->setPos(0, 0);
+ QCOMPARE(scene.sceneRect(), QRectF(-5, -5, 15, 15));
+ QCOMPARE(sceneRectChanged.count(), 2);
+ QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect());
+
+ scene.setSceneRect(-100, -100, 10, 10);
+ QCOMPARE(sceneRectChanged.count(), 3);
+ QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect());
+
+ QCOMPARE(scene.itemAt(0, 0), item);
+ QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
+ QCOMPARE(scene.sceneRect(), QRectF(-100, -100, 10, 10));
+ item->setPos(10, 10);
+ QCOMPARE(scene.sceneRect(), QRectF(-100, -100, 10, 10));
+ QCOMPARE(sceneRectChanged.count(), 3);
+ QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect());
+
+ scene.setSceneRect(QRectF());
+
+ QCOMPARE(scene.itemAt(10, 10), item);
+ QCOMPARE(scene.itemAt(20, 20), (QGraphicsItem *)0);
+ QCOMPARE(sceneRectChanged.count(), 4);
+ QCOMPARE(scene.sceneRect(), QRectF(-5, -5, 25, 25));
+ QCOMPARE(sceneRectChanged.count(), 5);
+ QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect());
+}
+
+void tst_QGraphicsScene::itemIndexMethod()
+{
+ QGraphicsScene scene;
+ QCOMPARE(scene.itemIndexMethod(), QGraphicsScene::BspTreeIndex);
+
+#ifdef QT_ARCH_ARM
+ const int minY = -500;
+ const int maxY = 500;
+ const int minX = -500;
+ const int maxX = 500;
+#else
+ const int minY = -1000;
+ const int maxY = 2000;
+ const int minX = -1000;
+ const int maxX = 2000;
+#endif
+
+ QList<QGraphicsItem *> items;
+ for (int y = minY; y < maxY; y += 100) {
+ for (int x = minX; x < maxX; x += 100) {
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10));
+ item->setPos(x, y);
+ QCOMPARE(scene.itemAt(x, y), item);
+ items << item;
+ }
+ }
+
+ int n = 0;
+ for (int y = minY; y < maxY; y += 100) {
+ for (int x = minX; x < maxX; x += 100)
+ QCOMPARE(scene.itemAt(x, y), items.at(n++));
+ }
+
+ scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+ QCOMPARE(scene.itemIndexMethod(), QGraphicsScene::NoIndex);
+
+ n = 0;
+ for (int y = minY; y < maxY; y += 100) {
+ for (int x = minX; x < maxX; x += 100)
+ QCOMPARE(scene.itemAt(x, y), items.at(n++));
+ }
+
+ scene.setItemIndexMethod(QGraphicsScene::BspTreeIndex);
+ QCOMPARE(scene.itemIndexMethod(), QGraphicsScene::BspTreeIndex);
+
+ n = 0;
+ for (int y = minY; y < maxY; y += 100) {
+ for (int x = minX; x < maxX; x += 100)
+ QCOMPARE(scene.itemAt(x, y), items.at(n++));
+ }
+}
+
+void tst_QGraphicsScene::bspTreeDepth()
+{
+ QGraphicsScene scene;
+ QCOMPARE(scene.itemIndexMethod(), QGraphicsScene::BspTreeIndex);
+ QCOMPARE(scene.bspTreeDepth(), 0);
+ scene.setBspTreeDepth(1);
+ QCOMPARE(scene.bspTreeDepth(), 1);
+ QTest::ignoreMessage(QtWarningMsg, "QGraphicsScene::setBspTreeDepth: invalid depth -1 ignored; must be >= 0");
+ scene.setBspTreeDepth(-1);
+ QCOMPARE(scene.bspTreeDepth(), 1);
+}
+
+void tst_QGraphicsScene::items()
+{
+#ifdef QT_ARCH_ARM
+ const int minY = -500;
+ const int maxY = 500;
+ const int minX = -500;
+ const int maxX = 500;
+#else
+ const int minY = -1000;
+ const int maxY = 2000;
+ const int minX = -1000;
+ const int maxX = 2000;
+#endif
+
+ {
+ QGraphicsScene scene;
+
+ QList<QGraphicsItem *> items;
+ for (int y = minY; y < maxY; y += 100) {
+ for (int x = minX; x < maxX; x += 100)
+ items << scene.addRect(QRectF(0, 0, 10, 10));
+ }
+ QCOMPARE(scene.items().size(), items.size());
+ scene.itemAt(0, 0); // trigger indexing
+
+ scene.removeItem(items.at(5));
+ delete items.at(5);
+ QVERIFY(!scene.items().contains(0));
+ delete items.at(7);
+ QVERIFY(!scene.items().contains(0));
+ }
+ {
+ QGraphicsScene scene;
+ QGraphicsLineItem *l1 = scene.addLine(-5, 0, 5, 0);
+ QGraphicsLineItem *l2 = scene.addLine(0, -5, 0, 5);
+ QVERIFY(!l1->sceneBoundingRect().intersects(l2->sceneBoundingRect()));
+ QVERIFY(!l2->sceneBoundingRect().intersects(l1->sceneBoundingRect()));
+ QList<QGraphicsItem *> items;
+ items<<l1<<l2;
+ QCOMPARE(scene.items().size(), items.size());
+ QVERIFY(scene.items(-1, -1, 2, 2).contains(l1));
+ QVERIFY(scene.items(-1, -1, 2, 2).contains(l2));
+ }
+}
+
+void tst_QGraphicsScene::itemsBoundingRect_data()
+{
+ QTest::addColumn<QList<QRectF> >("rects");
+ QTest::addColumn<QMatrix>("matrix");
+ QTest::addColumn<QRectF>("boundingRect");
+
+ QMatrix transformationMatrix;
+ transformationMatrix.translate(50, -50);
+ transformationMatrix.scale(2, 2);
+ transformationMatrix.rotate(90);
+
+ QTest::newRow("none")
+ << QList<QRectF>()
+ << QMatrix()
+ << QRectF();
+ QTest::newRow("{{0, 0, 10, 10}}")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10))
+ << QMatrix()
+ << QRectF(0, 0, 10, 10);
+ QTest::newRow("{{-10, -10, 10, 10}}")
+ << (QList<QRectF>() << QRectF(-10, -10, 10, 10))
+ << QMatrix()
+ << QRectF(-10, -10, 10, 10);
+ QTest::newRow("{{-1000, -1000, 1, 1}, {-10, -10, 10, 10}}")
+ << (QList<QRectF>() << QRectF(-1000, -1000, 1, 1) << QRectF(-10, -10, 10, 10))
+ << QMatrix()
+ << QRectF(-1000, -1000, 1000, 1000);
+ QTest::newRow("transformed {{0, 0, 10, 10}}")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10))
+ << transformationMatrix
+ << QRectF(30, -50, 20, 20);
+ QTest::newRow("transformed {{-10, -10, 10, 10}}")
+ << (QList<QRectF>() << QRectF(-10, -10, 10, 10))
+ << transformationMatrix
+ << QRectF(50, -70, 20, 20);
+ QTest::newRow("transformed {{-1000, -1000, 1, 1}, {-10, -10, 10, 10}}")
+ << (QList<QRectF>() << QRectF(-1000, -1000, 1, 1) << QRectF(-10, -10, 10, 10))
+ << transformationMatrix
+ << QRectF(50, -2050, 2000, 2000);
+
+ QList<QRectF> all;
+ for (int i = 0; i < 256; ++i)
+ all << QRectF(randomX[i], randomY[i], 10, 10);
+ QTest::newRow("all")
+ << all
+ << QMatrix()
+ << QRectF(-980, -994, 1988, 1983);
+ QTest::newRow("transformed all")
+ << all
+ << transformationMatrix
+ << QRectF(-1928, -2010, 3966, 3976);
+}
+
+void tst_QGraphicsScene::itemsBoundingRect()
+{
+ QFETCH(QList<QRectF>, rects);
+ QFETCH(QMatrix, matrix);
+ QFETCH(QRectF, boundingRect);
+
+ QGraphicsScene scene;
+
+ foreach (QRectF rect, rects) {
+ QPainterPath path;
+ path.addRect(rect);
+ scene.addPath(path)->setMatrix(matrix);
+ }
+
+ QCOMPARE(scene.itemsBoundingRect(), boundingRect);
+}
+
+void tst_QGraphicsScene::items_QPointF_data()
+{
+ QTest::addColumn<QList<QRectF> >("items");
+ QTest::addColumn<QPointF>("point");
+ QTest::addColumn<QList<int> >("itemsAtPoint");
+
+ QTest::newRow("empty")
+ << QList<QRectF>()
+ << QPointF()
+ << QList<int>();
+ QTest::newRow("1")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10))
+ << QPointF(0, 0)
+ << (QList<int>() << 0);
+ QTest::newRow("2")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10))
+ << QPointF(5, 5)
+ << (QList<int>() << 0);
+ QTest::newRow("3")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10))
+ << QPointF(9.9, 9.9)
+ << (QList<int>() << 0);
+ QTest::newRow("3.5")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10))
+ << QPointF(10, 10)
+ << QList<int>();
+ QTest::newRow("4")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10) << QRectF(9.9, 9.9, 10, 10))
+ << QPointF(9.9, 9.9)
+ << (QList<int>() << 1 << 0);
+ QTest::newRow("4.5")
+ << (QList<QRectF>() << QRectF(0, 0, 10, 10) << QRectF(10, 10, 10, 10))
+ << QPointF(10, 10)
+ << (QList<int>() << 1);
+ QTest::newRow("5")
+ << (QList<QRectF>() << QRectF(5, 5, 10, 10) << QRectF(10, 10, 10, 10))
+ << QPointF(10, 10)
+ << (QList<int>() << 1 << 0);
+ QTest::newRow("6")
+ << (QList<QRectF>() << QRectF(5, 5, 10, 10) << QRectF(10, 10, 10, 10) << QRectF(0, 0, 20, 30))
+ << QPointF(10, 10)
+ << (QList<int>() << 2 << 1 << 0);
+}
+
+void tst_QGraphicsScene::items_QPointF()
+{
+ QFETCH(QList<QRectF>, items);
+ QFETCH(QPointF, point);
+ QFETCH(QList<int>, itemsAtPoint);
+
+ QGraphicsScene scene;
+
+ int n = 0;
+ QList<QGraphicsItem *> addedItems;
+ foreach(QRectF rect, items) {
+ QPainterPath path;
+ path.addRect(0, 0, rect.width(), rect.height());
+
+ QGraphicsItem *item = scene.addPath(path);
+ item->setZValue(n++);
+ item->setPos(rect.topLeft());
+ addedItems << item;
+ }
+
+ QList<int> itemIndexes;
+ foreach (QGraphicsItem *item, scene.items(point))
+ itemIndexes << addedItems.indexOf(item);
+
+ QCOMPARE(itemIndexes, itemsAtPoint);
+}
+
+void tst_QGraphicsScene::items_QRectF()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 10, 10));
+ QGraphicsItem *item2 = scene.addRect(QRectF(10, -10, 10, 10));
+ QGraphicsItem *item3 = scene.addRect(QRectF(10, 10, 10, 10));
+ QGraphicsItem *item4 = scene.addRect(QRectF(-10, 10, 10, 10));
+
+ item1->setZValue(0);
+ item2->setZValue(1);
+ item3->setZValue(2);
+ item4->setZValue(3);
+
+ QCOMPARE(scene.items(QRectF(-10, -10, 10, 10)), QList<QGraphicsItem *>() << item1);
+ QCOMPARE(scene.items(QRectF(10, -10, 10, 10)), QList<QGraphicsItem *>() << item2);
+ QCOMPARE(scene.items(QRectF(10, 10, 10, 10)), QList<QGraphicsItem *>() << item3);
+ QCOMPARE(scene.items(QRectF(-10, 10, 10, 10)), QList<QGraphicsItem *>() << item4);
+ QCOMPARE(scene.items(QRectF(-10, -10, 1, 1)), QList<QGraphicsItem *>() << item1);
+ QCOMPARE(scene.items(QRectF(10, -10, 1, 1)), QList<QGraphicsItem *>() << item2);
+ QCOMPARE(scene.items(QRectF(10, 10, 1, 1)), QList<QGraphicsItem *>() << item3);
+ QCOMPARE(scene.items(QRectF(-10, 10, 1, 1)), QList<QGraphicsItem *>() << item4);
+
+ QCOMPARE(scene.items(QRectF(-10, -10, 40, 10)), QList<QGraphicsItem *>() << item2 << item1);
+ QCOMPARE(scene.items(QRectF(-10, 10, 40, 10)), QList<QGraphicsItem *>() << item4 << item3);
+
+ item1->setZValue(3);
+ item2->setZValue(2);
+ item3->setZValue(1);
+ item4->setZValue(0);
+
+ QCOMPARE(scene.items(QRectF(-10, -10, 40, 10)), QList<QGraphicsItem *>() << item1 << item2);
+ QCOMPARE(scene.items(QRectF(-10, 10, 40, 10)), QList<QGraphicsItem *>() << item3 << item4);
+}
+
+void tst_QGraphicsScene::items_QRectF_2_data()
+{
+ QTest::addColumn<QRectF>("ellipseRect");
+ QTest::addColumn<QRectF>("sceneRect");
+ QTest::addColumn<Qt::ItemSelectionMode>("selectionMode");
+ QTest::addColumn<bool>("contained");
+ QTest::addColumn<bool>("containedRotated");
+
+ // None of the rects contain the ellipse's shape nor bounding rect
+ QTest::newRow("1") << QRectF(0, 0, 100, 100) << QRectF(1, 1, 10, 10) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("2") << QRectF(0, 0, 100, 100) << QRectF(1, 89, 10, 10) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("3") << QRectF(0, 0, 100, 100) << QRectF(89, 1, 10, 10) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("4") << QRectF(0, 0, 100, 100) << QRectF(89, 89, 10, 10) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("5") << QRectF(0, 0, 100, 100) << QRectF(1, 1, 10, 10) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("6") << QRectF(0, 0, 100, 100) << QRectF(1, 89, 10, 10) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("7") << QRectF(0, 0, 100, 100) << QRectF(89, 1, 10, 10) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("8") << QRectF(0, 0, 100, 100) << QRectF(89, 89, 10, 10) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("9") << QRectF(0, 0, 100, 100) << QRectF(0, 0, 50, 50) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("10") << QRectF(0, 0, 100, 100) << QRectF(0, 50, 50, 50) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("11") << QRectF(0, 0, 100, 100) << QRectF(50, 0, 50, 50) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("12") << QRectF(0, 0, 100, 100) << QRectF(50, 50, 50, 50) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("13") << QRectF(0, 0, 100, 100) << QRectF(0, 0, 50, 50) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("14") << QRectF(0, 0, 100, 100) << QRectF(0, 50, 50, 50) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("15") << QRectF(0, 0, 100, 100) << QRectF(50, 0, 50, 50) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("16") << QRectF(0, 0, 100, 100) << QRectF(50, 50, 50, 50) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("17") << QRectF(0, 0, 100, 100) << QRectF(-50, -50, 100, 100) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("18") << QRectF(0, 0, 100, 100) << QRectF(0, -50, 100, 100) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("19") << QRectF(0, 0, 100, 100) << QRectF(-50, 0, 100, 100) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("20") << QRectF(0, 0, 100, 100) << QRectF(0, 0, 100, 100) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("21") << QRectF(0, 0, 100, 100) << QRectF(-50, -50, 100, 100) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("22") << QRectF(0, 0, 100, 100) << QRectF(0, -50, 100, 100) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("23") << QRectF(0, 0, 100, 100) << QRectF(-50, 0, 100, 100) << Qt::ContainsItemBoundingRect << false << false;
+
+ // The rect is the same as the ellipse's bounding rect
+ QTest::newRow("24") << QRectF(0, 0, 100, 100) << QRectF(0, 0, 100, 100) << Qt::ContainsItemBoundingRect << false << false;
+
+ // None intersects with the item's shape, but they all intersects with the
+ // item's bounding rect.
+ QTest::newRow("25") << QRectF(0, 0, 100, 100) << QRectF(1, 1, 10, 10) << Qt::IntersectsItemShape << false << false;
+ QTest::newRow("26") << QRectF(0, 0, 100, 100) << QRectF(1, 89, 10, 10) << Qt::IntersectsItemShape << false << true;
+ QTest::newRow("27") << QRectF(0, 0, 100, 100) << QRectF(89, 1, 10, 10) << Qt::IntersectsItemShape << false << false;
+ QTest::newRow("28") << QRectF(0, 0, 100, 100) << QRectF(89, 89, 10, 10) << Qt::IntersectsItemShape << false << false;
+ QTest::newRow("29") << QRectF(0, 0, 100, 100) << QRectF(1, 1, 10, 10) << Qt::IntersectsItemBoundingRect << true << true;
+ QTest::newRow("30") << QRectF(0, 0, 100, 100) << QRectF(1, 89, 10, 10) << Qt::IntersectsItemBoundingRect << true << true;
+ QTest::newRow("31") << QRectF(0, 0, 100, 100) << QRectF(89, 1, 10, 10) << Qt::IntersectsItemBoundingRect << true << false;
+ QTest::newRow("32") << QRectF(0, 0, 100, 100) << QRectF(89, 89, 10, 10) << Qt::IntersectsItemBoundingRect << true << false;
+
+ // This rect does not contain the shape nor the bounding rect
+ QTest::newRow("33") << QRectF(0, 0, 100, 100) << QRectF(5, 5, 90, 90) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("34") << QRectF(0, 0, 100, 100) << QRectF(5, 5, 90, 90) << Qt::ContainsItemBoundingRect << false << false;
+
+ // It will, however, intersect with both
+ QTest::newRow("35") << QRectF(0, 0, 100, 100) << QRectF(5, 5, 90, 90) << Qt::IntersectsItemShape << true << true;
+ QTest::newRow("36") << QRectF(0, 0, 100, 100) << QRectF(5, 5, 90, 90) << Qt::IntersectsItemBoundingRect << true << true;
+
+ // A rect that contains the whole ellipse will both contain and intersect
+ // with both the ellipse's shape and bounding rect.
+ QTest::newRow("37") << QRectF(0, 0, 100, 100) << QRectF(-5, -5, 110, 110) << Qt::IntersectsItemBoundingRect << true << true;
+ QTest::newRow("38") << QRectF(0, 0, 100, 100) << QRectF(-5, -5, 110, 110) << Qt::IntersectsItemShape << true << true;
+ QTest::newRow("39") << QRectF(0, 0, 100, 100) << QRectF(-5, -5, 110, 110) << Qt::ContainsItemBoundingRect << true << false;
+ QTest::newRow("40") << QRectF(0, 0, 100, 100) << QRectF(-5, -5, 110, 110) << Qt::ContainsItemShape << true << false;
+
+ // A rect that is fully contained within the ellipse will intersect only
+ QTest::newRow("41") << QRectF(0, 0, 100, 100) << QRectF(40, 40, 20, 20) << Qt::ContainsItemShape << false << false;
+ QTest::newRow("42") << QRectF(0, 0, 100, 100) << QRectF(40, 40, 20, 20) << Qt::ContainsItemBoundingRect << false << false;
+ QTest::newRow("43") << QRectF(0, 0, 100, 100) << QRectF(40, 40, 20, 20) << Qt::IntersectsItemShape << true << true;
+ QTest::newRow("44") << QRectF(0, 0, 100, 100) << QRectF(40, 40, 20, 20) << Qt::IntersectsItemBoundingRect << true << true;
+}
+
+void tst_QGraphicsScene::items_QRectF_2()
+{
+ QFETCH(QRectF, ellipseRect);
+ QFETCH(QRectF, sceneRect);
+ QFETCH(Qt::ItemSelectionMode, selectionMode);
+ QFETCH(bool, contained);
+ QFETCH(bool, containedRotated);
+
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addEllipse(ellipseRect);
+
+ QCOMPARE(!scene.items(sceneRect, selectionMode).isEmpty(), contained);
+ item->rotate(45);
+ QCOMPARE(!scene.items(sceneRect, selectionMode).isEmpty(), containedRotated);
+}
+
+void tst_QGraphicsScene::items_QPolygonF()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 10, 10));
+ QGraphicsItem *item2 = scene.addRect(QRectF(10, -10, 10, 10));
+ QGraphicsItem *item3 = scene.addRect(QRectF(10, 10, 10, 10));
+ QGraphicsItem *item4 = scene.addRect(QRectF(-10, 10, 10, 10));
+
+ item1->setZValue(0);
+ item2->setZValue(1);
+ item3->setZValue(2);
+ item4->setZValue(3);
+
+ QPolygonF poly1(item1->boundingRect());
+ QPolygonF poly2(item2->boundingRect());
+ QPolygonF poly3(item3->boundingRect());
+ QPolygonF poly4(item4->boundingRect());
+
+ QCOMPARE(scene.items(poly1), QList<QGraphicsItem *>() << item1);
+ QCOMPARE(scene.items(poly2), QList<QGraphicsItem *>() << item2);
+ QCOMPARE(scene.items(poly3), QList<QGraphicsItem *>() << item3);
+ QCOMPARE(scene.items(poly4), QList<QGraphicsItem *>() << item4);
+
+ poly1 = QPolygonF(QRectF(-10, -10, 1, 1));
+ poly2 = QPolygonF(QRectF(10, -10, 1, 1));
+ poly3 = QPolygonF(QRectF(10, 10, 1, 1));
+ poly4 = QPolygonF(QRectF(-10, 10, 1, 1));
+
+ QCOMPARE(scene.items(poly1), QList<QGraphicsItem *>() << item1);
+ QCOMPARE(scene.items(poly2), QList<QGraphicsItem *>() << item2);
+ QCOMPARE(scene.items(poly3), QList<QGraphicsItem *>() << item3);
+ QCOMPARE(scene.items(poly4), QList<QGraphicsItem *>() << item4);
+
+ poly1 = QPolygonF(QRectF(-10, -10, 40, 10));
+ poly2 = QPolygonF(QRectF(-10, 10, 40, 10));
+
+ QCOMPARE(scene.items(poly1), QList<QGraphicsItem *>() << item2 << item1);
+ QCOMPARE(scene.items(poly2), QList<QGraphicsItem *>() << item4 << item3);
+
+ item1->setZValue(3);
+ item2->setZValue(2);
+ item3->setZValue(1);
+ item4->setZValue(0);
+
+ QCOMPARE(scene.items(poly1), QList<QGraphicsItem *>() << item1 << item2);
+ QCOMPARE(scene.items(poly2), QList<QGraphicsItem *>() << item3 << item4);
+}
+
+void tst_QGraphicsScene::items_QPolygonF_2()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *ellipse = scene.addEllipse(QRectF(0, 0, 100, 100));
+
+ // None of the rects contain the ellipse's shape nor bounding rect
+ QVERIFY(scene.items(QPolygonF(QRectF(1, 1, 10, 10)), Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(1, 89, 10, 10)), Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(89, 1, 10, 10)), Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(89, 89, 10, 10)), Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(1, 1, 10, 10)), Qt::ContainsItemBoundingRect).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(1, 89, 10, 10)), Qt::ContainsItemBoundingRect).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(89, 1, 10, 10)), Qt::ContainsItemBoundingRect).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(89, 89, 10, 10)), Qt::ContainsItemBoundingRect).isEmpty());
+
+ // None intersects with the item's shape, but they all intersects with the
+ // item's bounding rect.
+ QVERIFY(scene.items(QPolygonF(QRectF(1, 1, 10, 10)), Qt::IntersectsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(1, 89, 10, 10)), Qt::IntersectsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(89, 1, 10, 10)), Qt::IntersectsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(89, 89, 10, 10)), Qt::IntersectsItemShape).isEmpty());
+ QCOMPARE(scene.items(QPolygonF(QRectF(1, 1, 10, 10)), Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(QPolygonF(QRectF(1, 89, 10, 10)), Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(QPolygonF(QRectF(89, 1, 10, 10)), Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(QPolygonF(QRectF(89, 89, 10, 10)), Qt::IntersectsItemBoundingRect).first(), ellipse);
+
+ // This rect does not contain the shape nor the bounding rect
+ QVERIFY(scene.items(QPolygonF(QRectF(5, 5, 90, 90)), Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(QPolygonF(QRectF(5, 5, 90, 90)), Qt::ContainsItemBoundingRect).isEmpty());
+
+ // It will, however, intersect with both
+ QCOMPARE(scene.items(QPolygonF(QRectF(5, 5, 90, 90)), Qt::IntersectsItemShape).first(), ellipse);
+ QCOMPARE(scene.items(QPolygonF(QRectF(5, 5, 90, 90)), Qt::IntersectsItemBoundingRect).first(), ellipse);
+
+ // A rect that contains the whole ellipse will both contain and intersect
+ // with both the ellipse's shape and bounding rect.
+ QCOMPARE(scene.items(QPolygonF(QRectF(-5, -5, 110, 110)), Qt::IntersectsItemShape).first(), ellipse);
+ QCOMPARE(scene.items(QPolygonF(QRectF(-5, -5, 110, 110)), Qt::ContainsItemShape).first(), ellipse);
+ QCOMPARE(scene.items(QPolygonF(QRectF(-5, -5, 110, 110)), Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(QPolygonF(QRectF(-5, -5, 110, 110)), Qt::ContainsItemBoundingRect).first(), ellipse);
+}
+
+void tst_QGraphicsScene::items_QPainterPath()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 10, 10));
+ QGraphicsItem *item2 = scene.addRect(QRectF(10, -10, 10, 10));
+ QGraphicsItem *item3 = scene.addRect(QRectF(10, 10, 10, 10));
+ QGraphicsItem *item4 = scene.addRect(QRectF(-10, 10, 10, 10));
+
+ item1->setZValue(0);
+ item2->setZValue(1);
+ item3->setZValue(2);
+ item4->setZValue(3);
+
+ QPainterPath path1; path1.addEllipse(item1->boundingRect());
+ QPainterPath path2; path2.addEllipse(item2->boundingRect());
+ QPainterPath path3; path3.addEllipse(item3->boundingRect());
+ QPainterPath path4; path4.addEllipse(item4->boundingRect());
+
+ QCOMPARE(scene.items(path1), QList<QGraphicsItem *>() << item1);
+ QCOMPARE(scene.items(path2), QList<QGraphicsItem *>() << item2);
+ QCOMPARE(scene.items(path3), QList<QGraphicsItem *>() << item3);
+ QCOMPARE(scene.items(path4), QList<QGraphicsItem *>() << item4);
+
+ path1 = QPainterPath(); path1.addEllipse(QRectF(-10, -10, 1, 1));
+ path2 = QPainterPath(); path2.addEllipse(QRectF(10, -10, 1, 1));
+ path3 = QPainterPath(); path3.addEllipse(QRectF(10, 10, 1, 1));
+ path4 = QPainterPath(); path4.addEllipse(QRectF(-10, 10, 1, 1));
+
+ QCOMPARE(scene.items(path1), QList<QGraphicsItem *>() << item1);
+ QCOMPARE(scene.items(path2), QList<QGraphicsItem *>() << item2);
+ QCOMPARE(scene.items(path3), QList<QGraphicsItem *>() << item3);
+ QCOMPARE(scene.items(path4), QList<QGraphicsItem *>() << item4);
+
+ path1 = QPainterPath(); path1.addRect(QRectF(-10, -10, 40, 10));
+ path2 = QPainterPath(); path2.addRect(QRectF(-10, 10, 40, 10));
+
+ QCOMPARE(scene.items(path1), QList<QGraphicsItem *>() << item2 << item1);
+ QCOMPARE(scene.items(path2), QList<QGraphicsItem *>() << item4 << item3);
+
+ item1->setZValue(3);
+ item2->setZValue(2);
+ item3->setZValue(1);
+ item4->setZValue(0);
+
+ QCOMPARE(scene.items(path1), QList<QGraphicsItem *>() << item1 << item2);
+ QCOMPARE(scene.items(path2), QList<QGraphicsItem *>() << item3 << item4);
+}
+
+void tst_QGraphicsScene::items_QPainterPath_2()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *ellipse = scene.addEllipse(QRectF(0, 0, 100, 100));
+
+ QPainterPath p1; p1.addRect(QRectF(1, 1, 10, 10));
+ QPainterPath p2; p2.addRect(QRectF(1, 89, 10, 10));
+ QPainterPath p3; p3.addRect(QRectF(89, 1, 10, 10));
+ QPainterPath p4; p4.addRect(QRectF(89, 89, 10, 10));
+
+ // None of the rects contain the ellipse's shape nor bounding rect
+ QVERIFY(scene.items(p1, Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(p2, Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(p3, Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(p4, Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(p1, Qt::ContainsItemBoundingRect).isEmpty());
+ QVERIFY(scene.items(p2, Qt::ContainsItemBoundingRect).isEmpty());
+ QVERIFY(scene.items(p3, Qt::ContainsItemBoundingRect).isEmpty());
+ QVERIFY(scene.items(p4, Qt::ContainsItemBoundingRect).isEmpty());
+
+ // None intersects with the item's shape, but they all intersects with the
+ // item's bounding rect.
+ QVERIFY(scene.items(p1, Qt::IntersectsItemShape).isEmpty());
+ QVERIFY(scene.items(p2, Qt::IntersectsItemShape).isEmpty());
+ QVERIFY(scene.items(p3, Qt::IntersectsItemShape).isEmpty());
+ QVERIFY(scene.items(p4, Qt::IntersectsItemShape).isEmpty());
+ QCOMPARE(scene.items(p1, Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(p2, Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(p3, Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(p4, Qt::IntersectsItemBoundingRect).first(), ellipse);
+
+ QPainterPath p5;
+ p5.addRect(QRectF(5, 5, 90, 90));
+
+ // This rect does not contain the shape nor the bounding rect
+ QVERIFY(scene.items(p5, Qt::ContainsItemShape).isEmpty());
+ QVERIFY(scene.items(p5, Qt::ContainsItemBoundingRect).isEmpty());
+
+ // It will, however, intersect with both
+ QCOMPARE(scene.items(p5, Qt::IntersectsItemShape).first(), ellipse);
+ QCOMPARE(scene.items(p5, Qt::IntersectsItemBoundingRect).first(), ellipse);
+
+ QPainterPath p6;
+ p6.addRect(QRectF(-5, -5, 110, 110));
+
+ // A rect that contains the whole ellipse will both contain and intersect
+ // with both the ellipse's shape and bounding rect.
+ QCOMPARE(scene.items(p6, Qt::IntersectsItemShape).first(), ellipse);
+ QCOMPARE(scene.items(p6, Qt::ContainsItemShape).first(), ellipse);
+ QCOMPARE(scene.items(p6, Qt::IntersectsItemBoundingRect).first(), ellipse);
+ QCOMPARE(scene.items(p6, Qt::ContainsItemBoundingRect).first(), ellipse);
+}
+
+void tst_QGraphicsScene::selection()
+{
+ // ### This test is difficult to make work for all platforms; instead, a
+ // hand crafted data set would make it stable. Its behavior is thoroughly
+ // covered by other tests. Todo: Fix this test.
+
+ /*
+ QGraphicsScene scene;
+ QMap<QGraphicsItem *, int> itemIndexes;
+ for (int i = 0; i < 256; ++i) {
+ QPainterPath path;
+ path.addRect(randomX[i], randomY[i], 25, 25);
+
+ QGraphicsPathItem *pathItem = scene.addPath(path);
+ pathItem->setFlag(QGraphicsItem::ItemIsSelectable);
+ itemIndexes.insert(pathItem, i);
+ }
+
+#if 0
+ // Write data
+ QFile::remove("graphicsScene_selection.data");
+ QFile file("graphicsScene_selection.data");
+ if (!file.open(QFile::WriteOnly))
+ QFAIL("Unable to generate data file graphicsScene_selection.data");
+ QDataStream stream(&file);
+ for (qreal y = -1000; y < 1000; y += 33) {
+ for (qreal x = -1000; x < 1000; x += 33) {
+ for (qreal size = 1; size < 200; size += 33) {
+ QPainterPath path;
+ path.addRect(QRectF(x, y, size, size));
+ scene.setSelectionArea(path);
+ QCOMPARE(scene.selectionArea(), path);
+
+ QList<int> indexes;
+ foreach (QGraphicsItem *item, scene.selectedItems())
+ indexes << itemIndexes.value(item);
+
+ stream << x << y << size << indexes;
+ }
+ }
+ }
+#else
+ // Read data
+ QFile file("graphicsScene_selection.data");
+ if (!file.open(QFile::ReadOnly))
+ QFAIL("Unable to load data file graphicsScene_selection.data");
+
+ QDataStream stream(&file);
+
+ while (!stream.atEnd()) {
+ QList<int> expectedIndexes;
+
+ qreal x, y, size;
+ stream >> x >> y >> size >> expectedIndexes;
+
+ QPainterPath path;
+ path.addRect(QRectF(x, y, size, size));
+ scene.setSelectionArea(path);
+ QCOMPARE(scene.selectionArea(), path);
+
+ QList<int> indexes;
+ foreach (QGraphicsItem *item, scene.selectedItems())
+ indexes << itemIndexes.value(item);
+
+ qSort(indexes);
+ qSort(expectedIndexes);
+
+ QCOMPARE(indexes, expectedIndexes);
+
+ scene.clearSelection();
+ QVERIFY(scene.selectedItems().isEmpty());
+ }
+#endif
+ */
+}
+
+class CustomView : public QGraphicsView
+{
+public:
+ CustomView() : repaints(0)
+ { }
+
+ int repaints;
+protected:
+ void paintEvent(QPaintEvent *event)
+ {
+ ++repaints;
+ QGraphicsView::paintEvent(event);
+ }
+};
+
+void tst_QGraphicsScene::selectionChanged()
+{
+ QGraphicsScene scene(0, 0, 1000, 1000);
+ QSignalSpy spy(&scene, SIGNAL(selectionChanged()));
+ QCOMPARE(spy.count(), 0);
+
+ QPainterPath path;
+ path.addRect(scene.sceneRect());
+ QCOMPARE(scene.selectionArea(), QPainterPath());
+ scene.setSelectionArea(path);
+ QCOMPARE(scene.selectionArea(), path);
+ QCOMPARE(spy.count(), 0); // selection didn't change
+ QVERIFY(scene.selectedItems().isEmpty());
+
+ QGraphicsItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
+ QCOMPARE(spy.count(), 0); // selection didn't change
+
+ rect->setSelected(true);
+ QVERIFY(!rect->isSelected());
+ QCOMPARE(spy.count(), 0); // selection didn't change, item isn't selectable
+
+ rect->setFlag(QGraphicsItem::ItemIsSelectable);
+ rect->setSelected(true);
+ QVERIFY(rect->isSelected());
+ QCOMPARE(spy.count(), 1); // selection changed
+ QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << rect);
+
+ rect->setSelected(false);
+ QVERIFY(!rect->isSelected());
+ QCOMPARE(spy.count(), 2); // selection changed
+ QVERIFY(scene.selectedItems().isEmpty());
+
+ QGraphicsEllipseItem *parentItem = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100));
+ QGraphicsEllipseItem *childItem = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100), parentItem);
+ QGraphicsEllipseItem *grandChildItem = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100), childItem);
+ grandChildItem->setFlag(QGraphicsItem::ItemIsSelectable);
+ grandChildItem->setSelected(true);
+ grandChildItem->setSelected(false);
+ grandChildItem->setSelected(true);
+ scene.addItem(parentItem);
+
+ QCOMPARE(spy.count(), 3); // the grandchild was added, so the selection changed once
+
+ scene.removeItem(parentItem);
+ QCOMPARE(spy.count(), 4); // the grandchild was removed, so the selection changed
+
+ rect->setSelected(true);
+ QCOMPARE(spy.count(), 5); // the rect was reselected, so the selection changed
+
+ scene.clearSelection();
+ QCOMPARE(spy.count(), 6); // the scene selection was cleared
+
+ rect->setSelected(true);
+ QCOMPARE(spy.count(), 7); // the rect was reselected, so the selection changed
+
+ rect->setFlag(QGraphicsItem::ItemIsSelectable, false);
+ QCOMPARE(spy.count(), 8); // the rect was unselected, so the selection changed
+
+ rect->setSelected(true);
+ QCOMPARE(spy.count(), 8); // the rect is not longer selectable, so the selection does not change
+
+
+ rect->setFlag(QGraphicsItem::ItemIsSelectable, true);
+ rect->setSelected(true);
+ QCOMPARE(spy.count(), 9); // the rect is again selectable, so the selection changed
+
+ delete rect;
+ QCOMPARE(spy.count(), 10); // a selected item was deleted; selection changed
+}
+
+void tst_QGraphicsScene::selectionChanged2()
+{
+ QGraphicsScene scene;
+ QSignalSpy spy(&scene, SIGNAL(selectionChanged()));
+
+ QGraphicsItem *item1 = scene.addRect(0, 0, 100, 100);
+ QGraphicsItem *item2 = scene.addRect(100, 100, 100, 100);
+ item1->setFlag(QGraphicsItem::ItemIsSelectable);
+ item2->setFlag(QGraphicsItem::ItemIsSelectable);
+
+ QCOMPARE(spy.count(), 0);
+ {
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+ event.setScenePos(QPointF(50, 50));
+ event.setButton(Qt::LeftButton);
+ qApp->sendEvent(&scene, &event);
+ }
+ {
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
+ event.setScenePos(QPointF(50, 50));
+ event.setButton(Qt::LeftButton);
+ qApp->sendEvent(&scene, &event);
+ }
+ QVERIFY(item1->isSelected());
+ QVERIFY(!item2->isSelected());
+ QCOMPARE(spy.count(), 1);
+ {
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+ event.setScenePos(QPointF(150, 150));
+ event.setButton(Qt::LeftButton);
+ qApp->sendEvent(&scene, &event);
+ }
+ {
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
+ event.setScenePos(QPointF(150, 150));
+ event.setButton(Qt::LeftButton);
+ qApp->sendEvent(&scene, &event);
+ }
+ QVERIFY(!item1->isSelected());
+ QVERIFY(item2->isSelected());
+ QCOMPARE(spy.count(), 2);
+ {
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+ event.setScenePos(QPointF(50, 50));
+ event.setButton(Qt::LeftButton);
+ event.setModifiers(Qt::ControlModifier);
+ qApp->sendEvent(&scene, &event);
+ }
+ QVERIFY(!item1->isSelected());
+ QVERIFY(item2->isSelected());
+ QCOMPARE(spy.count(), 2);
+ {
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
+ event.setScenePos(QPointF(50, 50));
+ event.setButton(Qt::LeftButton);
+ qApp->sendEvent(&scene, &event);
+ }
+ QVERIFY(item1->isSelected());
+ QVERIFY(!item2->isSelected());
+ QCOMPARE(spy.count(), 3);
+}
+
+void tst_QGraphicsScene::addItem()
+{
+ Q_CHECK_PAINTEVENTS
+ {
+ // 1) Create item, then scene, then add item
+ QGraphicsItem *path = new QGraphicsEllipseItem(QRectF(-10, -10, 20, 20));
+ QGraphicsScene scene;
+
+ CustomView view;
+ view.setScene(&scene);
+ view.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&view);
+#endif
+ qApp->processEvents();
+ view.repaints = 0;
+
+ scene.addItem(path);
+
+ // Adding an item should always issue a repaint.
+ qApp->processEvents(); // <- delayed update is called
+ qApp->processEvents(); // <- scene schedules pending update
+ qApp->processEvents(); // <- pending update is sent to view
+ QVERIFY(view.repaints > 0);
+ view.repaints = 0;
+
+ QCOMPARE(scene.itemAt(0, 0), path);
+
+ QGraphicsItem *path2 = new QGraphicsEllipseItem(QRectF(-10, -10, 20, 20));
+ path2->setPos(100, 100);
+
+ QCOMPARE(scene.itemAt(0, 0), path);
+ QCOMPARE(scene.itemAt(100, 100), (QGraphicsItem *)0);
+ scene.addItem(path2);
+
+ // Adding an item should always issue a repaint.
+ qApp->processEvents(); // <- delayed update is called
+ qApp->processEvents(); // <- scene schedules pending update
+ qApp->processEvents(); // <- pending update is sent to view
+ QVERIFY(view.repaints > 0);
+
+ QCOMPARE(scene.itemAt(100, 100), path2);
+ }
+ {
+ // 2) Create scene, then item, then add item
+ QGraphicsScene scene;
+ QGraphicsItem *path = new QGraphicsEllipseItem(QRectF(-10, -10, 20, 20));
+ scene.addItem(path);
+
+ QGraphicsItem *path2 = new QGraphicsEllipseItem(QRectF(-10, -10, 20, 20));
+ path2->setPos(100, 100);
+ scene.addItem(path2);
+
+ QCOMPARE(scene.itemAt(0, 0), path);
+ QCOMPARE(scene.itemAt(100, 100), path2);
+ }
+}
+
+void tst_QGraphicsScene::addEllipse()
+{
+ QGraphicsScene scene;
+ QGraphicsEllipseItem *ellipse = scene.addEllipse(QRectF(-10, -10, 20, 20),
+ QPen(Qt::red), QBrush(Qt::blue));
+ QCOMPARE(ellipse->pos(), QPointF());
+ QCOMPARE(ellipse->pen(), QPen(Qt::red));
+ QCOMPARE(ellipse->brush(), QBrush(Qt::blue));
+ QCOMPARE(ellipse->rect(), QRectF(-10, -10, 20, 20));
+ QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)ellipse);
+ QCOMPARE(scene.itemAt(-10, -10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(-9.9, 0), (QGraphicsItem *)ellipse);
+ QCOMPARE(scene.itemAt(-10, 10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(0, -9.9), (QGraphicsItem *)ellipse);
+ QCOMPARE(scene.itemAt(0, 9.9), (QGraphicsItem *)ellipse);
+ QCOMPARE(scene.itemAt(10, -10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(9.9, 0), (QGraphicsItem *)ellipse);
+ QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsScene::addLine()
+{
+ QGraphicsScene scene;
+ QPen pen(Qt::red);
+ pen.setWidthF(1.0);
+ QGraphicsLineItem *line = scene.addLine(QLineF(-10, -10, 20, 20),
+ pen);
+ QCOMPARE(line->pos(), QPointF());
+ QCOMPARE(line->pen(), pen);
+ QCOMPARE(line->line(), QLineF(-10, -10, 20, 20));
+ QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)line);
+ QCOMPARE(scene.itemAt(-10, -10), (QGraphicsItem *)line);
+ QCOMPARE(scene.itemAt(-9.9, 0), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(-10, 10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(0, -9.9), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(0, 9.9), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(10, -10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(9.9, 0), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)line);
+}
+
+void tst_QGraphicsScene::addPath()
+{
+ QGraphicsScene scene;
+ QPainterPath p;
+ p.addEllipse(QRectF(-10, -10, 20, 20));
+ p.addEllipse(QRectF(-10, 20, 20, 20));
+
+ QGraphicsPathItem *path = scene.addPath(p, QPen(Qt::red), QBrush(Qt::blue));
+ QCOMPARE(path->pos(), QPointF());
+ QCOMPARE(path->pen(), QPen(Qt::red));
+ QCOMPARE(path->path(), p);
+ QCOMPARE(path->brush(), QBrush(Qt::blue));
+ QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(-9.9, 0), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(9.9, 0), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(0, -9.9), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(0, 9.9), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(0, 30), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(-9.9, 30), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(9.9, 30), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(0, 20.1), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(0, 39.9), (QGraphicsItem *)path);
+ QCOMPARE(scene.itemAt(-10, -10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(10, -10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(-10, 10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(-10, 20), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(10, 20), (QGraphicsItem *)0);
+if (sizeof(qreal) != sizeof(double))
+ QWARN("Skipping test because of rounding errors when qreal != double");
+else
+ QCOMPARE(scene.itemAt(-10, 30), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(10.1, 30), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsScene::addPixmap()
+{
+ QGraphicsScene scene;
+ QPixmap pix(":/Ash_European.jpg");
+ QGraphicsPixmapItem *pixmap = scene.addPixmap(pix);
+
+ QCOMPARE(pixmap->pos(), QPointF());
+ QCOMPARE(pixmap->pixmap(), pix);
+ QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)pixmap);
+ QCOMPARE(scene.itemAt(pix.width() - 1, 0), (QGraphicsItem *)pixmap);
+ QCOMPARE(scene.itemAt(0, pix.height() - 1), (QGraphicsItem *)pixmap);
+ QCOMPARE(scene.itemAt(pix.width() - 1, pix.height() - 1), (QGraphicsItem *)pixmap);
+ QCOMPARE(scene.itemAt(-1, -1), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(pix.width() - 1, -1), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(-1, pix.height() - 1), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(pix.width(), pix.height()), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(0, pix.height()), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(pix.width(), 0), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsScene::addRect()
+{
+ QGraphicsScene scene;
+ QGraphicsRectItem *rect = scene.addRect(QRectF(-10, -10, 20, 20),
+ QPen(Qt::red), QBrush(Qt::blue));
+ QCOMPARE(rect->pos(), QPointF());
+ QCOMPARE(rect->pen(), QPen(Qt::red));
+ QCOMPARE(rect->brush(), QBrush(Qt::blue));
+ QCOMPARE(rect->rect(), QRectF(-10, -10, 20, 20));
+ QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)rect);
+ QCOMPARE(scene.itemAt(-10, -10), (QGraphicsItem *)rect);
+ QCOMPARE(scene.itemAt(-9.9, 0), (QGraphicsItem *)rect);
+ QCOMPARE(scene.itemAt(-10, 10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(0, -9.9), (QGraphicsItem *)rect);
+ QCOMPARE(scene.itemAt(0, 9.9), (QGraphicsItem *)rect);
+ QCOMPARE(scene.itemAt(10, -10), (QGraphicsItem *)0);
+ QCOMPARE(scene.itemAt(9.9, 0), (QGraphicsItem *)rect);
+ QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsScene::addText()
+{
+ QGraphicsScene scene;
+ QGraphicsTextItem *text = scene.addText("Qt", QFont());
+ QCOMPARE(text->pos(), QPointF());
+ QCOMPARE(text->toPlainText(), QString("Qt"));
+ QCOMPARE(text->font(), QFont());
+}
+
+void tst_QGraphicsScene::removeItem()
+{
+#if defined(Q_OS_WINCE) && !defined(GWES_ICONCURS)
+ QSKIP("No mouse cursor support", SkipAll);
+#endif
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10));
+ QCOMPARE(scene.itemAt(0, 0), item); // forces indexing
+ scene.removeItem(item);
+ QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)0);
+ delete item;
+
+ QGraphicsItem *item2 = scene.addRect(QRectF(0, 0, 10, 10));
+ item2->setFlag(QGraphicsItem::ItemIsSelectable);
+ QCOMPARE(scene.itemAt(0, 0), item2);
+
+ // Removing a selected item
+ QVERIFY(scene.selectedItems().isEmpty());
+ item2->setSelected(true);
+ QVERIFY(scene.selectedItems().contains(item2));
+ scene.removeItem(item2);
+ QVERIFY(scene.selectedItems().isEmpty());
+
+ // Check that we are in a state that can receive paint events
+ // (i.e., not logged out on Windows).
+ Q_CHECK_PAINTEVENTS
+
+ // Removing a hovered item
+ HoverItem *hoverItem = new HoverItem;
+ scene.addItem(hoverItem);
+ scene.setSceneRect(-50, -50, 100, 100);
+
+ QGraphicsView view(&scene);
+ view.setFixedSize(150, 150);
+ view.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&view);
+#endif
+ QTest::mouseMove(view.viewport(), QPoint(-1, -1));
+ {
+ QMouseEvent moveEvent(QEvent::MouseMove, view.mapFromScene(hoverItem->scenePos() + QPointF(20, 20)), Qt::NoButton, 0, 0);
+ QApplication::sendEvent(view.viewport(), &moveEvent);
+ }
+ qApp->processEvents(); // update
+ qApp->processEvents(); // draw
+ QVERIFY(!hoverItem->isHovered);
+
+ {
+ QTest::qWait(250);
+ QTest::mouseMove(view.viewport(), view.mapFromScene(hoverItem->scenePos()), Qt::NoButton);
+ QTest::qWait(10);
+ QMouseEvent moveEvent(QEvent::MouseMove, view.mapFromScene(hoverItem->scenePos()), Qt::NoButton, 0, 0);
+ QApplication::sendEvent(view.viewport(), &moveEvent);
+ }
+ qApp->processEvents(); // update
+ qApp->processEvents(); // draw
+ QVERIFY(hoverItem->isHovered);
+
+ scene.removeItem(hoverItem);
+ hoverItem->setAcceptsHoverEvents(false);
+ scene.addItem(hoverItem);
+ qApp->processEvents(); // <- delayed update is called
+ qApp->processEvents(); // <- scene schedules pending update
+ qApp->processEvents(); // <- pending update is sent to view
+ QVERIFY(!hoverItem->isHovered);
+}
+
+void tst_QGraphicsScene::focusItem()
+{
+ QGraphicsScene scene;
+ QEvent activate(QEvent::WindowActivate);
+ QApplication::sendEvent(&scene, &activate);
+
+ QVERIFY(!scene.focusItem());
+ QGraphicsItem *item = scene.addText("Qt");
+ QVERIFY(!scene.focusItem());
+ item->setFocus();
+ QVERIFY(!scene.focusItem());
+ item->setFlag(QGraphicsItem::ItemIsFocusable);
+ QVERIFY(!scene.focusItem());
+ item->setFocus();
+ QCOMPARE(scene.focusItem(), item);
+
+ QFocusEvent focusOut(QEvent::FocusOut);
+ QApplication::sendEvent(&scene, &focusOut);
+
+ QVERIFY(!scene.focusItem());
+
+ QFocusEvent focusIn(QEvent::FocusIn);
+ QApplication::sendEvent(&scene, &focusIn);
+ QCOMPARE(scene.focusItem(), item);
+
+ QGraphicsItem *item2 = scene.addText("Qt");
+ item2->setFlag(QGraphicsItem::ItemIsFocusable);
+ QCOMPARE(scene.focusItem(), item);
+
+ item2->setFocus();
+ QCOMPARE(scene.focusItem(), item2);
+ item->setFocus();
+ QCOMPARE(scene.focusItem(), item);
+
+ item2->setFocus();
+ QCOMPARE(scene.focusItem(), item2);
+ QApplication::sendEvent(&scene, &focusOut);
+ QVERIFY(!scene.hasFocus());
+ QVERIFY(!scene.focusItem());
+ QApplication::sendEvent(&scene, &focusIn);
+ QCOMPARE(scene.focusItem(), item2);
+
+ QApplication::sendEvent(&scene, &focusOut);
+
+ QVERIFY(!scene.focusItem());
+ scene.removeItem(item2);
+ delete item2;
+
+ QApplication::sendEvent(&scene, &focusIn);
+ QVERIFY(!scene.focusItem());
+}
+
+class FocusItem : public QGraphicsTextItem
+{
+protected:
+ void focusOutEvent(QFocusEvent *)
+ {
+ QVERIFY(!scene()->focusItem());
+ }
+};
+
+void tst_QGraphicsScene::focusItemLostFocus()
+{
+ QGraphicsScene scene;
+ QEvent activate(QEvent::WindowActivate);
+ QApplication::sendEvent(&scene, &activate);
+
+ FocusItem *item = new FocusItem;
+ item->setTextInteractionFlags(Qt::TextEditorInteraction);
+ scene.addItem(item);
+
+ item->setFocus();
+ QCOMPARE(scene.focusItem(), (QGraphicsItem *)item);
+ item->clearFocus();
+}
+
+class ClearTestItem : public QGraphicsRectItem
+{
+public:
+ ClearTestItem(QGraphicsItem *parent = 0) : QGraphicsRectItem(parent) {}
+ ~ClearTestItem() { qDeleteAll(items); }
+ QList<QGraphicsItem *> items;
+};
+
+void tst_QGraphicsScene::clear()
+{
+ QGraphicsScene scene;
+ scene.clear();
+ QVERIFY(scene.items().isEmpty());
+ scene.addRect(0, 0, 100, 100);
+ QCOMPARE(scene.sceneRect(), QRectF(0, 0, 100, 100));
+ scene.clear();
+ QVERIFY(scene.items().isEmpty());
+ QCOMPARE(scene.sceneRect(), QRectF(0, 0, 100, 100));
+
+ ClearTestItem *firstItem = new ClearTestItem;
+ QGraphicsItem *secondItem = new QGraphicsRectItem;
+ firstItem->items += secondItem;
+
+ scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+ scene.addItem(firstItem);
+ scene.addItem(secondItem);
+ QCOMPARE(scene.items().at(0), (QGraphicsItem*)firstItem);
+ QCOMPARE(scene.items().at(1), secondItem);
+
+ ClearTestItem *thirdItem = new ClearTestItem(firstItem);
+ QGraphicsItem *forthItem = new QGraphicsRectItem(firstItem);
+ thirdItem->items += forthItem;
+
+ // must not crash even if firstItem deletes secondItem
+ scene.clear();
+ QVERIFY(scene.items().isEmpty());
+}
+
+void tst_QGraphicsScene::setFocusItem()
+{
+ QGraphicsScene scene;
+ QEvent activate(QEvent::WindowActivate);
+ QApplication::sendEvent(&scene, &activate);
+
+ QGraphicsItem *item = scene.addText("Qt");
+ QVERIFY(!scene.focusItem());
+ QVERIFY(!scene.hasFocus());
+ scene.setFocusItem(item);
+ QVERIFY(!scene.hasFocus());
+ QVERIFY(!scene.focusItem());
+ item->setFlag(QGraphicsItem::ItemIsFocusable);
+
+ for (int i = 0; i < 3; ++i) {
+ scene.setFocusItem(item);
+ QVERIFY(scene.hasFocus());
+ QCOMPARE(scene.focusItem(), item);
+ QVERIFY(item->hasFocus());
+ }
+
+ QGraphicsItem *item2 = scene.addText("Qt");
+ item2->setFlag(QGraphicsItem::ItemIsFocusable);
+
+ scene.setFocusItem(item2);
+ QVERIFY(!item->hasFocus());
+ QVERIFY(item2->hasFocus());
+
+ scene.setFocusItem(item);
+ QVERIFY(item->hasFocus());
+ QVERIFY(!item2->hasFocus());
+
+ scene.clearFocus();
+ QVERIFY(!item->hasFocus());
+ QVERIFY(!item2->hasFocus());
+
+ scene.setFocus();
+ QVERIFY(item->hasFocus());
+ QVERIFY(!item2->hasFocus());
+
+ scene.setFocusItem(0);
+ QVERIFY(!item->hasFocus());
+ QVERIFY(!item2->hasFocus());
+
+ scene.setFocus();
+ QVERIFY(!item->hasFocus());
+ QVERIFY(!item2->hasFocus());
+}
+
+void tst_QGraphicsScene::setFocusItem_inactive()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addText("Qt");
+ QVERIFY(!scene.focusItem());
+ QVERIFY(!scene.hasFocus());
+ scene.setFocusItem(item);
+ QVERIFY(!scene.hasFocus());
+ QVERIFY(!scene.focusItem());
+ item->setFlag(QGraphicsItem::ItemIsFocusable);
+
+ for (int i = 0; i < 3; ++i) {
+ scene.setFocusItem(item);
+ QCOMPARE(scene.focusItem(), item);
+ QVERIFY(!item->hasFocus());
+ }
+
+}
+
+
+void tst_QGraphicsScene::mouseGrabberItem()
+{
+ QGraphicsScene scene;
+ QVERIFY(!scene.mouseGrabberItem());
+
+ QGraphicsItem *item = scene.addRect(QRectF(-10, -10, 20, 20));
+ item->setFlag(QGraphicsItem::ItemIsMovable);
+ item->setZValue(1);
+
+ QGraphicsItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
+ item2->setFlag(QGraphicsItem::ItemIsMovable);
+ item2->setZValue(0);
+
+ for (int i = 0; i < 3; ++i) {
+ item->setPos(0, 0);
+ item2->setPos(0, 0);
+ item->setZValue((i & 1) ? 0 : 1);
+ item2->setZValue((i & 1) ? 1 : 0);
+ QGraphicsItem *topMostItem = (i & 1) ? item2 : item;
+
+ QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+ pressEvent.setButton(Qt::LeftButton);
+ pressEvent.setScenePos(QPointF(0, 0));
+ pressEvent.setScreenPos(QPoint(100, 100));
+
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(scene.mouseGrabberItem(), topMostItem);
+
+ for (int i = 0; i < 1000; ++i) {
+ QGraphicsSceneMouseEvent moveEvent(QEvent::GraphicsSceneMouseMove);
+ moveEvent.setButtons(Qt::LeftButton);
+ moveEvent.setScenePos(QPointF(i * 10, i * 10));
+ moveEvent.setScreenPos(QPoint(100 + i * 10, 100 + i * 10));
+ QApplication::sendEvent(&scene, &moveEvent);
+ QCOMPARE(scene.mouseGrabberItem(), topMostItem);
+
+ // Geometrical changes should not affect the mouse grabber.
+ item->setZValue(rand() % 500);
+ item2->setZValue(rand() % 500);
+ item->setPos(rand() % 50000, rand() % 50000);
+ item2->setPos(rand() % 50000, rand() % 50000);
+ }
+
+ QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
+ releaseEvent.setScenePos(QPointF(10000, 10000));
+ releaseEvent.setScreenPos(QPoint(1000000, 1000000));
+ QApplication::sendEvent(&scene, &releaseEvent);
+ QVERIFY(!scene.mouseGrabberItem());
+ }
+
+ // Structural change: deleting the mouse grabber
+ item->setPos(0, 0);
+ item->setZValue(1);
+ item2->setPos(0, 0);
+ item2->setZValue(0);
+ QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+ pressEvent.setButton(Qt::LeftButton);
+ pressEvent.setScenePos(QPointF(0, 0));
+ pressEvent.setScreenPos(QPoint(100, 100));
+
+ QGraphicsSceneMouseEvent moveEvent(QEvent::GraphicsSceneMouseMove);
+ moveEvent.setButtons(Qt::LeftButton);
+ moveEvent.setScenePos(QPointF(0, 0));
+ moveEvent.setScreenPos(QPoint(100, 100));
+
+ QApplication::sendEvent(&scene, &pressEvent);
+ QApplication::sendEvent(&scene, &moveEvent);
+ QCOMPARE(scene.mouseGrabberItem(), item);
+ item->setVisible(false);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(scene.mouseGrabberItem(), item2);
+ item2->setVisible(false);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+ QApplication::sendEvent(&scene, &moveEvent);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+ item2->setVisible(true);
+ QApplication::sendEvent(&scene, &moveEvent);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+ QApplication::sendEvent(&scene, &pressEvent);
+ QApplication::sendEvent(&scene, &moveEvent);
+ QCOMPARE(scene.mouseGrabberItem(), item2);
+ scene.removeItem(item2);
+ delete item2;
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+}
+
+void tst_QGraphicsScene::hoverEvents_siblings()
+{
+ Q_CHECK_PAINTEVENTS
+
+ QGraphicsScene scene;
+ QGraphicsItem *lastItem = 0;
+ QList<HoverItem *> items;
+ for (int i = 0; i < 15; ++i) {
+ QGraphicsItem *item = new HoverItem;
+ scene.addItem(item);
+ items << (HoverItem *)item;
+ if (lastItem) {
+ item->setPos(lastItem->pos() + QPointF(sin(i / 3.0) * 17, cos(i / 3.0) * 17));
+ }
+ item->setZValue(i);
+ lastItem = item;
+ }
+
+ QGraphicsView view(&scene);
+ view.setRenderHint(QPainter::Antialiasing, true);
+#if defined(Q_OS_WINCE)
+ view.setMinimumSize(230, 200);
+#else
+ view.setMinimumSize(400, 300);
+#endif
+ view.rotate(10);
+ view.scale(1.7, 1.7);
+ view.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&view);
+#endif
+ qApp->setActiveWindow(&view);
+ view.activateWindow();
+ QTest::qWait(70);
+
+ QCursor::setPos(view.mapToGlobal(QPoint(-5, -5)));
+
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
+ mouseEvent.setScenePos(QPointF(-1000, -1000));
+ QApplication::sendEvent(&scene, &mouseEvent);
+
+ QTest::qWait(50);
+
+ for (int j = 1; j >= 0; --j) {
+ int i = j ? 0 : 14;
+ forever {
+ if (j)
+ QVERIFY(!items.at(i)->isHovered);
+ else
+ QVERIFY(!items.at(i)->isHovered);
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
+ mouseEvent.setScenePos(items.at(i)->mapToScene(0, 0));
+ QApplication::sendEvent(&scene, &mouseEvent);
+
+ qApp->processEvents(); // this posts updates from the scene to the view
+ qApp->processEvents(); // which trigger a repaint here
+
+ QTRY_VERIFY(items.at(i)->isHovered);
+ if (j && i > 0)
+ QVERIFY(!items.at(i - 1)->isHovered);
+ if (!j && i < 14)
+ QVERIFY(!items.at(i + 1)->isHovered);
+ i += j ? 1 : -1;
+ if ((j && i == 15) || (!j && i == -1))
+ break;
+ }
+
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
+ mouseEvent.setScenePos(QPointF(-1000, -1000));
+ QApplication::sendEvent(&scene, &mouseEvent);
+
+ qApp->processEvents(); // this posts updates from the scene to the view
+ qApp->processEvents(); // which trigger a repaint here
+ }
+}
+
+void tst_QGraphicsScene::hoverEvents_parentChild()
+{
+ Q_CHECK_PAINTEVENTS
+
+ QGraphicsScene scene;
+ QGraphicsItem *lastItem = 0;
+ QList<HoverItem *> items;
+ for (int i = 0; i < 15; ++i) {
+ QGraphicsItem *item = new HoverItem;
+ scene.addItem(item);
+ items << (HoverItem *)item;
+ if (lastItem) {
+ item->setParentItem(lastItem);
+ item->setPos(sin(i / 3.0) * 17, cos(i / 3.0) * 17);
+ }
+ lastItem = item;
+ }
+
+ QGraphicsView view(&scene);
+ view.setRenderHint(QPainter::Antialiasing, true);
+#if defined(Q_OS_WINCE)
+ view.setMinimumSize(230, 200);
+#else
+ view.setMinimumSize(400, 300);
+#endif
+ view.rotate(10);
+ view.scale(1.7, 1.7);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QTest::qWait(70);
+
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
+ mouseEvent.setScenePos(QPointF(-1000, -1000));
+ QApplication::sendEvent(&scene, &mouseEvent);
+
+ for (int j = 1; j >= 0; --j) {
+ int i = j ? 0 : 14;
+ forever {
+ if (j) {
+ QVERIFY(!items.at(i)->isHovered);
+ } else {
+ if (i == 14)
+ QVERIFY(!items.at(13)->isHovered);
+ }
+ mouseEvent.setScenePos(items.at(i)->mapToScene(0, 0));
+ QApplication::sendEvent(&scene, &mouseEvent);
+
+ qApp->processEvents(); // this posts updates from the scene to the view
+ qApp->processEvents(); // which trigger a repaint here
+
+ QTRY_VERIFY(items.at(i)->isHovered);
+ if (i < 14)
+ QVERIFY(!items.at(i + 1)->isHovered);
+ i += j ? 1 : -1;
+ if ((j && i == 15) || (!j && i == -1))
+ break;
+ }
+
+ mouseEvent.setScenePos(QPointF(-1000, -1000));
+ QApplication::sendEvent(&scene, &mouseEvent);
+
+ qApp->processEvents(); // this posts updates from the scene to the view
+ qApp->processEvents(); // which trigger a repaint here
+ }
+}
+
+void tst_QGraphicsScene::createItemGroup()
+{
+ QGraphicsScene scene;
+
+ QList<QGraphicsItem *> children1;
+ children1 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children1 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children1 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children1 << scene.addRect(QRectF(-10, -10, 20, 20));
+
+ QList<QGraphicsItem *> children2;
+ children2 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children2 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children2 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children2 << scene.addRect(QRectF(-10, -10, 20, 20));
+
+ QList<QGraphicsItem *> children3;
+ children3 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children3 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children3 << scene.addRect(QRectF(-10, -10, 20, 20));
+ children3 << scene.addRect(QRectF(-10, -10, 20, 20));
+
+ // All items in children1 are children of parent1
+ QGraphicsItem *parent1 = scene.addRect(QRectF(-10, -10, 20, 20));
+ foreach (QGraphicsItem *item, children1)
+ item->setParentItem(parent1);
+
+ QGraphicsItemGroup *group = scene.createItemGroup(children1);
+ QCOMPARE(group->parentItem(), parent1);
+ QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group);
+ scene.destroyItemGroup(group);
+ QCOMPARE(children1.first()->parentItem(), parent1);
+ group = scene.createItemGroup(children1);
+ QCOMPARE(group->parentItem(), parent1);
+ QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group);
+ scene.destroyItemGroup(group);
+ QCOMPARE(children1.first()->parentItem(), parent1);
+
+ // All items in children2 are children of parent2
+ QGraphicsItem *parent2 = scene.addRect(QRectF(-10, -10, 20, 20));
+ foreach (QGraphicsItem *item, children2)
+ item->setParentItem(parent2);
+
+ // Now make parent2 a child of parent1, so all children2 are also children
+ // of parent1.
+ parent2->setParentItem(parent1);
+
+ // The children2 group should still have parent2 as their common ancestor.
+ group = scene.createItemGroup(children2);
+ QCOMPARE(group->parentItem(), parent2);
+ QCOMPARE(children2.first()->parentItem(), (QGraphicsItem *)group);
+ scene.destroyItemGroup(group);
+ QCOMPARE(children2.first()->parentItem(), parent2);
+
+ // But the set of both children2 and children1 share only parent1.
+ group = scene.createItemGroup(children2 + children1);
+ QCOMPARE(group->parentItem(), parent1);
+ QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group);
+ QCOMPARE(children2.first()->parentItem(), (QGraphicsItem *)group);
+ scene.destroyItemGroup(group);
+ QCOMPARE(children1.first()->parentItem(), parent1);
+ QCOMPARE(children2.first()->parentItem(), parent1);
+
+ // Fixup the parent-child chain
+ foreach (QGraphicsItem *item, children2)
+ item->setParentItem(parent2);
+
+ // These share no common parent
+ group = scene.createItemGroup(children3);
+ QCOMPARE(group->parentItem(), (QGraphicsItem *)0);
+ scene.destroyItemGroup(group);
+
+ // Make children3 children of parent3
+ QGraphicsItem *parent3 = scene.addRect(QRectF(-10, -10, 20, 20));
+ foreach (QGraphicsItem *item, children3)
+ item->setParentItem(parent3);
+
+ // These should have parent3 as a parent
+ group = scene.createItemGroup(children3);
+ QCOMPARE(group->parentItem(), parent3);
+ scene.destroyItemGroup(group);
+
+ // Now make them all children of parent1
+ parent3->setParentItem(parent1);
+
+ group = scene.createItemGroup(children3);
+ QCOMPARE(group->parentItem(), parent3);
+ scene.destroyItemGroup(group);
+
+ group = scene.createItemGroup(children2);
+ QCOMPARE(group->parentItem(), parent2);
+ scene.destroyItemGroup(group);
+
+ group = scene.createItemGroup(children1);
+ QCOMPARE(group->parentItem(), parent1);
+ scene.destroyItemGroup(group);
+
+ QGraphicsItemGroup *emptyGroup = scene.createItemGroup(QList<QGraphicsItem *>());
+ QCOMPARE(emptyGroup->children(), QList<QGraphicsItem *>());
+ QVERIFY(!emptyGroup->parentItem());
+ QCOMPARE(emptyGroup->scene(), &scene);
+}
+
+class EventTester : public QGraphicsEllipseItem
+{
+public:
+ EventTester()
+ : QGraphicsEllipseItem(QRectF(-10, -10, 20, 20)), ignoreMouse(false)
+ { }
+
+ bool ignoreMouse;
+ QList<QEvent::Type> eventTypes;
+
+protected:
+ bool sceneEvent(QEvent *event)
+ {
+ eventTypes << QEvent::Type(event->type());
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ if (ignoreMouse) {
+ event->ignore();
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return QGraphicsEllipseItem::sceneEvent(event);
+ }
+};
+
+void tst_QGraphicsScene::mouseEventPropagation()
+{
+ EventTester *a = new EventTester;
+ EventTester *b = new EventTester;
+ EventTester *c = new EventTester;
+ EventTester *d = new EventTester;
+ b->setParentItem(a);
+ c->setParentItem(b);
+ d->setParentItem(c);
+
+ a->setFlag(QGraphicsItem::ItemIsMovable);
+ b->setFlag(QGraphicsItem::ItemIsMovable);
+ c->setFlag(QGraphicsItem::ItemIsMovable);
+ d->setFlag(QGraphicsItem::ItemIsMovable);
+
+ a->setData(0, "A");
+ b->setData(0, "B");
+ c->setData(0, "C");
+ d->setData(0, "D");
+
+ // scene -> a -> b -> c -> d
+ QGraphicsScene scene;
+ QEvent activate(QEvent::WindowActivate);
+ QApplication::sendEvent(&scene, &activate);
+
+ scene.addItem(a);
+
+ // Prepare some events
+ QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+ pressEvent.setButton(Qt::LeftButton);
+ pressEvent.setScenePos(QPointF(0, 0));
+ QGraphicsSceneMouseEvent moveEvent(QEvent::GraphicsSceneMouseMove);
+ moveEvent.setButton(Qt::LeftButton);
+ moveEvent.setScenePos(QPointF(0, 0));
+ QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
+ releaseEvent.setButton(Qt::LeftButton);
+ releaseEvent.setScenePos(QPointF(0, 0));
+
+ // Send a press
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(d->eventTypes.size(), 2);
+ QCOMPARE(d->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(d->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(c->eventTypes.size(), 0);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)d);
+
+ // Send a move
+ QApplication::sendEvent(&scene, &moveEvent);
+ QCOMPARE(d->eventTypes.size(), 3);
+ QCOMPARE(d->eventTypes.at(2), QEvent::GraphicsSceneMouseMove);
+ QCOMPARE(c->eventTypes.size(), 0);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)d);
+
+ // Send a release
+ QApplication::sendEvent(&scene, &releaseEvent);
+ QCOMPARE(d->eventTypes.size(), 5);
+ QCOMPARE(d->eventTypes.at(3), QEvent::GraphicsSceneMouseRelease);
+ QCOMPARE(d->eventTypes.at(4), QEvent::UngrabMouse);
+ QCOMPARE(c->eventTypes.size(), 0);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+
+ d->setAcceptedMouseButtons(Qt::RightButton);
+
+ // Send a press
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(d->eventTypes.size(), 5);
+ QCOMPARE(c->eventTypes.size(), 2);
+ QCOMPARE(c->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(c->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c);
+
+ // Send another press, with a button that isn't actually accepted
+ QApplication::sendEvent(&scene, &pressEvent);
+ pressEvent.setButton(Qt::RightButton);
+ QCOMPARE(d->eventTypes.size(), 5);
+ QCOMPARE(c->eventTypes.size(), 3);
+ QCOMPARE(c->eventTypes.at(2), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c);
+
+ // Send a move
+ QApplication::sendEvent(&scene, &moveEvent);
+ QCOMPARE(d->eventTypes.size(), 5);
+ QCOMPARE(c->eventTypes.size(), 4);
+ QCOMPARE(c->eventTypes.at(3), QEvent::GraphicsSceneMouseMove);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c);
+
+ // Send a release
+ QApplication::sendEvent(&scene, &releaseEvent);
+ QCOMPARE(d->eventTypes.size(), 5);
+ QCOMPARE(c->eventTypes.size(), 6);
+ QCOMPARE(c->eventTypes.at(4), QEvent::GraphicsSceneMouseRelease);
+ QCOMPARE(c->eventTypes.at(5), QEvent::UngrabMouse);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+
+ // Disabled items eat events. c should not get this.
+ d->setEnabled(false);
+ d->setAcceptedMouseButtons(Qt::RightButton);
+
+ // Send a right press. This disappears in d.
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(d->eventTypes.size(), 5);
+ QCOMPARE(c->eventTypes.size(), 6);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
+
+ // Send a left press. This goes to c.
+ pressEvent.setButton(Qt::LeftButton);
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(d->eventTypes.size(), 5);
+ QCOMPARE(c->eventTypes.size(), 8);
+ QCOMPARE(c->eventTypes.at(6), QEvent::GrabMouse);
+ QCOMPARE(c->eventTypes.at(7), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(b->eventTypes.size(), 0);
+ QCOMPARE(a->eventTypes.size(), 0);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c);
+
+ // Clicking outside the items removes the mouse grabber
+}
+
+void tst_QGraphicsScene::mouseEventPropagation_ignore()
+{
+ EventTester *a = new EventTester;
+ EventTester *b = new EventTester;
+ EventTester *c = new EventTester;
+ EventTester *d = new EventTester;
+ b->setParentItem(a);
+ c->setParentItem(b);
+ d->setParentItem(c);
+
+ a->setFlags(QGraphicsItem::ItemIsMovable);
+ b->setFlags(QGraphicsItem::ItemIsMovable);
+ c->setFlags(QGraphicsItem::ItemIsMovable);
+ d->setFlags(QGraphicsItem::ItemIsMovable);
+
+ // scene -> a -> b -> c -> d
+ QGraphicsScene scene;
+ scene.addItem(a);
+
+ // Prepare some events
+ QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+ pressEvent.setButton(Qt::LeftButton);
+ pressEvent.setScenePos(QPointF(0, 0));
+
+ b->ignoreMouse = true;
+ c->ignoreMouse = true;
+ d->ignoreMouse = true;
+
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(a->eventTypes.size(), 2);
+ QCOMPARE(a->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(a->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(b->eventTypes.size(), 3);
+ QCOMPARE(b->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(b->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(b->eventTypes.at(2), QEvent::UngrabMouse);
+ QCOMPARE(c->eventTypes.size(), 3);
+ QCOMPARE(c->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(c->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(c->eventTypes.at(2), QEvent::UngrabMouse);
+ QCOMPARE(d->eventTypes.size(), 3);
+ QCOMPARE(d->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(d->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(d->eventTypes.at(2), QEvent::UngrabMouse);
+ QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)a);
+
+ a->ignoreMouse = true;
+
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(a->eventTypes.size(), 3);
+ QCOMPARE(a->eventTypes.at(2), QEvent::GraphicsSceneMousePress);
+ QCOMPARE(b->eventTypes.size(), 3);
+ QCOMPARE(c->eventTypes.size(), 3);
+ QCOMPARE(d->eventTypes.size(), 3);
+
+ QVERIFY(!pressEvent.isAccepted());
+}
+
+void tst_QGraphicsScene::mouseEventPropagation_focus()
+{
+ EventTester *a = new EventTester;
+ EventTester *b = new EventTester;
+ EventTester *c = new EventTester;
+ EventTester *d = new EventTester;
+ b->setParentItem(a);
+ c->setParentItem(b);
+ d->setParentItem(c);
+
+ a->setFlag(QGraphicsItem::ItemIsMovable);
+ b->setFlag(QGraphicsItem::ItemIsMovable);
+ c->setFlag(QGraphicsItem::ItemIsMovable);
+ d->setFlag(QGraphicsItem::ItemIsMovable);
+
+ // scene -> a -> b -> c -> d
+ QGraphicsScene scene;
+ QEvent activate(QEvent::WindowActivate);
+ QApplication::sendEvent(&scene, &activate);
+
+ scene.addItem(a);
+
+ // Prepare some events
+ QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+ pressEvent.setButton(Qt::LeftButton);
+ pressEvent.setScenePos(QPointF(0, 0));
+
+ a->setFlag(QGraphicsItem::ItemIsFocusable);
+ QVERIFY(!a->hasFocus());
+
+ QApplication::sendEvent(&scene, &pressEvent);
+
+ QVERIFY(a->hasFocus());
+ QCOMPARE(a->eventTypes.size(), 1);
+ QCOMPARE(a->eventTypes.first(), QEvent::FocusIn);
+ QCOMPARE(d->eventTypes.size(), 2);
+ QCOMPARE(d->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(d->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+}
+
+void tst_QGraphicsScene::mouseEventPropagation_doubleclick()
+{
+ EventTester *a = new EventTester;
+ EventTester *b = new EventTester;
+ a->setFlags(QGraphicsItem::ItemIsMovable);
+ b->setFlags(QGraphicsItem::ItemIsMovable);
+
+ a->setPos(-50, 0);
+ b->setPos(50, 0);
+
+ QGraphicsScene scene;
+ scene.addItem(a);
+ scene.addItem(b);
+
+ // Prepare some events
+ QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
+ pressEvent.setButton(Qt::LeftButton);
+ pressEvent.setScenePos(QPointF(0, 0));
+ QGraphicsSceneMouseEvent doubleClickEvent(QEvent::GraphicsSceneMouseDoubleClick);
+ doubleClickEvent.setButton(Qt::LeftButton);
+ doubleClickEvent.setScenePos(QPointF(0, 0));
+ QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
+ releaseEvent.setButton(Qt::LeftButton);
+ releaseEvent.setScenePos(QPointF(0, 0));
+
+ // Send press to A
+ pressEvent.setScenePos(a->mapToScene(0, 0));
+ QApplication::sendEvent(&scene, &pressEvent);
+ QCOMPARE(a->eventTypes.size(), 2);
+ QCOMPARE(a->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(a->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+
+ // Send release to A
+ releaseEvent.setScenePos(a->mapToScene(0, 0));
+ QApplication::sendEvent(&scene, &releaseEvent);
+ QCOMPARE(a->eventTypes.size(), 4);
+ QCOMPARE(a->eventTypes.at(2), QEvent::GraphicsSceneMouseRelease);
+ QCOMPARE(a->eventTypes.at(3), QEvent::UngrabMouse);
+
+ // Send doubleclick to B
+ doubleClickEvent.setScenePos(b->mapToScene(0, 0));
+ QApplication::sendEvent(&scene, &doubleClickEvent);
+ QCOMPARE(a->eventTypes.size(), 4);
+ QCOMPARE(b->eventTypes.size(), 2);
+ QCOMPARE(b->eventTypes.at(0), QEvent::GrabMouse);
+ QCOMPARE(b->eventTypes.at(1), QEvent::GraphicsSceneMousePress);
+
+ // Send release to B
+ releaseEvent.setScenePos(b->mapToScene(0, 0));
+ QApplication::sendEvent(&scene, &releaseEvent);
+ QCOMPARE(a->eventTypes.size(), 4);
+ QCOMPARE(b->eventTypes.size(), 4);
+ QCOMPARE(b->eventTypes.at(2), QEvent::GraphicsSceneMouseRelease);
+ QCOMPARE(b->eventTypes.at(3), QEvent::UngrabMouse);
+}
+
+class Scene : public QGraphicsScene
+{
+public:
+ QList<QPointF> mouseMovePoints;
+
+protected:
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+ {
+ mouseMovePoints << event->scenePos();
+ }
+};
+
+void tst_QGraphicsScene::mouseEventPropagation_mouseMove()
+{
+ Scene scene;
+ scene.addRect(QRectF(5, 0, 12, 12));
+ scene.addRect(QRectF(15, 0, 12, 12))->setAcceptsHoverEvents(true);
+ for (int i = 0; i < 30; ++i) {
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
+ event.setScenePos(QPointF(i, 5));
+ QApplication::sendEvent(&scene, &event);
+ }
+
+ QCOMPARE(scene.mouseMovePoints.size(), 30);
+ for (int i = 0; i < 30; ++i)
+ QCOMPARE(scene.mouseMovePoints.at(i), QPointF(i, 5));
+}
+
+class DndTester : public QGraphicsEllipseItem
+{
+public:
+ DndTester(const QRectF &rect)
+ : QGraphicsEllipseItem(rect), lastEvent(0),
+ ignoresDragEnter(false), ignoresDragMove(false)
+
+ {
+ }
+
+ ~DndTester()
+ {
+ delete lastEvent;
+ }
+
+ QGraphicsSceneDragDropEvent *lastEvent;
+ QList<QEvent::Type> eventList;
+ bool ignoresDragEnter;
+ bool ignoresDragMove;
+
+protected:
+ void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
+ {
+ storeLastEvent(event);
+ event->setAccepted(!ignoresDragEnter);
+ if (!ignoresDragEnter)
+ event->setDropAction(Qt::IgnoreAction);
+ eventList << event->type();
+ }
+
+ void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
+ {
+ storeLastEvent(event);
+ event->setAccepted(!ignoresDragMove);
+ eventList << event->type();
+ }
+
+ void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
+ {
+ storeLastEvent(event);
+ eventList << event->type();
+ }
+
+ void dropEvent(QGraphicsSceneDragDropEvent *event)
+ {
+ storeLastEvent(event);
+ eventList << event->type();
+ }
+
+private:
+ void storeLastEvent(QGraphicsSceneDragDropEvent *event)
+ {
+ delete lastEvent;
+ lastEvent = new QGraphicsSceneDragDropEvent(event->type());
+ lastEvent->setScenePos(event->scenePos());
+ lastEvent->setScreenPos(event->screenPos());
+ lastEvent->setButtons(event->buttons());
+ lastEvent->setModifiers(event->modifiers());
+ lastEvent->setPossibleActions(event->possibleActions());
+ lastEvent->setProposedAction(event->proposedAction());
+ lastEvent->setDropAction(event->dropAction());
+ lastEvent->setMimeData(event->mimeData());
+ lastEvent->setWidget(event->widget());
+ lastEvent->setSource(event->source());
+ }
+};
+
+#ifndef QT_NO_DRAGANDDROP
+void tst_QGraphicsScene::dragAndDrop_simple()
+{
+ DndTester *item = new DndTester(QRectF(-10, -10, 20, 20));
+
+ QGraphicsScene scene;
+ scene.addItem(item);
+
+ QGraphicsView view(&scene);
+ view.setFixedSize(100, 100);
+
+ QMimeData mimeData;
+
+ // Initial drag enter for the scene
+ QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragEnter);
+ QVERIFY(dragEnter.isAccepted());
+ QCOMPARE(dragEnter.dropAction(), Qt::CopyAction);
+
+ {
+ // Move outside the item
+ QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ }
+ {
+ // Move inside the item without setAcceptDrops
+ QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ QCOMPARE(item->eventList.size(), 0);
+ }
+ item->setAcceptDrops(true);
+ {
+ // Move inside the item with setAcceptDrops
+ QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction);
+ QCOMPARE(item->eventList.size(), 2);
+ QCOMPARE(item->eventList.at(0), QEvent::GraphicsSceneDragEnter);
+ QCOMPARE(item->eventList.at(1), QEvent::GraphicsSceneDragMove);
+ QCOMPARE(item->lastEvent->screenPos(), view.mapToGlobal(dragMove.pos()));
+ QCOMPARE(item->lastEvent->scenePos(), view.mapToScene(dragMove.pos()));
+ QVERIFY(item->lastEvent->isAccepted());
+ QCOMPARE(item->lastEvent->dropAction(), Qt::IgnoreAction);
+ }
+ {
+ // Another move inside the item
+ QDragMoveEvent dragMove(view.mapFromScene(item->mapToScene(5, 5)), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction);
+ QCOMPARE(item->eventList.size(), 3);
+ QCOMPARE(item->eventList.at(2), QEvent::GraphicsSceneDragMove);
+ QCOMPARE(item->lastEvent->screenPos(), view.mapToGlobal(dragMove.pos()));
+ QCOMPARE(item->lastEvent->scenePos(), view.mapToScene(dragMove.pos()));
+ QVERIFY(item->lastEvent->isAccepted());
+ QCOMPARE(item->lastEvent->dropAction(), Qt::IgnoreAction);
+ }
+ {
+ // Move outside the item
+ QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ QCOMPARE(item->eventList.size(), 4);
+ QCOMPARE(item->eventList.at(3), QEvent::GraphicsSceneDragLeave);
+ QCOMPARE(item->lastEvent->screenPos(), view.mapToGlobal(dragMove.pos()));
+ QCOMPARE(item->lastEvent->scenePos(), view.mapToScene(dragMove.pos()));
+ QVERIFY(item->lastEvent->isAccepted());
+ QCOMPARE(item->lastEvent->dropAction(), Qt::CopyAction);
+ }
+ {
+ // Move inside the item again
+ QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction);
+ QCOMPARE(item->eventList.size(), 6);
+ QCOMPARE(item->eventList.at(4), QEvent::GraphicsSceneDragEnter);
+ QCOMPARE(item->eventList.at(5), QEvent::GraphicsSceneDragMove);
+ QCOMPARE(item->lastEvent->screenPos(), view.mapToGlobal(dragMove.pos()));
+ QCOMPARE(item->lastEvent->scenePos(), view.mapToScene(dragMove.pos()));
+ QVERIFY(item->lastEvent->isAccepted());
+ QCOMPARE(item->lastEvent->dropAction(), Qt::IgnoreAction);
+ }
+ {
+ // Drop inside the item
+ QDropEvent drop(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &drop);
+ QVERIFY(drop.isAccepted());
+ QCOMPARE(drop.dropAction(), Qt::CopyAction);
+ QCOMPARE(item->eventList.size(), 7);
+ QCOMPARE(item->eventList.at(6), QEvent::GraphicsSceneDrop);
+ QCOMPARE(item->lastEvent->screenPos(), view.mapToGlobal(drop.pos()));
+ QCOMPARE(item->lastEvent->scenePos(), view.mapToScene(drop.pos()));
+ QVERIFY(item->lastEvent->isAccepted());
+ QCOMPARE(item->lastEvent->dropAction(), Qt::CopyAction);
+ }
+}
+
+void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible()
+{
+ DndTester *item = new DndTester(QRectF(-10, -10, 20, 20));
+ item->setAcceptDrops(true);
+
+ QGraphicsScene scene;
+ scene.addItem(item);
+
+ QGraphicsView view(&scene);
+ view.setFixedSize(100, 100);
+
+ QMimeData mimeData;
+
+ // Initial drag enter for the scene
+ QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragEnter);
+ QVERIFY(dragEnter.isAccepted());
+ QCOMPARE(dragEnter.dropAction(), Qt::CopyAction);
+ {
+ // Move inside the item
+ QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction);
+ QCOMPARE(item->eventList.size(), 2);
+ QCOMPARE(item->eventList.at(0), QEvent::GraphicsSceneDragEnter);
+ QCOMPARE(item->eventList.at(1), QEvent::GraphicsSceneDragMove);
+ }
+ {
+ // Move outside the item
+ QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ QCOMPARE(item->eventList.size(), 3);
+ QCOMPARE(item->eventList.at(2), QEvent::GraphicsSceneDragLeave);
+ }
+
+ // Now disable the item
+ item->setEnabled(false);
+ QVERIFY(!item->isEnabled());
+ QVERIFY(item->isVisible());
+
+ {
+ // Move inside the item
+ QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ QCOMPARE(item->eventList.size(), 3);
+ QCOMPARE(item->eventList.at(2), QEvent::GraphicsSceneDragLeave);
+ }
+
+ // Reenable it, and make it invisible
+ item->setEnabled(true);
+ item->setVisible(false);
+ QVERIFY(item->isEnabled());
+ QVERIFY(!item->isVisible());
+
+ {
+ // Move inside the item
+ QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ QCOMPARE(item->eventList.size(), 3);
+ QCOMPARE(item->eventList.at(2), QEvent::GraphicsSceneDragLeave);
+ }
+
+ // Dummy drop event to keep the Mac from crashing.
+ QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dropEvent);
+}
+
+void tst_QGraphicsScene::dragAndDrop_propagate()
+{
+ DndTester *item1 = new DndTester(QRectF(-10, -10, 20, 20));
+ DndTester *item2 = new DndTester(QRectF(0, 0, 20, 20));
+ item1->setAcceptDrops(true);
+ item2->setAcceptDrops(true);
+ item2->ignoresDragMove = true;
+ item2->ignoresDragEnter = false;
+ item2->setZValue(1);
+
+ item1->setData(0, "item1");
+ item2->setData(0, "item2");
+
+ QGraphicsScene scene;
+ scene.addItem(item1);
+ scene.addItem(item2);
+
+ QGraphicsView view(&scene);
+ view.setFixedSize(100, 100);
+
+ QMimeData mimeData;
+
+ // Initial drag enter for the scene
+ QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragEnter);
+ QVERIFY(dragEnter.isAccepted());
+ QCOMPARE(dragEnter.dropAction(), Qt::CopyAction);
+
+ {
+ // Move outside the items
+ QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ QVERIFY(item1->eventList.isEmpty());
+ QVERIFY(item2->eventList.isEmpty());
+ }
+ {
+ // Move inside item1
+ QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction);
+ QCOMPARE(item1->eventList.size(), 2);
+ QCOMPARE(item1->eventList.at(0), QEvent::GraphicsSceneDragEnter);
+ QCOMPARE(item1->eventList.at(1), QEvent::GraphicsSceneDragMove);
+ }
+
+ {
+ // Move into the intersection item1-item2
+ QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted()); // move does not propagate, (ignoresDragMove = true)
+ QCOMPARE(item1->eventList.size(), 3);
+ QCOMPARE(item1->eventList.at(2), QEvent::GraphicsSceneDragLeave);
+ QCOMPARE(item2->eventList.size(), 2);
+ QCOMPARE(item2->eventList.at(0), QEvent::GraphicsSceneDragEnter);
+ QCOMPARE(item2->eventList.at(1), QEvent::GraphicsSceneDragMove);
+ }
+ {
+ // Move into the item2
+ QDragMoveEvent dragMove(view.mapFromScene(15, 15), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(!dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::CopyAction);
+ QCOMPARE(item1->eventList.size(), 3);
+ QCOMPARE(item2->eventList.size(), 3);
+ QCOMPARE(item2->eventList.at(2), QEvent::GraphicsSceneDragMove);
+ }
+ {
+ // Move inside item1
+ QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(dragMove.isAccepted());
+ QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction);
+ QCOMPARE(item1->eventList.size(), 5);
+ QCOMPARE(item1->eventList.at(3), QEvent::GraphicsSceneDragEnter);
+ QCOMPARE(item1->eventList.at(4), QEvent::GraphicsSceneDragMove);
+ QCOMPARE(item2->eventList.size(), 4);
+ QCOMPARE(item2->eventList.at(3), QEvent::GraphicsSceneDragLeave);
+ }
+
+ {
+ item2->ignoresDragEnter = true;
+ // Move into the intersection item1-item2
+ QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dragMove);
+ QVERIFY(dragMove.isAccepted()); // dragEnter propagates down to item1, which then accepts the move event.
+ QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction);
+ QCOMPARE(item1->eventList.size(), 6);
+ QCOMPARE(item1->eventList.at(5), QEvent::GraphicsSceneDragMove);
+ QCOMPARE(item2->eventList.size(), 5);
+ QCOMPARE(item2->eventList.at(4), QEvent::GraphicsSceneDragEnter);
+ }
+
+ {
+ item2->ignoresDragEnter = false;
+ // Drop on the intersection item1-item2
+ QDropEvent drop(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &drop);
+ QVERIFY(drop.isAccepted());
+ QCOMPARE(drop.dropAction(), Qt::CopyAction);
+
+ QCOMPARE(item1->eventList.size(), 7);
+ QCOMPARE(item1->eventList.at(6), QEvent::GraphicsSceneDrop);
+ QCOMPARE(item2->eventList.size(), 5);
+ }
+
+ // Dummy drop event to keep the Mac from crashing.
+ QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0);
+ QApplication::sendEvent(view.viewport(), &dropEvent);
+}
+#endif
+
+void tst_QGraphicsScene::render_data()
+{
+ QTest::addColumn<QRectF>("targetRect");
+ QTest::addColumn<QRectF>("sourceRect");
+ QTest::addColumn<Qt::AspectRatioMode>("aspectRatioMode");
+ QTest::addColumn<QMatrix>("matrix");
+ QTest::addColumn<QPainterPath>("clip");
+
+ QPainterPath clip_rect;
+ clip_rect.addRect(50, 100, 200, 150);
+
+ QPainterPath clip_ellipse;
+ clip_ellipse.addEllipse(100,50,150,200);
+
+ QTest::newRow("all-all-untransformed") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("all-topleft-untransformed") << QRectF(0, 0, 150, 150)
+ << QRectF() << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("all-topright-untransformed") << QRectF(150, 0, 150, 150)
+ << QRectF() << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("all-bottomleft-untransformed") << QRectF(0, 150, 150, 150)
+ << QRectF() << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("all-bottomright-untransformed") << QRectF(150, 150, 150, 150)
+ << QRectF() << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("topleft-all-untransformed") << QRectF() << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("topright-all-untransformed") << QRectF() << QRectF(0, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("bottomleft-all-untransformed") << QRectF() << QRectF(-10, 0, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("bottomright-all-untransformed") << QRectF() << QRectF(0, 0, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("topleft-topleft-untransformed") << QRectF(0, 0, 150, 150) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("topright-topleft-untransformed") << QRectF(150, 0, 150, 150) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("bottomleft-topleft-untransformed") << QRectF(0, 150, 150, 150) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("bottomright-topleft-untransformed") << QRectF(150, 150, 150, 150) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("top-topleft-untransformed") << QRectF(0, 0, 300, 150) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("bottom-topleft-untransformed") << QRectF(0, 150, 300, 150) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("left-topleft-untransformed") << QRectF(0, 0, 150, 300) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("right-topleft-untransformed") << QRectF(150, 0, 150, 300) << QRectF(-10, -10, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("top-bottomright-untransformed") << QRectF(0, 0, 300, 150) << QRectF(0, 0, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("bottom-bottomright-untransformed") << QRectF(0, 150, 300, 150) << QRectF(0, 0, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("left-bottomright-untransformed") << QRectF(0, 0, 150, 300) << QRectF(0, 0, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("right-bottomright-untransformed") << QRectF(150, 0, 150, 300) << QRectF(0, 0, 10, 10)
+ << Qt::IgnoreAspectRatio << QMatrix() << QPainterPath();
+ QTest::newRow("all-all-45-deg-right") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix().rotate(-45) << QPainterPath();
+ QTest::newRow("all-all-45-deg-left") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix().rotate(45) << QPainterPath();
+ QTest::newRow("all-all-scale-2x") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix().scale(2, 2) << QPainterPath();
+ QTest::newRow("all-all-translate-50-0") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix().translate(50, 0) << QPainterPath();
+ QTest::newRow("all-all-translate-0-50") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix().translate(0, 50) << QPainterPath();
+ QTest::newRow("all-all-untransformed-clip-rect") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix() << clip_rect;
+ QTest::newRow("all-all-untransformed-clip-ellipse") << QRectF() << QRectF()
+ << Qt::IgnoreAspectRatio << QMatrix() << clip_ellipse;
+}
+
+void tst_QGraphicsScene::render()
+{
+ QFETCH(QRectF, targetRect);
+ QFETCH(QRectF, sourceRect);
+ QFETCH(Qt::AspectRatioMode, aspectRatioMode);
+ QFETCH(QMatrix, matrix);
+ QFETCH(QPainterPath, clip);
+
+ QPixmap pix(30, 30);
+ pix.fill(Qt::blue);
+
+ QGraphicsView view;
+ QGraphicsScene scene(&view);
+ scene.addEllipse(QRectF(-10, -10, 20, 20), QPen(Qt::black), QBrush(Qt::white));
+ scene.addEllipse(QRectF(-2, -7, 4, 4), QPen(Qt::black), QBrush(Qt::yellow))->setZValue(1);
+ QGraphicsPixmapItem *item = scene.addPixmap(pix);
+ item->setZValue(2);
+ item->setOffset(QPointF(3, 3));
+ view.show();
+
+ scene.setSceneRect(scene.itemsBoundingRect());
+
+ QImage bigImage(300, 300, QImage::Format_RGB32);
+ bigImage.fill(0);
+ QPainter painter(&bigImage);
+ painter.setPen(Qt::lightGray);
+ for (int i = 0; i <= 300; i += 25) {
+ painter.drawLine(0, i, 300, i);
+ painter.drawLine(i, 0, i, 300);
+ }
+ painter.setPen(QPen(Qt::darkGray, 2));
+ painter.drawLine(0, 150, 300, 150);
+ painter.drawLine(150, 0, 150, 300);
+ painter.setMatrix(matrix);
+ if (!clip.isEmpty()) painter.setClipPath(clip);
+ scene.render(&painter, targetRect, sourceRect, aspectRatioMode);
+ painter.end();
+
+ const QString renderPath = QLatin1String(SRCDIR) + "/testData/render";
+ QString fileName = renderPath + QString("/%1.png").arg(QTest::currentDataTag());
+ QImage original(fileName);
+ QVERIFY(!original.isNull());
+
+ // Compare
+ int wrongPixels = 0;
+ for (int y = 0; y < original.height(); ++y) {
+ for (int x = 0; x < original.width(); ++x) {
+ if (bigImage.pixel(x, y) != original.pixel(x, y))
+ ++wrongPixels;
+ }
+ }
+
+ // This is a pixmap compare test - because of rounding errors on diverse
+ // platforms, and especially because tests are compiled in release mode,
+ // we set a 95% acceptance threshold for comparing images. This number may
+ // have to be adjusted if this test fails.
+ qreal threshold = 0.95;
+ qreal similarity = (1 - (wrongPixels / qreal(original.width() * original.height())));
+ if (similarity < threshold) {
+#if 1
+ // fail
+ QLabel *expectedLabel = new QLabel;
+ expectedLabel->setPixmap(QPixmap::fromImage(original));
+
+ QLabel *newLabel = new QLabel;
+ newLabel->setPixmap(QPixmap::fromImage(bigImage));
+
+ QGridLayout *gridLayout = new QGridLayout;
+ gridLayout->addWidget(new QLabel(tr("MISMATCH: %1").arg(QTest::currentDataTag())), 0, 0, 1, 2);
+ gridLayout->addWidget(new QLabel(tr("Current")), 1, 0);
+ gridLayout->addWidget(new QLabel(tr("Expected")), 1, 1);
+ gridLayout->addWidget(expectedLabel, 2, 1);
+ gridLayout->addWidget(newLabel, 2, 0);
+
+ QWidget widget;
+ widget.setLayout(gridLayout);
+ widget.show();
+
+ QTestEventLoop::instance().enterLoop(1);
+
+ QFAIL("Images are not identical.");
+#else
+ // generate
+ qDebug() << "Updating" << QTest::currentDataTag() << ":" << bigImage.save(fileName, "png");
+#endif
+ }
+}
+
+void tst_QGraphicsScene::renderItemsWithNegativeWidthOrHeight()
+{
+ QGraphicsScene scene(0, 0, 150, 150);
+
+ // Add item with negative width.
+ QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, -150, 50);
+ item1->setBrush(Qt::red);
+ item1->setPos(150, 50);
+ scene.addItem(item1);
+
+ // Add item with negative height.
+ QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 50, -150);
+ item2->setBrush(Qt::blue);
+ item2->setPos(50, 150);
+ scene.addItem(item2);
+
+ QGraphicsView view(&scene);
+ view.setFrameStyle(QFrame::NoFrame);
+ view.resize(150, 150);
+ view.show();
+ QCOMPARE(view.viewport()->size(), QSize(150, 150));
+
+ QImage expected(view.viewport()->size(), QImage::Format_RGB32);
+ view.viewport()->render(&expected);
+
+ // Make sure the scene background is the same as the viewport background.
+ scene.setBackgroundBrush(view.viewport()->palette().brush(view.viewport()->backgroundRole()));
+ QImage actual(150, 150, QImage::Format_RGB32);
+ QPainter painter(&actual);
+ scene.render(&painter);
+ painter.end();
+
+ QCOMPARE(actual, expected);
+}
+
+void tst_QGraphicsScene::contextMenuEvent()
+{
+ QGraphicsScene scene;
+ QEvent activate(QEvent::WindowActivate);
+ QApplication::sendEvent(&scene, &activate);
+
+ EventTester *item = new EventTester;
+ scene.addItem(item);
+ item->setFlag(QGraphicsItem::ItemIsFocusable);
+ item->setFocus();
+
+ QVERIFY(item->hasFocus());
+ QVERIFY(scene.hasFocus());
+
+ QGraphicsView view(&scene);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.activateWindow();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&view);
+#endif
+ view.centerOn(item);
+
+ {
+ QContextMenuEvent event(QContextMenuEvent::Keyboard, view.viewport()->rect().center(),
+ view.mapToGlobal(view.viewport()->rect().center()));
+ QApplication::sendEvent(view.viewport(), &event);
+ QCOMPARE(item->eventTypes.last(), QEvent::GraphicsSceneContextMenu);
+ }
+}
+
+class ContextMenuItem : public QGraphicsRectItem
+{
+public:
+ ContextMenuItem() : QGraphicsRectItem(0, 0, 100, 100)
+ { setBrush(Qt::red); }
+
+protected:
+ void contextMenuEvent(QGraphicsSceneContextMenuEvent *)
+ { /* just accept */ }
+};
+
+void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations()
+{
+ QGraphicsScene scene(0, 0, 200, 200);
+ ContextMenuItem *item = new ContextMenuItem;
+ item->setFlag(QGraphicsItem::ItemIgnoresTransformations);
+ scene.addItem(item);
+
+ QWidget topLevel;
+ QGraphicsView view(&scene, &topLevel);
+ view.resize(200, 200);
+ topLevel.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&view);
+#endif
+ QTest::qWaitForWindowShown(&topLevel);
+
+ {
+ QPoint pos(50, 50);
+ QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos));
+ event.ignore();
+ QApplication::sendEvent(view.viewport(), &event);
+ QVERIFY(event.isAccepted());
+ }
+ {
+ QPoint pos(150, 150);
+ QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos));
+ event.ignore();
+ QApplication::sendEvent(view.viewport(), &event);
+ QVERIFY(!event.isAccepted());
+ }
+ view.scale(1.5, 1.5);
+ {
+ QPoint pos(25, 25);
+ QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos));
+ event.ignore();
+ QApplication::sendEvent(view.viewport(), &event);
+ QVERIFY(event.isAccepted());
+ }
+ {
+ QPoint pos(55, 55);
+ QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos));
+ event.ignore();
+ QApplication::sendEvent(view.viewport(), &event);
+ QVERIFY(!event.isAccepted());
+ }
+}
+
+void tst_QGraphicsScene::update()
+{
+ QGraphicsScene scene;
+
+ QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 100, 100);
+ scene.addItem(rect);
+ qApp->processEvents();
+ rect->setPos(-100, -100);
+
+ // This function forces indexing
+ scene.itemAt(0, 0);
+
+ qRegisterMetaType<QList<QRectF> >("QList<QRectF>");
+ QSignalSpy spy(&scene, SIGNAL(changed(QList<QRectF>)));
+
+ // We update the scene.
+ scene.update();
+
+ // This function forces a purge, which will post an update signal
+ scene.itemAt(0, 0);
+
+ // This will process the pending update
+ QApplication::instance()->processEvents();
+
+ // Check that the update region is correct
+ QCOMPARE(spy.count(), 1);
+ QRectF region;
+ foreach (QRectF rectF, qVariantValue<QList<QRectF> >(spy.at(0).at(0)))
+ region |= rectF;
+ QCOMPARE(region, QRectF(-100, -100, 200, 200));
+}
+
+void tst_QGraphicsScene::update2()
+{
+ QGraphicsScene scene;
+ scene.setSceneRect(-200, -200, 200, 200);
+ CustomView view;
+ view.setScene(&scene);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QTRY_VERIFY(view.repaints >= 1);
+ view.repaints = 0;
+
+ // Make sure QGraphicsScene::update only requires one event-loop iteration
+ // before the view is updated.
+ scene.update();
+ qApp->processEvents();
+ QTRY_COMPARE(view.repaints, 1);
+ view.repaints = 0;
+
+ // The same for partial scene updates.
+ scene.update(QRectF(-100, -100, 100, 100));
+ qApp->processEvents();
+ QCOMPARE(view.repaints, 1);
+}
+
+void tst_QGraphicsScene::views()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+
+ QCOMPARE(scene.views().size(), 1);
+ QCOMPARE(scene.views().at(0), &view);
+
+ QGraphicsView view1(&scene);
+ QCOMPARE(scene.views().size(), 2);
+ QVERIFY(scene.views().contains(&view1));
+
+ view.setScene(0);
+ QCOMPARE(scene.views().size(), 1);
+ QCOMPARE(scene.views().at(0), &view1);
+
+ QGraphicsView *view2 = new QGraphicsView(&scene);
+ QCOMPARE(scene.views().size(), 2);
+ QCOMPARE(scene.views().at(0), &view1);
+ QCOMPARE(scene.views().at(1), view2);
+
+ delete view2;
+
+ QCOMPARE(scene.views().size(), 1);
+ QCOMPARE(scene.views().at(0), &view1);
+}
+
+class CustomScene : public QGraphicsScene
+{
+public:
+ CustomScene() : gotTimerEvent(false)
+ { startTimer(10); }
+
+ bool gotTimerEvent;
+protected:
+ void timerEvent(QTimerEvent *)
+ {
+ gotTimerEvent = true;
+ }
+};
+
+void tst_QGraphicsScene::event()
+{
+ // Test that QGraphicsScene properly propagates events to QObject.
+ CustomScene scene;
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(scene.gotTimerEvent);
+}
+
+class DisabledItemTester : public QGraphicsRectItem
+{
+public:
+ DisabledItemTester(const QRectF &rect, QGraphicsItem *parent = 0)
+ : QGraphicsRectItem(rect, parent)
+ { }
+
+ QList<QEvent::Type> receivedSceneEvents;
+ QList<QEvent::Type> receivedSceneEventFilters;
+
+protected:
+ bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+ {
+ receivedSceneEventFilters << event->type();
+ return QGraphicsRectItem::sceneEventFilter(watched, event);
+ }
+
+ bool sceneEvent(QEvent *event)
+ {
+ receivedSceneEvents << event->type();
+ return QGraphicsRectItem::sceneEvent(event);
+ }
+};
+
+void tst_QGraphicsScene::eventsToDisabledItems()
+{
+ QGraphicsScene scene;
+
+ DisabledItemTester *item1 = new DisabledItemTester(QRectF(-50, -50, 100, 100));
+ DisabledItemTester *item2 = new DisabledItemTester(QRectF(-50, -50, 100, 100));
+ item1->setZValue(1); // on top
+
+ scene.addItem(item1);
+ scene.addItem(item2);
+
+ item1->installSceneEventFilter(item2);
+
+ QVERIFY(item1->receivedSceneEvents.isEmpty());
+ QVERIFY(item2->receivedSceneEvents.isEmpty());
+ QVERIFY(item1->receivedSceneEventFilters.isEmpty());
+ QVERIFY(item2->receivedSceneEventFilters.isEmpty());
+
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+ event.setButton(Qt::LeftButton);
+ QApplication::sendEvent(&scene, &event);
+
+ // First item2 receives a scene event filter. Then item1 receives the
+ // actual event. Finally the event propagates to item2. So both items
+ // should have received the event, and item1 also got the filter.
+ QCOMPARE(item1->receivedSceneEvents.size(), 3);
+ QCOMPARE(item2->receivedSceneEvents.size(), 3);
+ QCOMPARE(item1->receivedSceneEventFilters.size(), 0);
+ QCOMPARE(item2->receivedSceneEventFilters.size(), 3);
+
+ item1->receivedSceneEvents.clear();
+ item1->receivedSceneEventFilters.clear();
+ item2->receivedSceneEvents.clear();
+ item2->receivedSceneEventFilters.clear();
+
+ item1->setEnabled(false); // disable the topmost item, eat mouse events
+
+ event.setButton(Qt::LeftButton);
+ event.setAccepted(false);
+ QApplication::sendEvent(&scene, &event);
+
+ // Check that only item1 received anything - it only got the filter.
+ QCOMPARE(item1->receivedSceneEvents.size(), 0);
+ QCOMPARE(item2->receivedSceneEvents.size(), 0);
+ QCOMPARE(item1->receivedSceneEventFilters.size(), 0);
+ QCOMPARE(item2->receivedSceneEventFilters.size(), 3);
+}
+
+class ExposedPixmapItem : public QGraphicsPixmapItem
+{
+public:
+ ExposedPixmapItem(QGraphicsItem *item = 0)
+ : QGraphicsPixmapItem(item)
+ { }
+
+ void paint(QPainter *, const QStyleOptionGraphicsItem *option, QWidget *)
+ {
+ exposed = option->exposedRect;
+ }
+
+ QRectF exposed;
+};
+
+void tst_QGraphicsScene::exposedRect()
+{
+ ExposedPixmapItem *item = new ExposedPixmapItem;
+ item->setPixmap(QPixmap(":/Ash_European.jpg"));
+ QGraphicsScene scene;
+ scene.addItem(item);
+
+ QCOMPARE(item->exposed, QRectF());
+
+ QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
+ QPainter painter(&image);
+
+ scene.render(&painter);
+ QCOMPARE(item->exposed, item->boundingRect());
+
+ painter.rotate(180);
+ painter.translate(100, 100);
+
+ scene.render(&painter);
+ QCOMPARE(item->exposed, item->boundingRect());
+}
+
+void tst_QGraphicsScene::tabFocus_emptyScene()
+{
+ QGraphicsScene scene;
+ QDial *dial1 = new QDial;
+ QGraphicsView *view = new QGraphicsView(&scene);
+ QDial *dial2 = new QDial;
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(dial1);
+ layout->addWidget(view);
+ layout->addWidget(dial2);
+
+ QWidget widget;
+ widget.setLayout(layout);
+ widget.show();
+ qApp->setActiveWindow(&widget);
+ widget.activateWindow();
+ QTest::qWait(125);
+
+ dial1->setFocus();
+ QVERIFY(dial1->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QVERIFY(!dial1->hasFocus());
+ QVERIFY(view->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QVERIFY(!view->hasFocus());
+ QVERIFY(dial2->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QVERIFY(!dial2->hasFocus());
+ QVERIFY(view->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QVERIFY(dial1->hasFocus());
+ QVERIFY(!dial2->hasFocus());
+}
+
+void tst_QGraphicsScene::tabFocus_sceneWithFocusableItems()
+{
+ QGraphicsScene scene;
+ QGraphicsTextItem *item = scene.addText("Qt rocks!");
+ item->setTabChangesFocus(true);
+ item->setTextInteractionFlags(Qt::TextEditorInteraction);
+ QVERIFY(item->flags() & QGraphicsItem::ItemIsFocusable);
+ item->setFocus();
+ item->clearFocus();
+
+ QGraphicsTextItem *item2 = scene.addText("Trolltech rocks!");
+ item2->setTabChangesFocus(true);
+ item2->setTextInteractionFlags(Qt::TextEditorInteraction);
+ item2->setPos(0, item->boundingRect().bottom());
+ QVERIFY(item2->flags() & QGraphicsItem::ItemIsFocusable);
+
+ QDial *dial1 = new QDial;
+ QGraphicsView *view = new QGraphicsView(&scene);
+ QDial *dial2 = new QDial;
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(dial1);
+ layout->addWidget(view);
+ layout->addWidget(dial2);
+
+ QWidget widget;
+ widget.setLayout(layout);
+ widget.show();
+ qApp->setActiveWindow(&widget);
+ widget.activateWindow();
+ QTest::qWaitForWindowShown(&widget);
+ QApplication::processEvents();
+
+ dial1->setFocus();
+ QTRY_VERIFY(dial1->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(view->hasFocus());
+ QVERIFY(view->viewport()->hasFocus());
+ QVERIFY(scene.hasFocus());
+ QVERIFY(item->hasFocus());
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(dial2->hasFocus());
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(view->hasFocus());
+ QTRY_VERIFY(view->viewport()->hasFocus());
+ QTRY_VERIFY(scene.hasFocus());
+ QTRY_VERIFY(item->hasFocus());
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(dial1->hasFocus());
+
+ // If the item requests input focus, it can only ensure that the scene
+ // sets focus on itself, but the scene cannot request focus from any view.
+ item->setFocus();
+ QApplication::processEvents();
+ QTRY_VERIFY(!view->hasFocus());
+ QVERIFY(!view->viewport()->hasFocus());
+ QTRY_VERIFY(scene.hasFocus());
+ QVERIFY(item->hasFocus());
+
+ view->setFocus();
+ QApplication::processEvents();
+ QTRY_VERIFY(view->hasFocus());
+ QTRY_VERIFY(view->viewport()->hasFocus());
+ QTRY_VERIFY(scene.hasFocus());
+ QTRY_VERIFY(item->hasFocus());
+
+ // Check that everyone loses focus when the widget is hidden.
+ widget.hide();
+ QTest::qWait(15);
+ QTRY_VERIFY(!view->hasFocus());
+ QVERIFY(!view->viewport()->hasFocus());
+ QVERIFY(!scene.hasFocus());
+ QVERIFY(!item->hasFocus());
+ QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
+
+ // Check that the correct item regains focus.
+ widget.show();
+ qApp->setActiveWindow(&widget);
+ widget.activateWindow();
+ QTest::qWaitForWindowShown(&widget);
+ QTRY_VERIFY(view->hasFocus());
+ QTRY_VERIFY(scene.isActive());
+ QVERIFY(view->viewport()->hasFocus());
+ QVERIFY(scene.hasFocus());
+ QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
+ QVERIFY(item->hasFocus());
+}
+
+class FocusWidget : public QGraphicsWidget
+{
+ Q_OBJECT
+public:
+ FocusWidget(QGraphicsItem *parent = 0)
+ : QGraphicsWidget(parent), tabs(0), backTabs(0)
+ {
+ setFocusPolicy(Qt::StrongFocus);
+ resize(100, 100);
+ }
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
+ {
+ if (option->state & QStyle::State_HasFocus) {
+ painter->fillRect(rect(), Qt::blue);
+ }
+ painter->setBrush(Qt::green);
+ painter->drawEllipse(rect());
+ if (option->state & QStyle::State_HasFocus) {
+ painter->setPen(QPen(Qt::black, 1, Qt::DashLine));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(rect().adjusted(5, 5, -5, -5));
+ }
+ }
+
+ int tabs;
+ int backTabs;
+
+protected:
+ bool sceneEvent(QEvent *event)
+ {
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *k = static_cast<QKeyEvent *>(event);
+ if (k->key() == Qt::Key_Tab)
+ ++tabs;
+ if (k->key() == Qt::Key_Backtab)
+ ++backTabs;
+ }
+ return QGraphicsWidget::sceneEvent(event);
+ }
+
+ void focusInEvent(QFocusEvent *)
+ { update(); }
+ void focusOutEvent(QFocusEvent *)
+ { update(); }
+};
+
+void tst_QGraphicsScene::tabFocus_sceneWithFocusWidgets()
+{
+ QGraphicsScene scene;
+
+ FocusWidget *widget1 = new FocusWidget;
+ FocusWidget *widget2 = new FocusWidget;
+ widget2->setPos(widget1->boundingRect().right(), 0);
+ scene.addItem(widget1);
+ scene.addItem(widget2);
+
+ QDial *dial1 = new QDial;
+ QGraphicsView *view = new QGraphicsView(&scene);
+ view->setRenderHint(QPainter::Antialiasing);
+ QDial *dial2 = new QDial;
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(dial1);
+ layout->addWidget(view);
+ layout->addWidget(dial2);
+
+ QWidget widget;
+ widget.setLayout(layout);
+ widget.show();
+ qApp->setActiveWindow(&widget);
+ widget.activateWindow();
+ QTest::qWaitForWindowShown(&widget);
+ QApplication::processEvents();
+
+ dial1->setFocus();
+ QTRY_VERIFY(dial1->hasFocus());
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(view->hasFocus());
+ QTRY_VERIFY(view->viewport()->hasFocus());
+ QTRY_VERIFY(scene.hasFocus());
+ QCOMPARE(widget1->tabs, 0);
+ QVERIFY(widget1->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_COMPARE(widget1->tabs, 1);
+ QTRY_VERIFY(widget2->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_COMPARE(widget2->tabs, 1);
+ QTRY_VERIFY(dial2->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(widget2->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_COMPARE(widget2->backTabs, 1);
+ QTRY_VERIFY(widget1->hasFocus());
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_COMPARE(widget1->backTabs, 1);
+ QTRY_VERIFY(dial1->hasFocus());
+
+ widget1->setFocus();
+ view->viewport()->setFocus();
+ widget.hide();
+ QTest::qWait(15);
+ widget.show();
+ qApp->setActiveWindow(&widget);
+ widget.activateWindow();
+ QTest::qWaitForWindowShown(&widget);
+ QTRY_VERIFY(widget1->hasFocus());
+}
+
+void tst_QGraphicsScene::tabFocus_sceneWithNestedFocusWidgets()
+{
+ QGraphicsScene scene;
+
+ FocusWidget *widget1 = new FocusWidget;
+ FocusWidget *widget1_1 = new FocusWidget;
+ FocusWidget *widget1_2 = new FocusWidget;
+ widget1_1->setParentItem(widget1);
+ widget1_1->scale(0.5, 0.5);
+ widget1_1->setPos(0, widget1->boundingRect().height() / 2);
+ widget1_2->setParentItem(widget1);
+ widget1_2->scale(0.5, 0.5);
+ widget1_2->setPos(widget1->boundingRect().width() / 2, widget1->boundingRect().height() / 2);
+
+ FocusWidget *widget2 = new FocusWidget;
+ widget2->setPos(widget1->boundingRect().right(), 0);
+
+ widget1->setData(0, "widget1");
+ widget1_1->setData(0, "widget1_1");
+ widget1_2->setData(0, "widget1_2");
+ widget2->setData(0, "widget2");
+
+ scene.addItem(widget1);
+ scene.addItem(widget2);
+
+ QDial *dial1 = new QDial;
+ QGraphicsView *view = new QGraphicsView(&scene);
+ view->setRenderHint(QPainter::Antialiasing);
+ QDial *dial2 = new QDial;
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(dial1);
+ layout->addWidget(view);
+ layout->addWidget(dial2);
+
+ QWidget widget;
+ widget.setLayout(layout);
+ widget.show();
+ qApp->setActiveWindow(&widget);
+ widget.activateWindow();
+ QTest::qWaitForWindowShown(&widget);
+
+ dial1->setFocus();
+ QTRY_VERIFY(dial1->hasFocus());
+
+ EventSpy focusInSpy_1(widget1, QEvent::FocusIn);
+ EventSpy focusOutSpy_1(widget1, QEvent::FocusOut);
+ EventSpy focusInSpy_1_1(widget1_1, QEvent::FocusIn);
+ EventSpy focusOutSpy_1_1(widget1_1, QEvent::FocusOut);
+ EventSpy focusInSpy_1_2(widget1_2, QEvent::FocusIn);
+ EventSpy focusOutSpy_1_2(widget1_2, QEvent::FocusOut);
+ EventSpy focusInSpy_2(widget2, QEvent::FocusIn);
+ EventSpy focusOutSpy_2(widget2, QEvent::FocusOut);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(widget1->hasFocus());
+ QCOMPARE(focusInSpy_1.count(), 1);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget1->hasFocus());
+ QVERIFY(widget1_1->hasFocus());
+ QCOMPARE(focusOutSpy_1.count(), 1);
+ QCOMPARE(focusInSpy_1_1.count(), 1);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget1_1->hasFocus());
+ QVERIFY(widget1_2->hasFocus());
+ QCOMPARE(focusOutSpy_1_1.count(), 1);
+ QCOMPARE(focusInSpy_1_2.count(), 1);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget1_2->hasFocus());
+ QVERIFY(widget2->hasFocus());
+ QCOMPARE(focusOutSpy_1_2.count(), 1);
+ QCOMPARE(focusInSpy_2.count(), 1);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget2->hasFocus());
+ QVERIFY(dial2->hasFocus());
+ QCOMPARE(focusOutSpy_2.count(), 1);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(widget2->hasFocus());
+ QCOMPARE(focusInSpy_2.count(), 2);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget2->hasFocus());
+ QTRY_VERIFY(widget1_2->hasFocus());
+ QCOMPARE(focusOutSpy_2.count(), 2);
+ QCOMPARE(focusInSpy_1_2.count(), 2);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget1_2->hasFocus());
+ QTRY_VERIFY(widget1_1->hasFocus());
+ QCOMPARE(focusOutSpy_1_2.count(), 2);
+ QCOMPARE(focusInSpy_1_1.count(), 2);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget1_1->hasFocus());
+ QTRY_VERIFY(widget1->hasFocus());
+ QCOMPARE(focusOutSpy_1_1.count(), 2);
+ QCOMPARE(focusInSpy_1.count(), 2);
+
+ QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab);
+ QApplication::processEvents();
+ QTRY_VERIFY(!widget1->hasFocus());
+ QTRY_VERIFY(dial1->hasFocus());
+ QCOMPARE(focusOutSpy_1.count(), 2);
+
+ widget1->setFocus();
+ view->viewport()->setFocus();
+ widget.hide();
+ QTest::qWait(12);
+ widget.show();
+ qApp->setActiveWindow(&widget);
+ widget.activateWindow();
+ QTest::qWaitForWindowShown(&widget);
+ QApplication::processEvents();
+ QTRY_VERIFY(widget1->hasFocus());
+}
+
+void tst_QGraphicsScene::style()
+{
+ QPointer<QWindowsStyle> windowsStyle = new QWindowsStyle;
+
+ QGraphicsScene scene;
+ QLineEdit *edit = new QLineEdit;
+ QGraphicsProxyWidget *proxy = scene.addWidget(edit);
+
+ EventSpy sceneSpy(&scene, QEvent::StyleChange);
+ EventSpy proxySpy(proxy, QEvent::StyleChange);
+ EventSpy editSpy(edit, QEvent::StyleChange);
+
+ QCOMPARE(scene.style(), QApplication::style());
+
+ scene.setStyle(windowsStyle);
+ QCOMPARE(sceneSpy.count(), 1);
+ QCOMPARE(proxySpy.count(), 1);
+ QCOMPARE(editSpy.count(), 1);
+ QCOMPARE(scene.style(), (QStyle *)windowsStyle);
+ QCOMPARE(proxy->style(), (QStyle *)windowsStyle);
+ QCOMPARE(edit->style(), (QStyle *)windowsStyle);
+
+ scene.setStyle(0);
+ QCOMPARE(sceneSpy.count(), 2);
+ QCOMPARE(proxySpy.count(), 2);
+ QCOMPARE(editSpy.count(), 2);
+ QCOMPARE(scene.style(), QApplication::style());
+ QCOMPARE(proxy->style(), QApplication::style());
+ QCOMPARE(edit->style(), QApplication::style());
+ QVERIFY(!windowsStyle); // deleted
+}
+
+void tst_QGraphicsScene::task139710_bspTreeCrash()
+{
+ // create a scene with 2000 items
+ QGraphicsScene scene(0, 0, 1000, 1000);
+
+ for (int i = 0; i < 2; ++i) {
+ // trigger delayed item indexing
+ qApp->processEvents();
+ scene.setSceneRect(0, 0, 10000, 10000);
+
+ // delete all items in the scene - pointers are now likely to be recycled
+ foreach (QGraphicsItem *item, scene.items()) {
+ scene.removeItem(item);
+ delete item;
+ }
+
+ // add 1000 more items - the BSP tree is now resized
+ for (int i = 0; i < 1000; ++i) {
+ QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 200, 200));
+ item->setPos(qrand() % 10000, qrand() % 10000);
+ }
+
+ // trigger delayed item indexing for the first 1000 items
+ qApp->processEvents();
+
+ // add 1000 more items - the BSP tree is now resized
+ for (int i = 0; i < 1000; ++i) {
+ QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 200, 200));
+ item->setPos(qrand() % 10000, qrand() % 10000);
+ }
+
+ // get items from the BSP tree and use them. there was junk in the tree
+ // the second time this happened.
+ foreach (QGraphicsItem *item, scene.items(QRectF(0, 0, 1000, 1000)))
+ item->moveBy(0, 0);
+ }
+}
+
+void tst_QGraphicsScene::task139782_containsItemBoundingRect()
+{
+ // The item in question has a scene bounding rect of (10, 10, 50, 50)
+ QGraphicsScene scene(0.0, 0.0, 200.0, 200.0);
+ QGraphicsRectItem *item = new QGraphicsRectItem(0.0, 0.0, 50.0, 50.0, 0, &scene);
+ item->setPos(10.0, 10.0);
+
+ // The (0, 0, 50, 50) scene rect should not include the item's bounding rect
+ QVERIFY(!scene.items(QRectF(0.0, 0.0, 50.0, 50.0), Qt::ContainsItemBoundingRect).contains(item));
+
+ // The (9, 9, 500, 500) scene rect _should_ include the item's bounding rect
+ QVERIFY(scene.items(QRectF(9.0, 9.0, 500.0, 500.0), Qt::ContainsItemBoundingRect).contains(item));
+
+ // The (25, 25, 5, 5) scene rect should not include the item's bounding rect
+ QVERIFY(!scene.items(QRectF(25.0, 25.0, 5.0, 5.0), Qt::ContainsItemBoundingRect).contains(item));
+}
+
+void tst_QGraphicsScene::task176178_itemIndexMethodBreaksSceneRect()
+{
+ QGraphicsScene scene;
+ scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+ QGraphicsRectItem *rect = new QGraphicsRectItem;
+ rect->setRect(0,0,100,100);
+ scene.addItem(rect);
+ QCOMPARE(scene.sceneRect(), rect->rect());
+}
+
+void tst_QGraphicsScene::task160653_selectionChanged()
+{
+ QGraphicsScene scene(0, 0, 100, 100);
+ scene.addItem(new QGraphicsRectItem(0, 0, 20, 20));
+ scene.addItem(new QGraphicsRectItem(30, 30, 20, 20));
+ foreach (QGraphicsItem *item, scene.items()) {
+ item->setFlags(
+ item->flags() | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
+ item->setSelected(true);
+ }
+ Q_ASSERT(scene.items().size() > 1);
+ QCOMPARE(scene.items().size(), scene.selectedItems().size());
+
+ QSignalSpy spy(&scene, SIGNAL(selectionChanged()));
+ QGraphicsView view(&scene);
+ QTest::mouseClick(
+ view.viewport(), Qt::LeftButton, 0, view.mapFromScene(scene.items().first()->scenePos()));
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QGraphicsScene::task250680_childClip()
+{
+ QGraphicsRectItem *clipper = new QGraphicsRectItem;
+ clipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+ clipper->setPen(QPen(Qt::green));
+ clipper->setRect(200, 200, 640, 480);
+
+ QGraphicsRectItem *rect = new QGraphicsRectItem(clipper);
+ rect->setPen(QPen(Qt::red));
+ rect->setBrush(QBrush(QColor(255, 0, 0, 75)));
+ rect->setPos(320, 240);
+ rect->setRect(-25, -25, 50, 50);
+
+ QGraphicsScene scene;
+ scene.addItem(clipper);
+
+ QPainterPath path;
+ path.addRect(-25, -25, 50, 50);
+ QVERIFY(QPathCompare::comparePaths(rect->clipPath().simplified(), path));
+
+ QCOMPARE(scene.items(QRectF(320, 240, 5, 5)).size(), 2);
+ rect->rotate(45);
+ QCOMPARE(scene.items(QRectF(320, 240, 5, 5)).size(), 2);
+}
+
+void tst_QGraphicsScene::sorting_data()
+{
+ QTest::addColumn<bool>("cache");
+
+ QTest::newRow("Normal sorting") << false;
+ QTest::newRow("Cached sorting") << true;
+}
+
+void tst_QGraphicsScene::sorting()
+{
+ QFETCH(bool, cache);
+
+ QGraphicsScene scene;
+ scene.setSortCacheEnabled(cache);
+
+ QGraphicsRectItem *t_1 = new QGraphicsRectItem(0, 0, 50, 50);
+ QGraphicsRectItem *c_1 = new QGraphicsRectItem(0, 0, 40, 40, t_1);
+ QGraphicsRectItem *c_1_1 = new QGraphicsRectItem(0, 0, 30, 30, c_1);
+ QGraphicsRectItem *c_1_1_1 = new QGraphicsRectItem(0, 0, 20, 20, c_1_1);
+ QGraphicsRectItem *c_1_2 = new QGraphicsRectItem(0, 0, 30, 30, c_1);
+ QGraphicsRectItem *c_2 = new QGraphicsRectItem(0, 0, 40, 40, t_1);
+ QGraphicsRectItem *c_2_1 = new QGraphicsRectItem(0, 0, 30, 30, c_2);
+ QGraphicsRectItem *c_2_1_1 = new QGraphicsRectItem(0, 0, 20, 20, c_2_1);
+ QGraphicsRectItem *c_2_2 = new QGraphicsRectItem(0, 0, 30, 30, c_2);
+ t_1->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_1->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_1_1->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_1_1_1->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_1_2->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_2->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_2_1->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_2_1_1->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+ c_2_2->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
+
+ c_1->setPos(23, 18);
+ c_1_1->setPos(24, 28);
+ c_1_1_1->setPos(-16, 16);
+ c_1_2->setPos(-16, 28);
+ c_1_2->setZValue(1);
+ c_2->setPos(-23, 18);
+ c_2->setZValue(1);
+ c_2_1->setPos(24, 28);
+ c_2_1_1->setPos(-16, 16);
+ c_2_2->setPos(-16, 28);
+ c_2_2->setZValue(1);
+
+ c_1->setFlag(QGraphicsItem::ItemIsMovable);
+ c_1_1->setFlag(QGraphicsItem::ItemIsMovable);
+ c_1_1_1->setFlag(QGraphicsItem::ItemIsMovable);
+ c_1_2->setFlag(QGraphicsItem::ItemIsMovable);
+ c_2->setFlag(QGraphicsItem::ItemIsMovable);
+ c_2_1->setFlag(QGraphicsItem::ItemIsMovable);
+ c_2_1_1->setFlag(QGraphicsItem::ItemIsMovable);
+ c_2_2->setFlag(QGraphicsItem::ItemIsMovable);
+
+ t_1->setData(0, "t_1");
+ c_1->setData(0, "c_1");
+ c_1_1->setData(0, "c_1_1");
+ c_1_1_1->setData(0, "c_1_1_1");
+ c_1_2->setData(0, "c_1_2");
+ c_2->setData(0, "c_2");
+ c_2_1->setData(0, "c_2_1");
+ c_2_1_1->setData(0, "c_2_1_1");
+ c_2_2->setData(0, "c_2_2");
+
+ scene.addItem(t_1);
+
+ foreach (QGraphicsItem *item, scene.items())
+ item->setFlag(QGraphicsItem::ItemIsSelectable);
+
+ // QGraphicsView view(&scene);
+ // view.setDragMode(QGraphicsView::RubberBandDrag);
+ // view.show();
+
+ qDebug() << "items: {";
+ foreach (QGraphicsItem *item, scene.items(32, 31, 4, 55))
+ qDebug() << "\t" << item->data(0).toString();
+ qDebug() << "}";
+
+ QCOMPARE(scene.items(32, 31, 4, 55),
+ QList<QGraphicsItem *>()
+ << c_1_2 << c_1_1_1 << c_1 << t_1);
+ QCOMPARE(scene.items(-53, 47, 136, 3),
+ QList<QGraphicsItem *>()
+ << c_2_2 << c_2_1 << c_2 << c_1_2 << c_1_1 << c_1 << t_1);
+ QCOMPARE(scene.items(-23, 79, 104, 3),
+ QList<QGraphicsItem *>()
+ << c_2_1_1 << c_1_1_1);
+ QCOMPARE(scene.items(-26, -3, 92, 79),
+ QList<QGraphicsItem *>()
+ << c_2_2 << c_2_1_1 << c_2_1 << c_2
+ << c_1_2 << c_1_1_1 << c_1_1 << c_1
+ << t_1);
+}
+
+class ChangedListener : public QObject
+{
+ Q_OBJECT
+public:
+ QList<QList<QRectF> > changes;
+
+public slots:
+ void changed(const QList<QRectF> &dirty)
+ {
+ changes << dirty;
+ }
+};
+
+void tst_QGraphicsScene::changedSignal_data()
+{
+ QTest::addColumn<bool>("withView");
+
+ QTest::newRow("without view") << false;
+ QTest::newRow("with view") << true;
+}
+
+void tst_QGraphicsScene::changedSignal()
+{
+ QFETCH(bool, withView);
+ QGraphicsScene scene;
+ ChangedListener cl;
+ connect(&scene, SIGNAL(changed(const QList<QRectF> &)), &cl, SLOT(changed(const QList<QRectF> &)));
+
+ QGraphicsView *view = 0;
+ if (withView)
+ view = new QGraphicsView(&scene);
+
+ QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 10, 10);
+ scene.addItem(rect);
+
+ QCOMPARE(cl.changes.size(), 0);
+ QTRY_COMPARE(cl.changes.size(), 1);
+ QCOMPARE(cl.changes.at(0).size(), 1);
+ QCOMPARE(cl.changes.at(0).first(), QRectF(0, 0, 10, 10));
+
+ rect->setPos(20, 0);
+
+ QCOMPARE(cl.changes.size(), 1);
+ qApp->processEvents();
+ QCOMPARE(cl.changes.size(), 2);
+ QCOMPARE(cl.changes.at(1).size(), 2);
+ QCOMPARE(cl.changes.at(1).first(), QRectF(0, 0, 10, 10));
+ QCOMPARE(cl.changes.at(1).last(), QRectF(20, 0, 10, 10));
+
+ QCOMPARE(scene.sceneRect(), QRectF(0, 0, 30, 10));
+
+ if (withView)
+ delete view;
+}
+
+void tst_QGraphicsScene::stickyFocus_data()
+{
+ QTest::addColumn<bool>("sticky");
+ QTest::newRow("sticky") << true;
+ QTest::newRow("not sticky") << false;
+}
+
+void tst_QGraphicsScene::stickyFocus()
+{
+ QFETCH(bool, sticky);
+
+ QGraphicsScene scene;
+ QEvent activate(QEvent::WindowActivate);
+ QApplication::sendEvent(&scene, &activate);
+
+ QGraphicsTextItem *text = scene.addText("Hei");
+ text->setTextInteractionFlags(Qt::TextEditorInteraction);
+ text->setFocus();
+
+ scene.setStickyFocus(sticky);
+
+ QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
+ event.setScenePos(QPointF(-10, -10)); // outside item
+ event.setButton(Qt::LeftButton);
+ qApp->sendEvent(&scene, &event);
+
+ QCOMPARE(text->hasFocus(), sticky);
+}
+
+void tst_QGraphicsScene::sendEvent()
+{
+ QGraphicsScene scene;
+ QGraphicsTextItem *item = scene.addText(QString());
+ EventSpy *spy = new EventSpy(&scene, item, QEvent::User);
+ QCOMPARE(spy->count(), 0);
+ QEvent event(QEvent::User);
+ scene.sendEvent(item, &event);
+ QCOMPARE(spy->count(), 1);
+}
+
+void tst_QGraphicsScene::inputMethod_data()
+{
+ QTest::addColumn<int>("flags");
+ QTest::addColumn<bool>("callFocusItem");
+ QTest::newRow("0") << 0 << false;
+ QTest::newRow("1") << (int)QGraphicsItem::ItemAcceptsInputMethod << false;
+ QTest::newRow("2") << (int)QGraphicsItem::ItemIsFocusable << false;
+ QTest::newRow("3") <<
+ (int)(QGraphicsItem::ItemAcceptsInputMethod|QGraphicsItem::ItemIsFocusable) << true;
+}
+
+class InputMethodTester : public QGraphicsRectItem
+{
+ void inputMethodEvent(QInputMethodEvent *) { ++eventCalls; }
+ QVariant inputMethodQuery(Qt::InputMethodQuery) const { ++queryCalls; return QVariant(); }
+public:
+ int eventCalls;
+ mutable int queryCalls;
+};
+
+class TestInputContext : public QInputContext
+{
+public:
+ TestInputContext() {}
+
+ QString identifierName() { return QString(); }
+ QString language() { return QString(); }
+
+ void reset() {
+ ++resetCalls;
+ sendEvent(QInputMethodEvent()); }
+
+ bool isComposing() const { return false; }
+
+ int resetCalls;
+};
+
+void tst_QGraphicsScene::inputMethod()
+{
+ QFETCH(int, flags);
+ QFETCH(bool, callFocusItem);
+
+ InputMethodTester *item = new InputMethodTester;
+ item->setFlags((QGraphicsItem::GraphicsItemFlags)flags);
+
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ TestInputContext inputContext;
+ view.setInputContext(&inputContext);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ view.setFocus();
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+
+ inputContext.resetCalls = 0;
+ scene.addItem(item);
+ QInputMethodEvent event;
+
+ scene.setFocusItem(item);
+ QCOMPARE(!!(item->flags() & QGraphicsItem::ItemIsFocusable), scene.focusItem() == item);
+ QCOMPARE(inputContext.resetCalls, 0);
+
+ item->eventCalls = 0;
+ qApp->sendEvent(&scene, &event);
+ QCOMPARE(item->eventCalls, callFocusItem ? 1 : 0);
+
+ item->queryCalls = 0;
+ scene.inputMethodQuery((Qt::InputMethodQuery)0);
+ QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0);
+
+ scene.setFocusItem(0);
+ // the input context is reset twice, once because an item has lost focus and again because
+ // the Qt::WA_InputMethodEnabled flag is cleared because no item has focus.
+ QCOMPARE(inputContext.resetCalls, callFocusItem ? 2 : 0);
+ QCOMPARE(item->eventCalls, callFocusItem ? 2 : 0); // verify correct delivery of "reset" event
+ QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0); // verify that value is unaffected
+
+ item->eventCalls = 0;
+ qApp->sendEvent(&scene, &event);
+ QCOMPARE(item->eventCalls, 0);
+
+ item->queryCalls = 0;
+ scene.inputMethodQuery((Qt::InputMethodQuery)0);
+ QCOMPARE(item->queryCalls, 0);
+}
+
+void tst_QGraphicsScene::dispatchHoverOnPress()
+{
+ QGraphicsScene scene;
+ EventTester *tester1 = new EventTester;
+ tester1->setAcceptHoverEvents(true);
+ EventTester *tester2 = new EventTester;
+ tester2->setAcceptHoverEvents(true);
+ tester2->setPos(30, 30);
+ scene.addItem(tester1);
+ scene.addItem(tester2);
+
+ tester1->eventTypes.clear();
+ tester2->eventTypes.clear();
+
+ {
+ QGraphicsSceneMouseEvent me(QEvent::GraphicsSceneMousePress);
+ me.setButton(Qt::LeftButton);
+ me.setButtons(Qt::LeftButton);
+ QGraphicsSceneMouseEvent me2(QEvent::GraphicsSceneMouseRelease);
+ me2.setButton(Qt::LeftButton);
+ qApp->sendEvent(&scene, &me);
+ qApp->sendEvent(&scene, &me2);
+ QCOMPARE(tester1->eventTypes, QList<QEvent::Type>()
+ << QEvent::GraphicsSceneHoverEnter
+ << QEvent::GraphicsSceneHoverMove
+ << QEvent::GrabMouse
+ << QEvent::GraphicsSceneMousePress
+ << QEvent::UngrabMouse);
+ tester1->eventTypes.clear();
+ qApp->sendEvent(&scene, &me);
+ qApp->sendEvent(&scene, &me2);
+ QCOMPARE(tester1->eventTypes, QList<QEvent::Type>()
+ << QEvent::GraphicsSceneHoverMove
+ << QEvent::GrabMouse
+ << QEvent::GraphicsSceneMousePress
+ << QEvent::UngrabMouse);
+ }
+ {
+ QGraphicsSceneMouseEvent me(QEvent::GraphicsSceneMousePress);
+ me.setScenePos(QPointF(30, 30));
+ me.setButton(Qt::LeftButton);
+ me.setButtons(Qt::LeftButton);
+ QGraphicsSceneMouseEvent me2(QEvent::GraphicsSceneMouseRelease);
+ me2.setScenePos(QPointF(30, 30));
+ me2.setButton(Qt::LeftButton);
+ tester1->eventTypes.clear();
+ qApp->sendEvent(&scene, &me);
+ qApp->sendEvent(&scene, &me2);
+ qDebug() << tester1->eventTypes;
+ QCOMPARE(tester1->eventTypes, QList<QEvent::Type>()
+ << QEvent::GraphicsSceneHoverLeave);
+ QCOMPARE(tester2->eventTypes, QList<QEvent::Type>()
+ << QEvent::GraphicsSceneHoverEnter
+ << QEvent::GraphicsSceneHoverMove
+ << QEvent::GrabMouse
+ << QEvent::GraphicsSceneMousePress
+ << QEvent::UngrabMouse);
+ tester2->eventTypes.clear();
+ qApp->sendEvent(&scene, &me);
+ qApp->sendEvent(&scene, &me2);
+ QCOMPARE(tester2->eventTypes, QList<QEvent::Type>()
+ << QEvent::GraphicsSceneHoverMove
+ << QEvent::GrabMouse
+ << QEvent::GraphicsSceneMousePress
+ << QEvent::UngrabMouse);
+ }
+}
+
+void tst_QGraphicsScene::initialFocus_data()
+{
+ QTest::addColumn<bool>("activeScene");
+ QTest::addColumn<bool>("explicitSetFocus");
+ QTest::addColumn<bool>("isPanel");
+ QTest::addColumn<bool>("shouldHaveFocus");
+
+ QTest::newRow("inactive scene, normal item") << false << false << false << false;
+ QTest::newRow("inactive scene, panel item") << false << false << true << false;
+ QTest::newRow("inactive scene, normal item, explicit focus") << false << true << false << true;
+ QTest::newRow("inactive scene, panel, explicit focus") << false << true << true << true;
+ QTest::newRow("active scene, normal item") << true << false << false << false;
+ QTest::newRow("active scene, panel item") << true << false << true << false;
+ QTest::newRow("active scene, normal item, explicit focus") << true << true << false << true;
+ QTest::newRow("active scene, panel, explicit focus") << true << true << true << true;
+}
+
+void tst_QGraphicsScene::initialFocus()
+{
+ QFETCH(bool, activeScene);
+ QFETCH(bool, explicitSetFocus);
+ QFETCH(bool, isPanel);
+ QFETCH(bool, shouldHaveFocus);
+
+ QGraphicsRectItem *rect = new QGraphicsRectItem;
+ rect->setFlag(QGraphicsItem::ItemIsFocusable);
+ QVERIFY(!rect->hasFocus());
+
+ if (isPanel)
+ rect->setFlag(QGraphicsItem::ItemIsPanel);
+
+ // Setting focus on an item before adding to the scene will ensure
+ // it gets focus when the scene is activated.
+ if (explicitSetFocus)
+ rect->setFocus();
+
+ QGraphicsScene scene;
+ QVERIFY(!scene.isActive());
+
+ if (activeScene) {
+ QEvent windowActivate(QEvent::WindowActivate);
+ qApp->sendEvent(&scene, &windowActivate);
+ scene.setFocus();
+ }
+
+ scene.addItem(rect);
+
+ if (!activeScene) {
+ QEvent windowActivate(QEvent::WindowActivate);
+ qApp->sendEvent(&scene, &windowActivate);
+ scene.setFocus();
+ }
+
+ QCOMPARE(rect->hasFocus(), shouldHaveFocus);
+}
+
+class PolishItem : public QGraphicsTextItem
+{
+public:
+ PolishItem(QGraphicsItem *parent = 0)
+ : QGraphicsTextItem(parent), polished(false), deleteChildrenInPolish(true), addChildrenInPolish(false) { }
+
+ bool polished;
+ bool deleteChildrenInPolish;
+ bool addChildrenInPolish;
+protected:
+ QVariant itemChange(GraphicsItemChange change, const QVariant& value)
+ {
+ if (change == ItemVisibleChange) {
+ polished = true;
+ if (deleteChildrenInPolish)
+ qDeleteAll(childItems());
+ if (addChildrenInPolish) {
+ for (int i = 0; i < 10; ++i)
+ new PolishItem(this);
+ }
+ }
+ return QGraphicsItem::itemChange(change, value);
+ }
+};
+
+void tst_QGraphicsScene::polishItems()
+{
+ QGraphicsScene scene;
+ PolishItem *parent = new PolishItem;
+ scene.addItem(parent);
+ PolishItem *child = new PolishItem(parent);
+ Q_UNUSED(child)
+ // test that QGraphicsScenePrivate::_q_polishItems() doesn't crash
+ QMetaObject::invokeMethod(&scene,"_q_polishItems");
+}
+
+void tst_QGraphicsScene::polishItems2()
+{
+ QGraphicsScene scene;
+ PolishItem *item = new PolishItem;
+ item->addChildrenInPolish = true;
+ item->deleteChildrenInPolish = true;
+ // These children should be deleted in the polish.
+ for (int i = 0; i < 20; ++i)
+ new PolishItem(item);
+ scene.addItem(item);
+
+ // Wait for the polish event to be delivered.
+ QVERIFY(!item->polished);
+ QApplication::sendPostedEvents(&scene, QEvent::MetaCall);
+ QVERIFY(item->polished);
+
+ // We deleted the children we added above, but we also
+ // added 10 new children. These should be polished in the next
+ // event loop iteration.
+ QList<QGraphicsItem *> children = item->childItems();
+ QCOMPARE(children.count(), 10);
+ foreach (QGraphicsItem *child, children)
+ QVERIFY(!static_cast<PolishItem *>(child)->polished);
+
+ QApplication::sendPostedEvents(&scene, QEvent::MetaCall);
+ foreach (QGraphicsItem *child, children)
+ QVERIFY(static_cast<PolishItem *>(child)->polished);
+}
+
+void tst_QGraphicsScene::isActive()
+{
+ QGraphicsScene scene1;
+ QVERIFY(!scene1.isActive());
+ QGraphicsScene scene2;
+ QVERIFY(!scene2.isActive());
+
+ {
+ QWidget toplevel1;
+ QHBoxLayout *layout = new QHBoxLayout;
+ toplevel1.setLayout(layout);
+ QGraphicsView *view1 = new QGraphicsView(&scene1);
+ QGraphicsView *view2 = new QGraphicsView(&scene2);
+ layout->addWidget(view1);
+ layout->addWidget(view2);
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(!scene2.isActive());
+
+ view1->setVisible(false);
+
+ toplevel1.show();
+ QApplication::setActiveWindow(&toplevel1);
+ QTest::qWaitForWindowShown(&toplevel1);
+ QTRY_COMPARE(QApplication::activeWindow(), &toplevel1);
+
+ QVERIFY(!scene1.isActive()); //it is hidden;
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+
+ view1->show();
+ QVERIFY(scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+
+ view2->hide();
+
+ QVERIFY(scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ toplevel1.hide();
+ QTest::qWait(50);
+ QTRY_VERIFY(!scene1.isActive());
+ QTRY_VERIFY(!scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ toplevel1.show();
+ QApplication::setActiveWindow(&toplevel1);
+ QApplication::processEvents();
+ QTRY_COMPARE(QApplication::activeWindow(), &toplevel1);
+
+ QTRY_VERIFY(scene1.isActive());
+ QTRY_VERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ view2->show();
+ QVERIFY(scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+ }
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+
+ {
+ QWidget toplevel2;
+ QHBoxLayout *layout = new QHBoxLayout;
+ toplevel2.setLayout(layout);
+ QGraphicsView *view1 = new QGraphicsView(&scene1);
+ QGraphicsView *view2 = new QGraphicsView();
+ layout->addWidget(view1);
+ layout->addWidget(view2);
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ toplevel2.show();
+ QApplication::setActiveWindow(&toplevel2);
+ QTest::qWaitForWindowShown(&toplevel2);
+ QTRY_COMPARE(QApplication::activeWindow(), &toplevel2);
+
+ QVERIFY(scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ view2->setScene(&scene2);
+
+ QVERIFY(scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ view1->setScene(&scene2);
+ QVERIFY(!scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+
+ view1->hide();
+ QVERIFY(!scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+
+ view1->setScene(&scene1);
+ QVERIFY(!scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+
+ view1->show();
+ QVERIFY(scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+
+ view2->hide();
+ QVERIFY(scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ QGraphicsView topLevelView;
+ topLevelView.show();
+ QApplication::setActiveWindow(&topLevelView);
+ topLevelView.setFocus();
+ QTest::qWaitForWindowShown(&topLevelView);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&topLevelView));
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ topLevelView.setScene(&scene1);
+ QVERIFY(scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ view2->show();
+ QVERIFY(scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ view1->hide();
+ QVERIFY(scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ QApplication::setActiveWindow(&toplevel2);
+ QTRY_COMPARE(QApplication::activeWindow(), &toplevel2);
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+ }
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ {
+ QWidget toplevel3;
+ QHBoxLayout *layout = new QHBoxLayout;
+ toplevel3.setLayout(layout);
+ QGraphicsView *view1 = new QGraphicsView(&scene1);
+ QGraphicsView *view2 = new QGraphicsView(&scene2);
+ layout->addWidget(view1);
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+
+ toplevel3.show();
+ QApplication::setActiveWindow(&toplevel3);
+ QTest::qWaitForWindowShown(&toplevel3);
+ QTRY_COMPARE(QApplication::activeWindow(), &toplevel3);
+
+ QVERIFY(scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ layout->addWidget(view2);
+ QApplication::processEvents();
+ QVERIFY(scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+ view1->setParent(0);
+ QVERIFY(!scene1.isActive());
+ QVERIFY(scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(scene2.hasFocus());
+ delete view1;
+ }
+
+ QVERIFY(!scene1.isActive());
+ QVERIFY(!scene2.isActive());
+ QVERIFY(!scene1.hasFocus());
+ QVERIFY(!scene2.hasFocus());
+
+}
+
+void tst_QGraphicsScene::siblingIndexAlwaysValid()
+{
+ QGraphicsScene scene;
+
+ QGraphicsWidget *parent = new QGraphicsWidget;
+ parent->setZValue(350);
+ parent->setGeometry(0, 0, 100, 100);
+ QGraphicsWidget *parent2 = new QGraphicsWidget;
+ parent2->setGeometry(10, 10, 50, 50);
+ QGraphicsWidget *child = new QGraphicsWidget(parent2);
+ child->setGeometry(15, 15, 25, 25);
+ child->setZValue(150);
+ //Both are top level
+ scene.addItem(parent);
+ scene.addItem(parent2);
+
+ //Then we make the child a top level
+ child->setParentItem(0);
+
+ //This is trigerred by a repaint...
+ QGraphicsScenePrivate::get(&scene)->index->estimateTopLevelItems(QRectF(), Qt::AscendingOrder);
+
+ delete child;
+
+ //If there are in the list that's bad, we crash...
+ QVERIFY(!QGraphicsScenePrivate::get(&scene)->topLevelItems.contains(static_cast<QGraphicsItem *>(child)));
+
+ //Other case
+ QGraphicsScene scene2;
+ // works with bsp tree index
+ scene2.setItemIndexMethod(QGraphicsScene::NoIndex);
+
+ QGraphicsView view2(&scene2);
+
+ // first add the blue rect
+ QGraphicsRectItem* const item1 = new QGraphicsRectItem(QRect( 10, 10, 10, 10 ));
+ item1->setPen(QColor(Qt::blue));
+ item1->setBrush(Qt::blue);
+ scene2.addItem(item1);
+
+ // then add the red rect
+ QGraphicsRectItem* const item2 = new QGraphicsRectItem(5, 5, 10, 10);
+ item2->setPen(QColor(Qt::red));
+ item2->setBrush(Qt::red);
+ scene2.addItem(item2);
+
+ // now the blue one is visible on top of the red one -> swap them (important for the bug)
+ item1->setZValue(1.0);
+ item2->setZValue(0.0);
+
+ view2.show();
+
+ // handle events as a real life app would do
+ QApplication::processEvents();
+
+ // now delete the red rect
+ delete item2;
+
+ // handle events as a real life app would do
+ QApplication::processEvents();
+
+ //We should not crash
+
+}
+
+void tst_QGraphicsScene::removeFullyTransparentItem()
+{
+ QGraphicsScene scene;
+
+ QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
+ parent->setFlag(QGraphicsItem::ItemHasNoContents);
+
+ QGraphicsItem *child = scene.addRect(0, 0, 100, 100);
+ child->setParentItem(parent);
+
+ CustomView view;
+ view.setScene(&scene);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ // NB! The parent has the ItemHasNoContents flag set, which means
+ // the parent itself doesn't generate any update requests, only the
+ // child can possibly trigger an update. Also note that the child
+ // is removed before processing events.
+ view.repaints = 0;
+ parent->setOpacity(0);
+ QVERIFY(qFuzzyIsNull(child->effectiveOpacity()));
+ scene.removeItem(child);
+ QVERIFY(!scene.items().contains(child));
+ QTRY_VERIFY(view.repaints > 0);
+
+ // Re-add child. There's nothing new to display (child is still
+ // effectively hidden), so it shouldn't trigger an update.
+ view.repaints = 0;
+ child->setParentItem(parent);
+ QVERIFY(scene.items().contains(child));
+ QVERIFY(qFuzzyIsNull(child->effectiveOpacity()));
+ QApplication::processEvents();
+ QCOMPARE(view.repaints, 0);
+
+ // Nothing is visible on the screen, removing child item shouldn't trigger an update.
+ scene.removeItem(child);
+ QApplication::processEvents();
+ QCOMPARE(view.repaints, 0);
+ delete child;
+}
+
+void tst_QGraphicsScene::taskQTBUG_5904_crashWithDeviceCoordinateCache()
+{
+ QGraphicsScene scene;
+ QGraphicsRectItem *rectItem = scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));
+
+ rectItem->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+
+ QPixmap pixmap(100,200);
+ QPainter painter(&pixmap);
+ painter.setRenderHint(QPainter::Antialiasing);
+ scene.render(&painter);
+ painter.end();
+ // No crash, then it passed!
+}
+
+void tst_QGraphicsScene::taskQT657_paintIntoCacheWithTransparentParts()
+{
+ // Test using DeviceCoordinateCache and opaque item
+ QWidget *w = new QWidget();
+ w->setPalette(QColor(0, 0, 255));
+ w->setGeometry(0, 0, 50, 50);
+
+ QGraphicsScene *scene = new QGraphicsScene();
+ CustomView *view = new CustomView;
+ view->setScene(scene);
+
+ QGraphicsProxyWidget *proxy = scene->addWidget(w);
+ proxy->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+ proxy->rotate(15);
+
+ view->show();
+ QTest::qWaitForWindowShown(view);
+ view->repaints = 0;
+ proxy->update(10, 10, 10, 10);
+ QTest::qWait(50);
+ QTRY_VERIFY(view->repaints > 0);
+
+ QPixmap pix;
+ QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(proxy);
+ QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view->viewport()).key, &pix));
+
+ QTransform t = proxy->sceneTransform();
+ // Map from scene coordinates to pixmap coordinates.
+ // X origin in the pixmap is the most-left point
+ // of the item's boundingRect in the scene.
+ qreal adjust = t.mapRect(proxy->boundingRect().toRect()).left();
+ QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1);
+ QPixmap subpix = pix.copy(rect);
+
+ QImage im = subpix.toImage();
+ for(int i = 0; i < im.width(); i++) {
+ for(int j = 0; j < im.height(); j++)
+ QCOMPARE(qAlpha(im.pixel(i, j)), 255);
+ }
+
+ delete w;
+}
+
+void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts()
+{
+ // Test using DeviceCoordinateCache and semi-transparent item
+ {
+ QGraphicsRectItem *backItem = new QGraphicsRectItem(0, 0, 100, 100);
+ backItem->setBrush(QColor(255, 255, 0));
+ QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 50, 50);
+ rectItem->setBrush(QColor(0, 0, 255, 125));
+ rectItem->setParentItem(backItem);
+
+ QGraphicsScene *scene = new QGraphicsScene();
+ CustomView *view = new CustomView;
+ view->setScene(scene);
+
+ scene->addItem(backItem);
+ rectItem->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+ backItem->rotate(15);
+
+ view->show();
+ QTest::qWaitForWindowShown(view);
+ view->repaints = 0;
+ rectItem->update(10, 10, 10, 10);
+ QTest::qWait(50);
+ QTRY_VERIFY(view->repaints > 0);
+
+ QPixmap pix;
+ QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem);
+ QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view->viewport()).key, &pix));
+
+ QTransform t = rectItem->sceneTransform();
+ // Map from scene coordinates to pixmap coordinates.
+ // X origin in the pixmap is the most-left point
+ // of the item's boundingRect in the scene.
+ qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left();
+ QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1);
+ QPixmap subpix = pix.copy(rect);
+
+ QImage im = subpix.toImage();
+ for(int i = 0; i < im.width(); i++) {
+ for(int j = 0; j < im.height(); j++) {
+ QCOMPARE(qAlpha(im.pixel(i, j)), 125);
+ }
+ }
+
+ delete view;
+ }
+
+ // Test using ItemCoordinateCache and opaque item
+ {
+ QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 50, 50);
+ rectItem->setBrush(QColor(0, 0, 255));
+
+ QGraphicsScene *scene = new QGraphicsScene();
+ CustomView *view = new CustomView;
+ view->setScene(scene);
+
+ scene->addItem(rectItem);
+ rectItem->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ rectItem->rotate(15);
+
+ view->show();
+ QTest::qWaitForWindowShown(view);
+ view->repaints = 0;
+ rectItem->update(10, 10, 10, 10);
+ QTest::qWait(50);
+ QTRY_VERIFY(view->repaints > 0);
+
+ QPixmap pix;
+ QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem);
+ QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->key, &pix));
+
+ QTransform t = rectItem->sceneTransform();
+ // Map from scene coordinates to pixmap coordinates.
+ // X origin in the pixmap is the most-left point
+ // of the item's boundingRect in the scene.
+ qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left();
+ QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1);
+ QPixmap subpix = pix.copy(rect);
+
+ QImage im = subpix.toImage();
+ for(int i = 0; i < im.width(); i++) {
+ for(int j = 0; j < im.height(); j++)
+ QCOMPARE(qAlpha(im.pixel(i, j)), 255);
+ }
+
+ delete view;
+ }
+
+ // Test using ItemCoordinateCache and semi-transparent item
+ {
+ QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 50, 50);
+ rectItem->setBrush(QColor(0, 0, 255, 125));
+
+ QGraphicsScene *scene = new QGraphicsScene();
+ CustomView *view = new CustomView;
+ view->setScene(scene);
+
+ scene->addItem(rectItem);
+ rectItem->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ rectItem->rotate(15);
+
+ view->show();
+ QTest::qWaitForWindowShown(view);
+ view->repaints = 0;
+ rectItem->update(10, 10, 10, 10);
+ QTest::qWait(50);
+ QTRY_VERIFY(view->repaints > 0);
+
+ QPixmap pix;
+ QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem);
+ QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->key, &pix));
+
+ QTransform t = rectItem->sceneTransform();
+ // Map from scene coordinates to pixmap coordinates.
+ // X origin in the pixmap is the most-left point
+ // of the item's boundingRect in the scene.
+ qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left();
+ QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1);
+ QPixmap subpix = pix.copy(rect);
+
+ QImage im = subpix.toImage();
+ for(int i = 0; i < im.width(); i++) {
+ for(int j = 0; j < im.height(); j++)
+ QCOMPARE(qAlpha(im.pixel(i, j)), 125);
+ }
+
+ delete view;
+ }
+}
+
+void tst_QGraphicsScene::taskQT_3674_doNotCrash()
+{
+ QGraphicsScene scene;
+
+ QGraphicsView view(&scene);
+ view.resize(200, 200);
+
+ QPixmap pixmap(view.size());
+ QPainter painter(&pixmap);
+ view.render(&painter);
+ painter.end();
+
+ scene.addItem(new QGraphicsWidget);
+ scene.setBackgroundBrush(Qt::green);
+
+ QApplication::processEvents();
+ QApplication::processEvents();
+}
+
+void tst_QGraphicsScene::zeroScale()
+{
+ //should not crash
+ QGraphicsScene scene;
+ scene.setSceneRect(-100, -100, 100, 100);
+ QGraphicsView view(&scene);
+
+ ChangedListener cl;
+ connect(&scene, SIGNAL(changed(const QList<QRectF> &)), &cl, SLOT(changed(const QList<QRectF> &)));
+
+ QGraphicsRectItem *rect1 = new QGraphicsRectItem(0, 0, 0.0000001, 0.00000001);
+ scene.addItem(rect1);
+ rect1->setRotation(82);
+ rect1->setScale(0.00000001);
+
+ QApplication::processEvents();
+ QTRY_COMPARE(cl.changes.count(), 1);
+ QGraphicsRectItem *rect2 = new QGraphicsRectItem(-0.0000001, -0.0000001, 0.0000001, 0.0000001);
+ rect2->setScale(0.00000001);
+ scene.addItem(rect2);
+ rect1->setPos(20,20);
+ QApplication::processEvents();
+ QTRY_COMPARE(cl.changes.count(), 2);
+}
+
+void tst_QGraphicsScene::taskQTBUG_15977_renderWithDeviceCoordinateCache()
+{
+ QGraphicsScene scene;
+ scene.setSceneRect(0, 0, 100, 100);
+ QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
+ rect->setPen(Qt::NoPen);
+ rect->setBrush(Qt::red);
+ rect->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+
+ QImage image(100, 100, QImage::Format_RGB32);
+ QPainter p(&image);
+ scene.render(&p);
+ p.end();
+
+ QImage expected(100, 100, QImage::Format_RGB32);
+ p.begin(&expected);
+ p.fillRect(expected.rect(), Qt::red);
+ p.end();
+
+ QCOMPARE(image, expected);
+}
+
+void tst_QGraphicsScene::taskQTBUG_16401_focusItem()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
+ rect->setFlag(QGraphicsItem::ItemIsFocusable);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QApplication::setActiveWindow(&view);
+
+ QVERIFY(!scene.focusItem());
+
+ rect->setFocus();
+ QCOMPARE(scene.focusItem(), rect);
+ QFocusEvent focusOut(QEvent::FocusOut);
+ QApplication::sendEvent(&view, &focusOut);
+ QVERIFY(!scene.focusItem());
+ QFocusEvent focusIn(QEvent::FocusIn);
+ QApplication::sendEvent(&view, &focusIn);
+ QCOMPARE(scene.focusItem(), rect);
+
+ rect->clearFocus();
+ QVERIFY(!scene.focusItem());
+ QApplication::sendEvent(&view, &focusOut);
+ QVERIFY(!scene.focusItem());
+ QApplication::sendEvent(&view, &focusIn);
+ QVERIFY(!scene.focusItem());
+}
+
+QTEST_MAIN(tst_QGraphicsScene)
+#include "tst_qgraphicsscene.moc"