634f6826c9625c47e0cabd349e5247f82519cda1
[profile/ivi/qtbase.git] / tests / auto / widgets / graphicsview / qgraphicsitem / tst_qgraphicsitem.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44
45 #include <private/qgraphicsitem_p.h>
46 #include <private/qgraphicsview_p.h>
47 #include <private/qgraphicsscene_p.h>
48 #include <QStyleOptionGraphicsItem>
49 #include <QAbstractTextDocumentLayout>
50 #include <QBitmap>
51 #include <QCursor>
52 #include <QLabel>
53 #include <QDial>
54 #include <QGraphicsItem>
55 #include <QGraphicsScene>
56 #include <QGraphicsSceneEvent>
57 #include <QGraphicsView>
58 #include <QGraphicsWidget>
59 #include <QGraphicsProxyWidget>
60 #include <QPainter>
61 #include <QScrollBar>
62 #include <QVBoxLayout>
63 #include <QGraphicsEffect>
64 #include <QInputContext>
65 #include <QPushButton>
66 #include <QLineEdit>
67 #include <QGraphicsLinearLayout>
68 #include <float.h>
69
70 //TESTED_CLASS=
71 //TESTED_FILES=
72
73 Q_DECLARE_METATYPE(QList<int>)
74 Q_DECLARE_METATYPE(QList<QRectF>)
75 Q_DECLARE_METATYPE(QPainterPath)
76 Q_DECLARE_METATYPE(QPointF)
77 Q_DECLARE_METATYPE(QRectF)
78
79 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
80 #include <windows.h>
81 #define Q_CHECK_PAINTEVENTS \
82     if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \
83         QSKIP("The Graphics View doesn't get the paint events");
84 #else
85 #define Q_CHECK_PAINTEVENTS
86 #endif
87
88 #if defined(Q_WS_MAC)
89 // On mac (cocoa) we always get full update.
90 // So check that the expected region is contained inside the actual
91 #define COMPARE_REGIONS(ACTUAL, EXPECTED) QVERIFY((EXPECTED).subtracted(ACTUAL).isEmpty())
92 #else
93 #define COMPARE_REGIONS QTRY_COMPARE
94 #endif
95
96 #include "../../../platformquirks.h"
97
98 static QGraphicsRectItem staticItem; //QTBUG-7629, we should not crash at exit.
99
100 static void sendMousePress(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
101 {
102     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
103     event.setScenePos(point);
104     event.setButton(button);
105     event.setButtons(button);
106     QApplication::sendEvent(scene, &event);
107 }
108
109 static void sendMouseMove(QGraphicsScene *scene, const QPointF &point,
110                           Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons /* buttons */ = 0)
111 {
112     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
113     event.setScenePos(point);
114     event.setButton(button);
115     event.setButtons(button);
116     QApplication::sendEvent(scene, &event);
117 }
118
119 static void sendMouseRelease(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
120 {
121     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
122     event.setScenePos(point);
123     event.setButton(button);
124     QApplication::sendEvent(scene, &event);
125 }
126
127 static void sendMouseClick(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
128 {
129     sendMousePress(scene, point, button);
130     sendMouseRelease(scene, point, button);
131 }
132
133 static void sendKeyPress(QGraphicsScene *scene, Qt::Key key)
134 {
135     QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier);
136     QApplication::sendEvent(scene, &keyEvent);
137 }
138
139 static void sendKeyRelease(QGraphicsScene *scene, Qt::Key key)
140 {
141     QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier);
142     QApplication::sendEvent(scene, &keyEvent);
143 }
144
145 static void sendKeyClick(QGraphicsScene *scene, Qt::Key key)
146 {
147     sendKeyPress(scene, key);
148     sendKeyRelease(scene, key);
149 }
150
151 class EventSpy : public QGraphicsWidget
152 {
153     Q_OBJECT
154 public:
155     EventSpy(QObject *watched, QEvent::Type type)
156         : _count(0), spied(type)
157     {
158         watched->installEventFilter(this);
159     }
160
161     EventSpy(QGraphicsScene *scene, QGraphicsItem *watched, QEvent::Type type)
162         : _count(0), spied(type)
163     {
164         scene->addItem(this);
165         watched->installSceneEventFilter(this);
166     }
167
168     int count() const { return _count; }
169
170 protected:
171     bool eventFilter(QObject *watched, QEvent *event)
172     {
173         Q_UNUSED(watched);
174         if (event->type() == spied)
175             ++_count;
176         return false;
177     }
178
179     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
180     {
181         Q_UNUSED(watched);
182         if (event->type() == spied)
183             ++_count;
184         return false;
185     }
186
187     int _count;
188     QEvent::Type spied;
189 };
190
191 class EventSpy2 : public QGraphicsWidget
192 {
193     Q_OBJECT
194 public:
195     EventSpy2(QObject *watched)
196     {
197         watched->installEventFilter(this);
198     }
199
200     EventSpy2(QGraphicsScene *scene, QGraphicsItem *watched)
201     {
202         scene->addItem(this);
203         watched->installSceneEventFilter(this);
204     }
205
206     QMap<QEvent::Type, int> counts;
207
208 protected:
209     bool eventFilter(QObject *watched, QEvent *event)
210     {
211         Q_UNUSED(watched);
212         ++counts[event->type()];
213         return false;
214     }
215
216     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
217     {
218         Q_UNUSED(watched);
219         ++counts[event->type()];
220         return false;
221     }
222 };
223
224 class EventTester : public QGraphicsItem
225 {
226 public:
227     EventTester(QGraphicsItem *parent = 0) : QGraphicsItem(parent), repaints(0)
228     { br = QRectF(-10, -10, 20, 20); }
229
230     void setGeometry(const QRectF &rect)
231     {
232         prepareGeometryChange();
233         br = rect;
234         update();
235     }
236
237     QRectF boundingRect() const
238     { return br; }
239
240     void paint(QPainter *painter, const QStyleOptionGraphicsItem *o, QWidget *)
241     {
242         hints = painter->renderHints();
243         painter->setBrush(brush);
244         painter->drawRect(boundingRect());
245         lastExposedRect = o->exposedRect;
246         ++repaints;
247     }
248
249     bool sceneEvent(QEvent *event)
250     {
251         events << event->type();
252         return QGraphicsItem::sceneEvent(event);
253     }
254
255     void reset()
256     {
257         events.clear();
258         hints = QPainter::RenderHints(0);
259         repaints = 0;
260         lastExposedRect = QRectF();
261     }
262
263     QList<QEvent::Type> events;
264     QPainter::RenderHints hints;
265     int repaints;
266     QRectF br;
267     QRectF lastExposedRect;
268     QBrush brush;
269 };
270
271 class MyGraphicsView : public QGraphicsView
272 {
273 public:
274     int repaints;
275     QRegion paintedRegion;
276     MyGraphicsView(QGraphicsScene *scene, QWidget *parent=0) : QGraphicsView(scene,parent), repaints(0) {}
277     void paintEvent(QPaintEvent *e)
278     {
279         paintedRegion += e->region();
280         ++repaints;
281         QGraphicsView::paintEvent(e);
282     }
283     void reset() { repaints = 0; paintedRegion = QRegion(); }
284 };
285
286 class tst_QGraphicsItem : public QObject
287 {
288     Q_OBJECT
289
290 public slots:
291     void init();
292
293 private slots:
294     void construction();
295     void constructionWithParent();
296     void destruction();
297     void deleteChildItem();
298     void scene();
299     void parentItem();
300     void setParentItem();
301     void children();
302     void flags();
303     void inputMethodHints();
304     void toolTip();
305     void visible();
306     void isVisibleTo();
307     void explicitlyVisible();
308     void enabled();
309     void explicitlyEnabled();
310     void selected();
311     void selected2();
312     void selected_group();
313     void selected_textItem();
314     void selected_multi();
315     void acceptedMouseButtons();
316     void acceptsHoverEvents();
317     void childAcceptsHoverEvents();
318     void hasFocus();
319     void pos();
320     void scenePos();
321     void matrix();
322     void sceneMatrix();
323     void setMatrix();
324     void zValue();
325     void shape();
326     void contains();
327     void collidesWith_item();
328     void collidesWith_path_data();
329     void collidesWith_path();
330     void collidesWithItemWithClip();
331     void isObscuredBy();
332     void isObscured();
333     void mapFromToParent();
334     void mapFromToScene();
335     void mapFromToItem();
336     void mapRectFromToParent_data();
337     void mapRectFromToParent();
338     void isAncestorOf();
339     void commonAncestorItem();
340     void data();
341     void type();
342     void graphicsitem_cast();
343     void hoverEventsGenerateRepaints();
344     void boundingRects_data();
345     void boundingRects();
346     void boundingRects2();
347     void sceneBoundingRect();
348     void childrenBoundingRect();
349     void childrenBoundingRectTransformed();
350     void childrenBoundingRect2();
351     void childrenBoundingRect3();
352     void childrenBoundingRect4();
353     void childrenBoundingRect5();
354     void group();
355     void setGroup();
356     void setGroup2();
357     void nestedGroups();
358     void warpChildrenIntoGroup();
359     void removeFromGroup();
360     void handlesChildEvents();
361     void handlesChildEvents2();
362     void handlesChildEvents3();
363     void filtersChildEvents();
364     void filtersChildEvents2();
365     void ensureVisible();
366     void cursor();
367     //void textControlGetterSetter();
368     void defaultItemTest_QGraphicsLineItem();
369     void defaultItemTest_QGraphicsPixmapItem();
370     void defaultItemTest_QGraphicsTextItem();
371     void defaultItemTest_QGraphicsEllipseItem();
372     void itemChange();
373     void sceneEventFilter();
374     void prepareGeometryChange();
375     void paint();
376     void deleteItemInEventHandlers();
377     void itemClipsToShape();
378     void itemClipsChildrenToShape();
379     void itemClipsChildrenToShape2();
380     void itemClipsChildrenToShape3();
381     void itemClipsChildrenToShape4();
382     void itemClipsChildrenToShape5();
383     void itemClipsTextChildToShape();
384     void itemClippingDiscovery();
385     void ancestorFlags();
386     void untransformable();
387     void contextMenuEventPropagation();
388     void itemIsMovable();
389     void boundingRegion_data();
390     void boundingRegion();
391     void itemTransform_parentChild();
392     void itemTransform_siblings();
393     void itemTransform_unrelated();
394     void opacity_data();
395     void opacity();
396     void opacity2();
397     void opacityZeroUpdates();
398     void itemStacksBehindParent();
399     void nestedClipping();
400     void nestedClippingTransforms();
401     void sceneTransformCache();
402     void tabChangesFocus();
403     void tabChangesFocus_data();
404     void cacheMode();
405     void cacheMode2();
406     void updateCachedItemAfterMove();
407     void deviceTransform_data();
408     void deviceTransform();
409     void update();
410     void setTransformProperties_data();
411     void setTransformProperties();
412     void itemUsesExtendedStyleOption();
413     void itemSendsGeometryChanges();
414     void moveItem();
415     void moveLineItem();
416     void sorting_data();
417     void sorting();
418     void itemHasNoContents();
419     void hitTestUntransformableItem();
420     void hitTestGraphicsEffectItem();
421     void focusProxy();
422     void subFocus();
423     void focusProxyDeletion();
424     void negativeZStacksBehindParent();
425     void setGraphicsEffect();
426     void panel();
427     void addPanelToActiveScene();
428     void panelWithFocusItem();
429     void activate();
430     void setActivePanelOnInactiveScene();
431     void activationOnShowHide();
432     void moveWhileDeleting();
433     void ensureDirtySceneTransform();
434     void focusScope();
435     void focusScope2();
436     void stackBefore();
437     void sceneModality();
438     void panelModality();
439     void mixedModality();
440     void modality_hover();
441     void modality_mouseGrabber();
442     void modality_clickFocus();
443     void modality_keyEvents();
444     void itemIsInFront();
445     void scenePosChange();
446     void updateMicroFocus();
447     void textItem_shortcuts();
448     void scroll();
449     void focusHandling_data();
450     void focusHandling();
451     void touchEventPropagation_data();
452     void touchEventPropagation();
453     void deviceCoordinateCache_simpleRotations();
454
455     // task specific tests below me
456     void task141694_textItemEnsureVisible();
457     void task128696_textItemEnsureMovable();
458     void ensureUpdateOnTextItem();
459     void task177918_lineItemUndetected();
460     void task240400_clickOnTextItem_data();
461     void task240400_clickOnTextItem();
462     void task243707_addChildBeforeParent();
463     void task197802_childrenVisibility();
464     void QTBUG_4233_updateCachedWithSceneRect();
465     void QTBUG_5418_textItemSetDefaultColor();
466     void QTBUG_6738_missingUpdateWithSetParent();
467     void QTBUG_7714_fullUpdateDiscardingOpacityUpdate2();
468     void QT_2653_fullUpdateDiscardingOpacityUpdate();
469     void QT_2649_focusScope();
470     void sortItemsWhileAdding();
471     void doNotMarkFullUpdateIfNotInScene();
472     void itemDiesDuringDraggingOperation();
473     void QTBUG_12112_focusItem();
474     void QTBUG_13473_sceneposchange();
475     void QTBUG_16374_crashInDestructor();
476     void QTBUG_20699_focusScopeCrash();
477
478 private:
479     QList<QGraphicsItem *> paintedItems;
480 };
481
482 void tst_QGraphicsItem::init()
483 {
484 #ifdef Q_OS_WINCE //disable magic for WindowsCE
485     qApp->setAutoMaximizeThreshold(-1);
486 #endif
487 }
488
489 void tst_QGraphicsItem::construction()
490 {
491     for (int i = 0; i < 7; ++i) {
492         QGraphicsItem *item;
493         switch (i) {
494         case 0:
495             item = new QGraphicsEllipseItem;
496             QCOMPARE(int(item->type()), int(QGraphicsEllipseItem::Type));
497             QCOMPARE(qgraphicsitem_cast<QGraphicsEllipseItem *>(item), (QGraphicsEllipseItem *)item);
498             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
499             QCOMPARE(item->flags(), 0);
500             break;
501         case 1:
502             item = new QGraphicsLineItem;
503             QCOMPARE(int(item->type()), int(QGraphicsLineItem::Type));
504             QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)item);
505             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
506             QCOMPARE(item->flags(), 0);
507             break;
508         case 2:
509             item = new QGraphicsPathItem;
510             QCOMPARE(int(item->type()), int(QGraphicsPathItem::Type));
511             QCOMPARE(qgraphicsitem_cast<QGraphicsPathItem *>(item), (QGraphicsPathItem *)item);
512             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
513             QCOMPARE(item->flags(), 0);
514             break;
515         case 3:
516             item = new QGraphicsPixmapItem;
517             QCOMPARE(int(item->type()), int(QGraphicsPixmapItem::Type));
518             QCOMPARE(qgraphicsitem_cast<QGraphicsPixmapItem *>(item), (QGraphicsPixmapItem *)item);
519             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
520             QCOMPARE(item->flags(), 0);
521             break;
522         case 4:
523             item = new QGraphicsPolygonItem;
524             QCOMPARE(int(item->type()), int(QGraphicsPolygonItem::Type));
525             QCOMPARE(qgraphicsitem_cast<QGraphicsPolygonItem *>(item), (QGraphicsPolygonItem *)item);
526             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
527             QCOMPARE(item->flags(), 0);
528             break;
529         case 5:
530             item = new QGraphicsRectItem;
531             QCOMPARE(int(item->type()), int(QGraphicsRectItem::Type));
532             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)item);
533             QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)0);
534             QCOMPARE(item->flags(), 0);
535             break;
536         case 6:
537             item = new QGraphicsTextItem;
538             QCOMPARE(int(item->type()), int(QGraphicsTextItem::Type));
539             QCOMPARE(qgraphicsitem_cast<QGraphicsTextItem *>(item), (QGraphicsTextItem *)item);
540             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
541             // This is the only item that uses an extended style option.
542             QCOMPARE(item->flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
543             break;
544         default:
545             qFatal("You broke the logic, please fix!");
546             break;
547         }
548
549         QCOMPARE(item->scene(), (QGraphicsScene *)0);
550         QCOMPARE(item->parentItem(), (QGraphicsItem *)0);
551         QVERIFY(item->children().isEmpty());
552         QVERIFY(item->isVisible());
553         QVERIFY(item->isEnabled());
554         QVERIFY(!item->isSelected());
555         QCOMPARE(item->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
556         if (item->type() == QGraphicsTextItem::Type)
557             QVERIFY(item->acceptsHoverEvents());
558         else
559             QVERIFY(!item->acceptsHoverEvents());
560         QVERIFY(!item->hasFocus());
561         QCOMPARE(item->pos(), QPointF());
562         QCOMPARE(item->matrix(), QMatrix());
563         QCOMPARE(item->sceneMatrix(), QMatrix());
564         QCOMPARE(item->zValue(), qreal(0));
565         QCOMPARE(item->sceneBoundingRect(), QRectF());
566         QCOMPARE(item->shape(), QPainterPath());
567         QVERIFY(!item->contains(QPointF(0, 0)));
568         QVERIFY(!item->collidesWithItem(0));
569         QVERIFY(item->collidesWithItem(item));
570         QVERIFY(!item->collidesWithPath(QPainterPath()));
571         QVERIFY(!item->isAncestorOf(0));
572         QVERIFY(!item->isAncestorOf(item));
573         QCOMPARE(item->data(0), QVariant());
574         delete item;
575     }
576 }
577
578 class BoundingRectItem : public QGraphicsRectItem
579 {
580 public:
581     BoundingRectItem(QGraphicsItem *parent = 0)
582         : QGraphicsRectItem(0, 0, parent ? 200 : 100, parent ? 200 : 100,
583                             parent)
584     {}
585
586     QRectF boundingRect() const
587     {
588         QRectF tmp = QGraphicsRectItem::boundingRect();
589         foreach (QGraphicsItem *child, children())
590             tmp |= child->boundingRect(); // <- might be pure virtual
591         return tmp;
592     }
593 };
594
595 void tst_QGraphicsItem::constructionWithParent()
596 {
597     // This test causes a crash if item1 calls item2's pure virtuals before the
598     // object has been constructed.
599     QGraphicsItem *item0 = new BoundingRectItem;
600     QGraphicsItem *item1 = new BoundingRectItem;
601     QGraphicsScene scene;
602     scene.addItem(item0);
603     scene.addItem(item1);
604     QGraphicsItem *item2 = new BoundingRectItem(item1);
605     QCOMPARE(item1->children(), QList<QGraphicsItem *>() << item2);
606     QCOMPARE(item1->boundingRect(), QRectF(0, 0, 200, 200));
607
608     item2->setParentItem(item0);
609     QCOMPARE(item0->children(), QList<QGraphicsItem *>() << item2);
610     QCOMPARE(item0->boundingRect(), QRectF(0, 0, 200, 200));
611 }
612
613 static int itemDeleted = 0;
614 class Item : public QGraphicsRectItem
615 {
616 public:
617     ~Item()
618     { ++itemDeleted; }
619 };
620
621 void tst_QGraphicsItem::destruction()
622 {
623     QCOMPARE(itemDeleted, 0);
624     {
625         QGraphicsItem *parent = new QGraphicsRectItem;
626         Item *child = new Item;
627         child->setParentItem(parent);
628         QCOMPARE(child->parentItem(), parent);
629         delete parent;
630         QCOMPARE(itemDeleted, 1);
631     }
632     {
633         QGraphicsItem *parent = new QGraphicsRectItem;
634         Item *child = new Item;
635         child->setParentItem(parent);
636         QCOMPARE(parent->children().size(), 1);
637         delete child;
638         QCOMPARE(parent->children().size(), 0);
639         delete parent;
640         QCOMPARE(itemDeleted, 2);
641     }
642     {
643         QGraphicsScene scene;
644         QGraphicsItem *parent = new QGraphicsRectItem;
645         Item *child = new Item;
646         QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
647         child->setParentItem(parent);
648         QCOMPARE(child->parentItem(), parent);
649         scene.addItem(parent);
650         QCOMPARE(child->parentItem(), parent);
651         delete parent;
652         QCOMPARE(itemDeleted, 3);
653     }
654     {
655         QGraphicsScene scene;
656         QGraphicsItem *parent = new QGraphicsRectItem;
657         Item *child = new Item;
658         child->setParentItem(parent);
659         scene.addItem(parent);
660         QCOMPARE(child->scene(), &scene);
661         QCOMPARE(parent->children().size(), 1);
662         delete child;
663         QCOMPARE(parent->children().size(), 0);
664         delete parent;
665         QCOMPARE(itemDeleted, 4);
666     }
667     {
668         QGraphicsScene scene;
669         QGraphicsItem *parent = new QGraphicsRectItem;
670         Item *child = new Item;
671         child->setParentItem(parent);
672         scene.addItem(parent);
673         QCOMPARE(child->scene(), &scene);
674         scene.removeItem(parent);
675         QCOMPARE(child->scene(), (QGraphicsScene *)0);
676         delete parent;
677         QCOMPARE(itemDeleted, 5);
678     }
679     {
680         QGraphicsScene scene;
681         QGraphicsItem *parent = new QGraphicsRectItem;
682         Item *child = new Item;
683         child->setParentItem(parent);
684         QCOMPARE(child->scene(), (QGraphicsScene *)0);
685         QCOMPARE(parent->scene(), (QGraphicsScene *)0);
686         scene.addItem(parent);
687         QCOMPARE(child->scene(), &scene);
688         scene.removeItem(child);
689         QCOMPARE(child->scene(), (QGraphicsScene *)0);
690         QCOMPARE(parent->scene(), &scene);
691         QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
692         QVERIFY(parent->children().isEmpty());
693         delete parent;
694         QCOMPARE(itemDeleted, 5);
695         delete child;
696         QCOMPARE(itemDeleted, 6);
697     }
698     {
699         QGraphicsScene scene;
700         QGraphicsItem *parent = new QGraphicsRectItem;
701         Item *child = new Item;
702         child->setParentItem(parent);
703         scene.addItem(parent);
704         scene.removeItem(child);
705         scene.removeItem(parent);
706         delete child;
707         delete parent;
708         QCOMPARE(itemDeleted, 7);
709     }
710     {
711         QGraphicsScene scene;
712         QGraphicsItem *parent = new QGraphicsRectItem;
713         Item *child = new Item;
714         child->setParentItem(parent);
715         scene.addItem(parent);
716         QGraphicsScene scene2;
717         scene2.addItem(parent);
718         delete parent;
719         QCOMPARE(itemDeleted, 8);
720     }
721     {
722         QGraphicsScene scene;
723         QGraphicsItem *parent = new QGraphicsRectItem;
724         Item *child = new Item;
725         child->setParentItem(parent);
726         scene.addItem(parent);
727         QCOMPARE(child->scene(), &scene);
728         QGraphicsScene scene2;
729         scene2.addItem(parent);
730         QCOMPARE(child->scene(), &scene2);
731         scene.addItem(parent);
732         QCOMPARE(child->scene(), &scene);
733         scene2.addItem(parent);
734         QCOMPARE(child->scene(), &scene2);
735         delete parent;
736         QCOMPARE(itemDeleted, 9);
737     }
738     {
739         QGraphicsScene scene;
740         QGraphicsItem *parent = new QGraphicsRectItem;
741         Item *child = new Item;
742         child->setParentItem(parent);
743         scene.addItem(parent);
744         QCOMPARE(child->scene(), &scene);
745         QGraphicsScene scene2;
746         scene2.addItem(child);
747         QCOMPARE(child->scene(), &scene2);
748         delete parent;
749         QCOMPARE(itemDeleted, 9);
750         delete child;
751         QCOMPARE(itemDeleted, 10);
752     }
753     {
754         QGraphicsScene scene;
755         QGraphicsItem *root = new QGraphicsRectItem;
756         QGraphicsItem *parent = root;
757         QGraphicsItem *middleItem = 0;
758         for (int i = 0; i < 99; ++i) {
759             Item *child = new Item;
760             child->setParentItem(parent);
761             parent = child;
762             if (i == 50)
763                 middleItem = parent;
764         }
765         scene.addItem(root);
766
767         QCOMPARE(scene.items().size(), 100);
768
769         QGraphicsScene scene2;
770         scene2.addItem(middleItem);
771
772         delete middleItem;
773         QCOMPARE(itemDeleted, 59);
774     }
775     QCOMPARE(itemDeleted, 109);
776     {
777         QGraphicsScene *scene = new QGraphicsScene;
778         QGraphicsRectItem *parent = new QGraphicsRectItem;
779         Item *child = new Item;
780         child->setParentItem(parent);
781         parent->setVisible(false);
782         scene->addItem(parent);
783         QCOMPARE(child->parentItem(), static_cast<QGraphicsItem*>(parent));
784         delete scene;
785         QCOMPARE(itemDeleted, 110);
786     }
787 }
788
789 void tst_QGraphicsItem::deleteChildItem()
790 {
791     QGraphicsScene scene;
792     QGraphicsItem *rect = scene.addRect(QRectF());
793     QGraphicsItem *child1 = new QGraphicsRectItem(rect);
794     QGraphicsItem *child2 = new QGraphicsRectItem(rect);
795     QGraphicsItem *child3 = new QGraphicsRectItem(rect);
796     Q_UNUSED(child3);
797     delete child1;
798     child2->setParentItem(0);
799     delete child2;
800 }
801
802 void tst_QGraphicsItem::scene()
803 {
804     QGraphicsRectItem *item = new QGraphicsRectItem;
805     QCOMPARE(item->scene(), (QGraphicsScene *)0);
806
807     QGraphicsScene scene;
808     scene.addItem(item);
809     QCOMPARE(item->scene(), (QGraphicsScene *)&scene);
810
811     QGraphicsScene scene2;
812     scene2.addItem(item);
813     QCOMPARE(item->scene(), (QGraphicsScene *)&scene2);
814
815     scene2.removeItem(item);
816     QCOMPARE(item->scene(), (QGraphicsScene *)0);
817
818     delete item;
819 }
820
821 void tst_QGraphicsItem::parentItem()
822 {
823     QGraphicsRectItem item;
824     QCOMPARE(item.parentItem(), (QGraphicsItem *)0);
825
826     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
827     QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
828     item2->setParentItem(&item);
829     QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
830     item2->setParentItem(0);
831     QCOMPARE(item2->parentItem(), (QGraphicsItem *)0);
832
833     delete item2;
834 }
835
836 void tst_QGraphicsItem::setParentItem()
837 {
838     QGraphicsScene scene;
839     QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10));
840     QCOMPARE(item->scene(), &scene);
841
842     QGraphicsRectItem *child = new QGraphicsRectItem;
843     QCOMPARE(child->scene(), (QGraphicsScene *)0);
844
845     // This implicitly adds the item to the parent's scene
846     child->setParentItem(item);
847     QCOMPARE(child->scene(), &scene);
848
849     // This just makes it a toplevel
850     child->setParentItem(0);
851     QCOMPARE(child->scene(), &scene);
852
853     // Add the child back to the parent, then remove the parent from the scene
854     child->setParentItem(item);
855     scene.removeItem(item);
856     QCOMPARE(child->scene(), (QGraphicsScene *)0);
857 }
858
859 void tst_QGraphicsItem::children()
860 {
861     QGraphicsRectItem item;
862     QVERIFY(item.children().isEmpty());
863
864     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
865     QCOMPARE(item.children().size(), 1);
866     QCOMPARE(item.children().first(), (QGraphicsItem *)item2);
867     QVERIFY(item2->children().isEmpty());
868
869     delete item2;
870     QVERIFY(item.children().isEmpty());
871 }
872
873 void tst_QGraphicsItem::flags()
874 {
875     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
876     QCOMPARE(item->flags(), 0);
877
878     QGraphicsScene scene;
879     QEvent activate(QEvent::WindowActivate);
880     QApplication::sendEvent(&scene, &activate);
881
882     scene.addItem(item);
883
884     {
885         // Focus
886         item->setFlag(QGraphicsItem::ItemIsFocusable, false);
887         QVERIFY(!item->hasFocus());
888         item->setFocus();
889         QVERIFY(!item->hasFocus());
890
891         item->setFlag(QGraphicsItem::ItemIsFocusable, true);
892         QVERIFY(!item->hasFocus());
893         item->setFocus();
894         QVERIFY(item->hasFocus());
895         QVERIFY(scene.hasFocus());
896
897         item->setFlag(QGraphicsItem::ItemIsFocusable, false);
898         QVERIFY(!item->hasFocus());
899         QVERIFY(scene.hasFocus());
900     }
901     {
902         // Selectable
903         item->setFlag(QGraphicsItem::ItemIsSelectable, false);
904         QVERIFY(!item->isSelected());
905         item->setSelected(true);
906         QVERIFY(!item->isSelected());
907
908         item->setFlag(QGraphicsItem::ItemIsSelectable, true);
909         QVERIFY(!item->isSelected());
910         item->setSelected(true);
911         QVERIFY(item->isSelected());
912         item->setFlag(QGraphicsItem::ItemIsSelectable, false);
913         QVERIFY(!item->isSelected());
914     }
915     {
916         // Movable
917         item->setFlag(QGraphicsItem::ItemIsMovable, false);
918         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
919         event.setScenePos(QPointF(0, 0));
920         event.setButton(Qt::LeftButton);
921         event.setButtons(Qt::LeftButton);
922         QApplication::sendEvent(&scene, &event);
923         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); // mouse grabber is reset
924
925         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
926         event2.setScenePos(QPointF(10, 10));
927         event2.setButton(Qt::LeftButton);
928         event2.setButtons(Qt::LeftButton);
929         QApplication::sendEvent(&scene, &event2);
930         QCOMPARE(item->pos(), QPointF());
931
932         QGraphicsSceneMouseEvent event3(QEvent::GraphicsSceneMouseRelease);
933         event3.setScenePos(QPointF(10, 10));
934         event3.setButtons(0);
935         QApplication::sendEvent(&scene, &event3);
936         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
937
938         item->setFlag(QGraphicsItem::ItemIsMovable, true);
939         QGraphicsSceneMouseEvent event4(QEvent::GraphicsSceneMousePress);
940         event4.setScenePos(QPointF(0, 0));
941         event4.setButton(Qt::LeftButton);
942         event4.setButtons(Qt::LeftButton);
943         QApplication::sendEvent(&scene, &event4);
944         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
945         QGraphicsSceneMouseEvent event5(QEvent::GraphicsSceneMouseMove);
946         event5.setScenePos(QPointF(10, 10));
947         event5.setButton(Qt::LeftButton);
948         event5.setButtons(Qt::LeftButton);
949         QApplication::sendEvent(&scene, &event5);
950         QCOMPARE(item->pos(), QPointF(10, 10));
951     }
952     {
953         QGraphicsItem* clippingParent = new QGraphicsRectItem;
954         clippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
955
956         QGraphicsItem* nonClippingParent = new QGraphicsRectItem;
957         nonClippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
958
959         QGraphicsItem* child = new QGraphicsRectItem(nonClippingParent);
960         QVERIFY(!child->isClipped());
961
962         child->setParentItem(clippingParent);
963         QVERIFY(child->isClipped());
964
965         child->setParentItem(nonClippingParent);
966         QVERIFY(!child->isClipped());
967     }
968 }
969
970 class ImhTester : public QGraphicsItem
971 {
972     QRectF boundingRect() const { return QRectF(); }
973     void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
974 };
975
976 void tst_QGraphicsItem::inputMethodHints()
977 {
978     ImhTester *item = new ImhTester;
979     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
980     item->setFlag(QGraphicsItem::ItemIsFocusable, true);
981     QCOMPARE(item->inputMethodHints(), Qt::ImhNone);
982     ImhTester *item2 = new ImhTester;
983     item2->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
984     item2->setFlag(QGraphicsItem::ItemIsFocusable, true);
985     Qt::InputMethodHints imHints = item2->inputMethodHints();
986     imHints |= Qt::ImhHiddenText;
987     item2->setInputMethodHints(imHints);
988     QGraphicsScene scene;
989     scene.addItem(item);
990     scene.addItem(item2);
991     QGraphicsView view(&scene);
992     QApplication::setActiveWindow(&view);
993     view.show();
994     QTest::qWaitForWindowShown(&view);
995     item->setFocus();
996     QTRY_VERIFY(item->hasFocus());
997     QCOMPARE(view.inputMethodHints(), item->inputMethodHints());
998     item2->setFocus();
999     QTRY_VERIFY(item2->hasFocus());
1000     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1001     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, false);
1002     item->setFocus();
1003     QTRY_VERIFY(item->hasFocus());
1004     //Focus has changed but the new item doesn't accept input method, no hints.
1005     QCOMPARE(view.inputMethodHints(), 0);
1006     item2->setFocus();
1007     QTRY_VERIFY(item2->hasFocus());
1008     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1009     imHints = item2->inputMethodHints();
1010     imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
1011     item2->setInputMethodHints(imHints);
1012     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1013     QGraphicsProxyWidget *widget = new QGraphicsProxyWidget;
1014     QLineEdit *edit = new QLineEdit;
1015     edit->setEchoMode(QLineEdit::Password);
1016     scene.addItem(widget);
1017     widget->setFocus();
1018     QTRY_VERIFY(widget->hasFocus());
1019     //No widget on the proxy, so no hints
1020     QCOMPARE(view.inputMethodHints(), 0);
1021     widget->setWidget(edit);
1022     //View should match with the line edit
1023     QCOMPARE(view.inputMethodHints(), edit->inputMethodHints());
1024 }
1025
1026 void tst_QGraphicsItem::toolTip()
1027 {
1028     QString toolTip = "Qt rocks!";
1029
1030     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
1031     item->setPen(QPen(Qt::red, 1));
1032     item->setBrush(QBrush(Qt::blue));
1033     QVERIFY(item->toolTip().isEmpty());
1034     item->setToolTip(toolTip);
1035     QCOMPARE(item->toolTip(), toolTip);
1036
1037     QGraphicsScene scene;
1038     scene.addItem(item);
1039
1040     QGraphicsView view(&scene);
1041     view.setFixedSize(200, 200);
1042     view.show();
1043     QTest::qWait(250);
1044     {
1045         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
1046                              view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
1047         QApplication::sendEvent(view.viewport(), &helpEvent);
1048         QTest::qWait(250);
1049
1050         bool foundView = false;
1051         bool foundTipLabel = false;
1052         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1053             if (widget == &view)
1054                 foundView = true;
1055             if (widget->inherits("QTipLabel"))
1056                 foundTipLabel = true;
1057         }
1058         QVERIFY(foundView);
1059         QVERIFY(!foundTipLabel);
1060     }
1061
1062     {
1063         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().center(),
1064                              view.viewport()->mapToGlobal(view.viewport()->rect().center()));
1065         QApplication::sendEvent(view.viewport(), &helpEvent);
1066         QTest::qWait(250);
1067
1068         bool foundView = false;
1069         bool foundTipLabel = false;
1070         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1071             if (widget == &view)
1072                 foundView = true;
1073             if (widget->inherits("QTipLabel"))
1074                 foundTipLabel = true;
1075         }
1076         QVERIFY(foundView);
1077         QVERIFY(foundTipLabel);
1078     }
1079
1080     {
1081         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
1082                              view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
1083         QApplication::sendEvent(view.viewport(), &helpEvent);
1084         QTest::qWait(1000);
1085
1086         bool foundView = false;
1087         bool foundTipLabel = false;
1088         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1089             if (widget == &view)
1090                 foundView = true;
1091             if (widget->inherits("QTipLabel") && widget->isVisible())
1092                 foundTipLabel = true;
1093         }
1094         QVERIFY(foundView);
1095         QVERIFY(!foundTipLabel);
1096     }
1097 }
1098
1099 void tst_QGraphicsItem::visible()
1100 {
1101     QGraphicsItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
1102     item->setFlag(QGraphicsItem::ItemIsMovable);
1103     QVERIFY(item->isVisible());
1104     item->setVisible(false);
1105     QVERIFY(!item->isVisible());
1106     item->setVisible(true);
1107     QVERIFY(item->isVisible());
1108
1109     QGraphicsScene scene;
1110     QEvent activate(QEvent::WindowActivate);
1111     QApplication::sendEvent(&scene, &activate);
1112
1113     scene.addItem(item);
1114     QVERIFY(item->isVisible());
1115     QCOMPARE(scene.itemAt(0, 0), item);
1116     item->setVisible(false);
1117     QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)0);
1118     item->setVisible(true);
1119     QCOMPARE(scene.itemAt(0, 0), item);
1120
1121     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1122     event.setButton(Qt::LeftButton);
1123     event.setScenePos(QPointF(0, 0));
1124     QApplication::sendEvent(&scene, &event);
1125     QCOMPARE(scene.mouseGrabberItem(), item);
1126     item->setVisible(false);
1127     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1128     item->setVisible(true);
1129     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1130
1131     item->setFlag(QGraphicsItem::ItemIsFocusable);
1132     item->setFocus();
1133     QVERIFY(item->hasFocus());
1134     item->setVisible(false);
1135     QVERIFY(!item->hasFocus());
1136     item->setVisible(true);
1137     QVERIFY(!item->hasFocus());
1138 }
1139
1140 void tst_QGraphicsItem::isVisibleTo()
1141 {
1142     QGraphicsScene scene;
1143     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1144     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1145     QGraphicsItem *grandChild = scene.addRect(QRectF(50, 50, 50, 50));
1146     QGraphicsItem *stranger = scene.addRect(100, 100, 100, 100);
1147
1148     child->setParentItem(parent);
1149     grandChild->setParentItem(child);
1150
1151     QVERIFY(grandChild->isVisible());
1152     QVERIFY(grandChild->isVisibleTo(grandChild));
1153     QVERIFY(grandChild->isVisibleTo(child));
1154     QVERIFY(grandChild->isVisibleTo(parent));
1155     QVERIFY(grandChild->isVisibleTo(0));
1156     QVERIFY(child->isVisible());
1157     QVERIFY(child->isVisibleTo(child));
1158     QVERIFY(child->isVisibleTo(parent));
1159     QVERIFY(child->isVisibleTo(0));
1160     QVERIFY(parent->isVisible());
1161     QVERIFY(parent->isVisibleTo(parent));
1162     QVERIFY(parent->isVisibleTo(0));
1163     QVERIFY(!parent->isVisibleTo(child));
1164     QVERIFY(!child->isVisibleTo(grandChild));
1165     QVERIFY(!grandChild->isVisibleTo(stranger));
1166     QVERIFY(!child->isVisibleTo(stranger));
1167     QVERIFY(!parent->isVisibleTo(stranger));
1168     QVERIFY(!stranger->isVisibleTo(grandChild));
1169     QVERIFY(!stranger->isVisibleTo(child));
1170     QVERIFY(!stranger->isVisibleTo(parent));
1171
1172     // Case 1: only parent is explicitly hidden
1173     parent->hide();
1174
1175     QVERIFY(!grandChild->isVisible());
1176     QVERIFY(grandChild->isVisibleTo(grandChild));
1177     QVERIFY(grandChild->isVisibleTo(child));
1178     QVERIFY(grandChild->isVisibleTo(parent));
1179     QVERIFY(!grandChild->isVisibleTo(0));
1180     QVERIFY(!child->isVisible());
1181     QVERIFY(child->isVisibleTo(child));
1182     QVERIFY(child->isVisibleTo(parent));
1183     QVERIFY(!child->isVisibleTo(0));
1184     QVERIFY(!parent->isVisible());
1185     QVERIFY(!parent->isVisibleTo(parent));
1186     QVERIFY(!parent->isVisibleTo(0));
1187     QVERIFY(!parent->isVisibleTo(child));
1188     QVERIFY(!child->isVisibleTo(grandChild));
1189     QVERIFY(!grandChild->isVisibleTo(stranger));
1190     QVERIFY(!child->isVisibleTo(stranger));
1191     QVERIFY(!parent->isVisibleTo(stranger));
1192     QVERIFY(!stranger->isVisibleTo(grandChild));
1193     QVERIFY(!stranger->isVisibleTo(child));
1194     QVERIFY(!stranger->isVisibleTo(parent));
1195
1196     // Case 2: only child is hidden
1197     parent->show();
1198     child->hide();
1199
1200     QVERIFY(!grandChild->isVisible());
1201     QVERIFY(grandChild->isVisibleTo(grandChild));
1202     QVERIFY(grandChild->isVisibleTo(child));
1203     QVERIFY(!grandChild->isVisibleTo(parent));
1204     QVERIFY(!grandChild->isVisibleTo(0));
1205     QVERIFY(!child->isVisible());
1206     QVERIFY(!child->isVisibleTo(child));
1207     QVERIFY(!child->isVisibleTo(parent));
1208     QVERIFY(!child->isVisibleTo(0));
1209     QVERIFY(parent->isVisible());
1210     QVERIFY(parent->isVisibleTo(parent));
1211     QVERIFY(parent->isVisibleTo(0));
1212     QVERIFY(!parent->isVisibleTo(child));
1213     QVERIFY(!child->isVisibleTo(grandChild));
1214     QVERIFY(!grandChild->isVisibleTo(stranger));
1215     QVERIFY(!child->isVisibleTo(stranger));
1216     QVERIFY(!parent->isVisibleTo(stranger));
1217     QVERIFY(!stranger->isVisibleTo(grandChild));
1218     QVERIFY(!stranger->isVisibleTo(child));
1219     QVERIFY(!stranger->isVisibleTo(parent));
1220
1221     // Case 3: only grand child is hidden
1222     child->show();
1223     grandChild->hide();
1224
1225     QVERIFY(!grandChild->isVisible());
1226     QVERIFY(!grandChild->isVisibleTo(grandChild));
1227     QVERIFY(!grandChild->isVisibleTo(child));
1228     QVERIFY(!grandChild->isVisibleTo(parent));
1229     QVERIFY(!grandChild->isVisibleTo(0));
1230     QVERIFY(child->isVisible());
1231     QVERIFY(child->isVisibleTo(child));
1232     QVERIFY(child->isVisibleTo(parent));
1233     QVERIFY(child->isVisibleTo(0));
1234     QVERIFY(parent->isVisible());
1235     QVERIFY(parent->isVisibleTo(parent));
1236     QVERIFY(parent->isVisibleTo(0));
1237     QVERIFY(!parent->isVisibleTo(child));
1238     QVERIFY(!child->isVisibleTo(grandChild));
1239     QVERIFY(!grandChild->isVisibleTo(stranger));
1240     QVERIFY(!child->isVisibleTo(stranger));
1241     QVERIFY(!parent->isVisibleTo(stranger));
1242     QVERIFY(!stranger->isVisibleTo(grandChild));
1243     QVERIFY(!stranger->isVisibleTo(child));
1244     QVERIFY(!stranger->isVisibleTo(parent));
1245 }
1246
1247 void tst_QGraphicsItem::explicitlyVisible()
1248 {
1249     QGraphicsScene scene;
1250     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1251     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1252     child->setParentItem(parent);
1253
1254     QVERIFY(parent->isVisible());
1255     QVERIFY(child->isVisible());
1256
1257     parent->hide();
1258
1259     QVERIFY(!parent->isVisible());
1260     QVERIFY(!child->isVisible());
1261
1262     parent->show();
1263     child->hide();
1264
1265     QVERIFY(parent->isVisible());
1266     QVERIFY(!child->isVisible());
1267
1268     parent->hide();
1269
1270     QVERIFY(!parent->isVisible());
1271     QVERIFY(!child->isVisible());
1272
1273     parent->show();
1274
1275     QVERIFY(parent->isVisible());
1276     QVERIFY(!child->isVisible()); // <- explicitly hidden
1277
1278     child->show();
1279
1280     QVERIFY(child->isVisible());
1281
1282     parent->hide();
1283
1284     QVERIFY(!parent->isVisible());
1285     QVERIFY(!child->isVisible()); // <- explicit show doesn't work
1286
1287     parent->show();
1288
1289     QVERIFY(parent->isVisible());
1290     QVERIFY(child->isVisible()); // <- no longer explicitly hidden
1291
1292     // ------------------- Reparenting ------------------------------
1293
1294     QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
1295     QVERIFY(parent2->isVisible());
1296
1297     // Reparent implicitly hidden item to a visible parent.
1298     parent->hide();
1299     QVERIFY(!parent->isVisible());
1300     QVERIFY(!child->isVisible());
1301     child->setParentItem(parent2);
1302     QVERIFY(parent2->isVisible());
1303     QVERIFY(child->isVisible());
1304
1305     // Reparent implicitly hidden item to a hidden parent.
1306     child->setParentItem(parent);
1307     parent2->hide();
1308     child->setParentItem(parent2);
1309     QVERIFY(!parent2->isVisible());
1310     QVERIFY(!child->isVisible());
1311
1312     // Reparent explicitly hidden item to a visible parent.
1313     child->hide();
1314     parent->show();
1315     child->setParentItem(parent);
1316     QVERIFY(parent->isVisible());
1317     QVERIFY(!child->isVisible());
1318
1319     // Reparent explicitly hidden item to a hidden parent.
1320     child->setParentItem(parent2);
1321     QVERIFY(!parent2->isVisible());
1322     QVERIFY(!child->isVisible());
1323
1324     // Reparent explicitly hidden item to a visible parent.
1325     parent->show();
1326     child->setParentItem(parent);
1327     QVERIFY(parent->isVisible());
1328     QVERIFY(!child->isVisible());
1329
1330     // Reparent visible item to a hidden parent.
1331     child->show();
1332     parent2->hide();
1333     child->setParentItem(parent2);
1334     QVERIFY(!parent2->isVisible());
1335     QVERIFY(!child->isVisible());
1336     parent2->show();
1337     QVERIFY(parent2->isVisible());
1338     QVERIFY(child->isVisible());
1339
1340     // Reparent implicitly hidden child to root.
1341     parent2->hide();
1342     QVERIFY(!child->isVisible());
1343     child->setParentItem(0);
1344     QVERIFY(child->isVisible());
1345
1346     // Reparent an explicitly hidden child to root.
1347     child->hide();
1348     child->setParentItem(parent2);
1349     parent2->show();
1350     QVERIFY(!child->isVisible());
1351     child->setParentItem(0);
1352     QVERIFY(!child->isVisible());
1353 }
1354
1355 void tst_QGraphicsItem::enabled()
1356 {
1357     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
1358     item->setFlag(QGraphicsItem::ItemIsMovable);
1359     QVERIFY(item->isEnabled());
1360     item->setEnabled(false);
1361     QVERIFY(!item->isEnabled());
1362     item->setEnabled(true);
1363     QVERIFY(item->isEnabled());
1364     item->setEnabled(false);
1365     item->setFlag(QGraphicsItem::ItemIsFocusable);
1366     QGraphicsScene scene;
1367     QEvent activate(QEvent::WindowActivate);
1368     QApplication::sendEvent(&scene, &activate);
1369
1370     scene.addItem(item);
1371     item->setFocus();
1372     QVERIFY(!item->hasFocus());
1373     item->setEnabled(true);
1374     item->setFocus();
1375     QVERIFY(item->hasFocus());
1376     item->setEnabled(false);
1377     QVERIFY(!item->hasFocus());
1378
1379     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1380     event.setButton(Qt::LeftButton);
1381     event.setScenePos(QPointF(0, 0));
1382     QApplication::sendEvent(&scene, &event);
1383     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1384     item->setEnabled(true);
1385     QApplication::sendEvent(&scene, &event);
1386     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
1387     item->setEnabled(false);
1388     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1389 }
1390
1391 void tst_QGraphicsItem::explicitlyEnabled()
1392 {
1393     QGraphicsScene scene;
1394     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1395     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1396     child->setParentItem(parent);
1397
1398     QVERIFY(parent->isEnabled());
1399     QVERIFY(child->isEnabled());
1400
1401     parent->setEnabled(false);
1402
1403     QVERIFY(!parent->isEnabled());
1404     QVERIFY(!child->isEnabled());
1405
1406     parent->setEnabled(true);
1407     child->setEnabled(false);
1408
1409     QVERIFY(parent->isEnabled());
1410     QVERIFY(!child->isEnabled());
1411
1412     parent->setEnabled(false);
1413
1414     QVERIFY(!parent->isEnabled());
1415     QVERIFY(!child->isEnabled());
1416
1417     parent->setEnabled(true);
1418
1419     QVERIFY(parent->isEnabled());
1420     QVERIFY(!child->isEnabled()); // <- explicitly disabled
1421
1422     child->setEnabled(true);
1423
1424     QVERIFY(child->isEnabled());
1425
1426     parent->setEnabled(false);
1427
1428     QVERIFY(!parent->isEnabled());
1429     QVERIFY(!child->isEnabled()); // <- explicit enabled doesn't work
1430
1431     parent->setEnabled(true);
1432
1433     QVERIFY(parent->isEnabled());
1434     QVERIFY(child->isEnabled()); // <- no longer explicitly disabled
1435
1436     // ------------------- Reparenting ------------------------------
1437
1438     QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
1439     QVERIFY(parent2->isEnabled());
1440
1441     // Reparent implicitly hidden item to a enabled parent.
1442     parent->setEnabled(false);
1443     QVERIFY(!parent->isEnabled());
1444     QVERIFY(!child->isEnabled());
1445     child->setParentItem(parent2);
1446     QVERIFY(parent2->isEnabled());
1447     QVERIFY(child->isEnabled());
1448
1449     // Reparent implicitly hidden item to a hidden parent.
1450     child->setParentItem(parent);
1451     parent2->setEnabled(false);
1452     child->setParentItem(parent2);
1453     QVERIFY(!parent2->isEnabled());
1454     QVERIFY(!child->isEnabled());
1455
1456     // Reparent explicitly hidden item to a enabled parent.
1457     child->setEnabled(false);
1458     parent->setEnabled(true);
1459     child->setParentItem(parent);
1460     QVERIFY(parent->isEnabled());
1461     QVERIFY(!child->isEnabled());
1462
1463     // Reparent explicitly hidden item to a hidden parent.
1464     child->setParentItem(parent2);
1465     QVERIFY(!parent2->isEnabled());
1466     QVERIFY(!child->isEnabled());
1467
1468     // Reparent explicitly hidden item to a enabled parent.
1469     parent->setEnabled(true);
1470     child->setParentItem(parent);
1471     QVERIFY(parent->isEnabled());
1472     QVERIFY(!child->isEnabled());
1473
1474     // Reparent enabled item to a hidden parent.
1475     child->setEnabled(true);
1476     parent2->setEnabled(false);
1477     child->setParentItem(parent2);
1478     QVERIFY(!parent2->isEnabled());
1479     QVERIFY(!child->isEnabled());
1480     parent2->setEnabled(true);
1481     QVERIFY(parent2->isEnabled());
1482     QVERIFY(child->isEnabled());
1483
1484     // Reparent implicitly hidden child to root.
1485     parent2->setEnabled(false);
1486     QVERIFY(!child->isEnabled());
1487     child->setParentItem(0);
1488     QVERIFY(child->isEnabled());
1489
1490     // Reparent an explicitly hidden child to root.
1491     child->setEnabled(false);
1492     child->setParentItem(parent2);
1493     parent2->setEnabled(true);
1494     QVERIFY(!child->isEnabled());
1495     child->setParentItem(0);
1496     QVERIFY(!child->isEnabled());
1497 }
1498
1499 class SelectChangeItem : public QGraphicsRectItem
1500 {
1501 public:
1502     SelectChangeItem() : QGraphicsRectItem(-50, -50, 100, 100) { setBrush(Qt::blue); }
1503     QList<bool> values;
1504
1505 protected:
1506     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
1507     {
1508         if (change == ItemSelectedChange)
1509             values << value.toBool();
1510         return QGraphicsRectItem::itemChange(change, value);
1511     }
1512 };
1513
1514 void tst_QGraphicsItem::selected()
1515 {
1516     SelectChangeItem *item = new SelectChangeItem;
1517     item->setFlag(QGraphicsItem::ItemIsSelectable);
1518     QVERIFY(!item->isSelected());
1519     QVERIFY(item->values.isEmpty());
1520     item->setSelected(true);
1521     QCOMPARE(item->values.size(), 1);
1522     QCOMPARE(item->values.last(), true);
1523     QVERIFY(item->isSelected());
1524     item->setSelected(false);
1525     QCOMPARE(item->values.size(), 2);
1526     QCOMPARE(item->values.last(), false);
1527     QVERIFY(!item->isSelected());
1528     item->setSelected(true);
1529     QCOMPARE(item->values.size(), 3);
1530     item->setEnabled(false);
1531     QCOMPARE(item->values.size(), 4);
1532     QCOMPARE(item->values.last(), false);
1533     QVERIFY(!item->isSelected());
1534     item->setEnabled(true);
1535     QCOMPARE(item->values.size(), 4);
1536     item->setSelected(true);
1537     QCOMPARE(item->values.size(), 5);
1538     QCOMPARE(item->values.last(), true);
1539     QVERIFY(item->isSelected());
1540     item->setVisible(false);
1541     QCOMPARE(item->values.size(), 6);
1542     QCOMPARE(item->values.last(), false);
1543     QVERIFY(!item->isSelected());
1544     item->setVisible(true);
1545     QCOMPARE(item->values.size(), 6);
1546     item->setSelected(true);
1547     QCOMPARE(item->values.size(), 7);
1548     QCOMPARE(item->values.last(), true);
1549     QVERIFY(item->isSelected());
1550
1551     QGraphicsScene scene(-100, -100, 200, 200);
1552     scene.addItem(item);
1553     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
1554     item->setSelected(false);
1555     QVERIFY(scene.selectedItems().isEmpty());
1556     item->setSelected(true);
1557     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
1558     item->setSelected(false);
1559     QVERIFY(scene.selectedItems().isEmpty());
1560
1561     // Interactive selection
1562     QGraphicsView view(&scene);
1563     view.setFixedSize(250, 250);
1564     view.show();
1565
1566     QTest::qWaitForWindowShown(&view);
1567     qApp->processEvents();
1568     qApp->processEvents();
1569
1570     scene.clearSelection();
1571     QCOMPARE(item->values.size(), 10);
1572     QCOMPARE(item->values.last(), false);
1573     QVERIFY(!item->isSelected());
1574
1575     // Click inside and check that it's selected
1576     QTest::mouseMove(view.viewport());
1577     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
1578     QCOMPARE(item->values.size(), 11);
1579     QCOMPARE(item->values.last(), true);
1580     QVERIFY(item->isSelected());
1581
1582     // Click outside and check that it's not selected
1583     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos() + QPointF(item->boundingRect().width(), item->boundingRect().height())));
1584     QCOMPARE(item->values.size(), 12);
1585     QCOMPARE(item->values.last(), false);
1586     QVERIFY(!item->isSelected());
1587
1588     SelectChangeItem *item2 = new SelectChangeItem;
1589     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1590     item2->setPos(100, 0);
1591     scene.addItem(item2);
1592
1593     // Click inside and check that it's selected
1594     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
1595     QCOMPARE(item->values.size(), 13);
1596     QCOMPARE(item->values.last(), true);
1597     QVERIFY(item->isSelected());
1598
1599     // Click inside item2 and check that it's selected, and item is not
1600     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1601     QCOMPARE(item->values.size(), 14);
1602     QCOMPARE(item->values.last(), false);
1603     QVERIFY(!item->isSelected());
1604     QCOMPARE(item2->values.size(), 1);
1605     QCOMPARE(item2->values.last(), true);
1606     QVERIFY(item2->isSelected());
1607 }
1608
1609 void tst_QGraphicsItem::selected2()
1610 {
1611     // Selecting an item, then moving another previously caused a crash.
1612     QGraphicsScene scene;
1613     QGraphicsItem *line1 = scene.addRect(QRectF(0, 0, 100, 100));
1614     line1->setPos(-105, 0);
1615     line1->setFlag(QGraphicsItem::ItemIsSelectable);
1616
1617     QGraphicsItem *line2 = scene.addRect(QRectF(0, 0, 100, 100));
1618     line2->setFlag(QGraphicsItem::ItemIsMovable);
1619
1620     line1->setSelected(true);
1621
1622     {
1623         QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
1624         mousePress.setScenePos(QPointF(50, 50));
1625         mousePress.setButton(Qt::LeftButton);
1626         QApplication::sendEvent(&scene, &mousePress);
1627         QVERIFY(mousePress.isAccepted());
1628     }
1629     {
1630         QGraphicsSceneMouseEvent mouseMove(QEvent::GraphicsSceneMouseMove);
1631         mouseMove.setScenePos(QPointF(60, 60));
1632         mouseMove.setButton(Qt::LeftButton);
1633         mouseMove.setButtons(Qt::LeftButton);
1634         QApplication::sendEvent(&scene, &mouseMove);
1635         QVERIFY(mouseMove.isAccepted());
1636     }
1637 }
1638
1639 void tst_QGraphicsItem::selected_group()
1640 {
1641     QGraphicsScene scene;
1642     QGraphicsItem *item1 = scene.addRect(QRectF());
1643     QGraphicsItem *item2 = scene.addRect(QRectF());
1644     item1->setFlag(QGraphicsItem::ItemIsSelectable);
1645     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1646     scene.addRect(QRectF())->setParentItem(item1);
1647     QGraphicsItem *leaf = scene.addRect(QRectF());
1648     leaf->setFlag(QGraphicsItem::ItemIsSelectable);
1649     leaf->setParentItem(item2);
1650
1651     QGraphicsItemGroup *group = scene.createItemGroup(QList<QGraphicsItem *>() << item1 << item2);
1652     QCOMPARE(group->scene(), &scene);
1653     group->setFlag(QGraphicsItem::ItemIsSelectable);
1654     foreach (QGraphicsItem *item, scene.items()) {
1655         if (item == group)
1656             QVERIFY(!item->group());
1657         else
1658             QCOMPARE(item->group(), group);
1659     }
1660
1661     QVERIFY(group->handlesChildEvents());
1662     QVERIFY(!group->isSelected());
1663     group->setSelected(false);
1664     QVERIFY(!group->isSelected());
1665     group->setSelected(true);
1666     QVERIFY(group->isSelected());
1667     foreach (QGraphicsItem *item, scene.items())
1668         QVERIFY(item->isSelected());
1669     group->setSelected(false);
1670     QVERIFY(!group->isSelected());
1671     foreach (QGraphicsItem *item, scene.items())
1672         QVERIFY(!item->isSelected());
1673     leaf->setSelected(true);
1674     foreach (QGraphicsItem *item, scene.items())
1675         QVERIFY(item->isSelected());
1676     leaf->setSelected(false);
1677     foreach (QGraphicsItem *item, scene.items())
1678         QVERIFY(!item->isSelected());
1679
1680     leaf->setSelected(true);
1681     QGraphicsScene scene2;
1682     scene2.addItem(item1);
1683     QVERIFY(!item1->isSelected());
1684     QVERIFY(item2->isSelected());
1685 }
1686
1687 void tst_QGraphicsItem::selected_textItem()
1688 {
1689     QGraphicsScene scene;
1690     QGraphicsTextItem *text = scene.addText(QLatin1String("Text"));
1691     text->setFlag(QGraphicsItem::ItemIsSelectable);
1692
1693     QGraphicsView view(&scene);
1694     view.show();
1695     QTest::qWaitForWindowShown(&view);
1696     QTest::qWait(20);
1697
1698     QTRY_VERIFY(!text->isSelected());
1699     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
1700                       view.mapFromScene(text->mapToScene(0, 0)));
1701     QTRY_VERIFY(text->isSelected());
1702
1703     text->setSelected(false);
1704     text->setTextInteractionFlags(Qt::TextEditorInteraction);
1705
1706     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
1707                       view.mapFromScene(text->mapToScene(0, 0)));
1708     QTRY_VERIFY(text->isSelected());
1709 }
1710
1711 void tst_QGraphicsItem::selected_multi()
1712 {
1713     // Test multiselection behavior
1714     QGraphicsScene scene;
1715
1716     // Create two disjoint items
1717     QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
1718     QGraphicsItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
1719     item1->setPos(-15, 0);
1720     item2->setPos(15, 20);
1721
1722     // Make both items selectable
1723     item1->setFlag(QGraphicsItem::ItemIsSelectable);
1724     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1725
1726     // Create and show a view
1727     QGraphicsView view(&scene);
1728     view.show();
1729     view.fitInView(scene.sceneRect());
1730     qApp->processEvents();
1731
1732     QVERIFY(!item1->isSelected());
1733     QVERIFY(!item2->isSelected());
1734
1735     // Start clicking
1736     QTest::qWait(200);
1737
1738     // Click on item1
1739     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1740     QTest::qWait(20);
1741     QVERIFY(item1->isSelected());
1742     QVERIFY(!item2->isSelected());
1743
1744     // Click on item2
1745     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1746     QTest::qWait(20);
1747     QVERIFY(item2->isSelected());
1748     QVERIFY(!item1->isSelected());
1749
1750     // Ctrl-click on item1
1751     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1752     QTest::qWait(20);
1753     QVERIFY(item2->isSelected());
1754     QVERIFY(item1->isSelected());
1755
1756     // Ctrl-click on item1 again
1757     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1758     QTest::qWait(20);
1759     QVERIFY(item2->isSelected());
1760     QVERIFY(!item1->isSelected());
1761
1762     // Ctrl-click on item2
1763     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item2->scenePos()));
1764     QTest::qWait(20);
1765     QVERIFY(!item2->isSelected());
1766     QVERIFY(!item1->isSelected());
1767
1768     // Click on item1
1769     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1770     QTest::qWait(20);
1771     QVERIFY(item1->isSelected());
1772     QVERIFY(!item2->isSelected());
1773
1774     // Click on scene
1775     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(0, 0));
1776     QTest::qWait(20);
1777     QVERIFY(!item1->isSelected());
1778     QVERIFY(!item2->isSelected());
1779
1780     // Click on item1
1781     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1782     QTest::qWait(20);
1783     QVERIFY(item1->isSelected());
1784     QVERIFY(!item2->isSelected());
1785
1786     // Ctrl-click on scene
1787     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(0, 0));
1788     QTest::qWait(20);
1789     QVERIFY(!item1->isSelected());
1790     QVERIFY(!item2->isSelected());
1791
1792     // Click on item1
1793     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1794     QTest::qWait(20);
1795     QVERIFY(item1->isSelected());
1796     QVERIFY(!item2->isSelected());
1797
1798     // Press on item2
1799     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1800     QTest::qWait(20);
1801     QVERIFY(!item1->isSelected());
1802     QVERIFY(item2->isSelected());
1803
1804     // Release on item2
1805     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1806     QTest::qWait(20);
1807     QVERIFY(!item1->isSelected());
1808     QVERIFY(item2->isSelected());
1809
1810     // Click on item1
1811     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1812     QTest::qWait(20);
1813     QVERIFY(item1->isSelected());
1814     QVERIFY(!item2->isSelected());
1815
1816     // Ctrl-click on item1
1817     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1818     QTest::qWait(20);
1819     QVERIFY(!item1->isSelected());
1820     QVERIFY(!item2->isSelected());
1821
1822     // Ctrl-press on item1
1823     QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1824     QTest::qWait(20);
1825     QVERIFY(!item1->isSelected());
1826     QVERIFY(!item2->isSelected());
1827
1828     {
1829         // Ctrl-move on item1
1830         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
1831         QApplication::sendEvent(view.viewport(), &event);
1832         QTest::qWait(20);
1833         QVERIFY(!item1->isSelected());
1834         QVERIFY(!item2->isSelected());
1835     }
1836
1837     // Release on item1
1838     QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1839     QTest::qWait(20);
1840     QVERIFY(item1->isSelected());
1841     QVERIFY(!item2->isSelected());
1842
1843     item1->setFlag(QGraphicsItem::ItemIsMovable);
1844     item1->setSelected(false);
1845
1846     // Ctrl-press on item1
1847     QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1848     QTest::qWait(20);
1849     QVERIFY(!item1->isSelected());
1850     QVERIFY(!item2->isSelected());
1851
1852     {
1853         // Ctrl-move on item1
1854         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
1855         QApplication::sendEvent(view.viewport(), &event);
1856         QTest::qWait(20);
1857         QVERIFY(item1->isSelected());
1858         QVERIFY(!item2->isSelected());
1859     }
1860
1861     // Release on item1
1862     QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1863     QTest::qWait(20);
1864     QVERIFY(item1->isSelected());
1865     QVERIFY(!item2->isSelected());
1866 }
1867
1868 void tst_QGraphicsItem::acceptedMouseButtons()
1869 {
1870     QGraphicsScene scene;
1871     QGraphicsRectItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
1872     QGraphicsRectItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
1873     item2->setZValue(1);
1874
1875     item1->setFlag(QGraphicsItem::ItemIsMovable);
1876     item2->setFlag(QGraphicsItem::ItemIsMovable);
1877
1878     QCOMPARE(item1->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
1879     QCOMPARE(item2->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
1880
1881     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1882     event.setButton(Qt::LeftButton);
1883     event.setScenePos(QPointF(0, 0));
1884     QApplication::sendEvent(&scene, &event);
1885     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item2);
1886     item2->setAcceptedMouseButtons(0);
1887     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1888     QApplication::sendEvent(&scene, &event);
1889     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item1);
1890 }
1891
1892 class HoverItem : public QGraphicsRectItem
1893 {
1894 public:
1895     HoverItem(const QRectF &rect)
1896         : QGraphicsRectItem(rect), hoverInCount(0),
1897           hoverMoveCount(0), hoverOutCount(0)
1898     { }
1899
1900     int hoverInCount;
1901     int hoverMoveCount;
1902     int hoverOutCount;
1903 protected:
1904     void hoverEnterEvent(QGraphicsSceneHoverEvent *)
1905     { ++hoverInCount; }
1906
1907     void hoverMoveEvent(QGraphicsSceneHoverEvent *)
1908     { ++hoverMoveCount; }
1909
1910     void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
1911     { ++hoverOutCount; }
1912 };
1913
1914 void tst_QGraphicsItem::acceptsHoverEvents()
1915 {
1916     QGraphicsScene scene;
1917     HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
1918     HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
1919     scene.addItem(item1);
1920     scene.addItem(item2);
1921     item2->setZValue(1);
1922
1923     QVERIFY(!item1->acceptsHoverEvents());
1924     QVERIFY(!item2->acceptsHoverEvents());
1925     item1->setAcceptsHoverEvents(true);
1926     item2->setAcceptsHoverEvents(true);
1927
1928     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
1929     event.setScenePos(QPointF(-100, -100));
1930     QApplication::sendEvent(&scene, &event);
1931     event.setScenePos(QPointF(-2.5, -2.5));
1932     QApplication::sendEvent(&scene, &event);
1933
1934     QCOMPARE(item1->hoverInCount, 0);
1935     QCOMPARE(item2->hoverInCount, 1);
1936
1937     item1->setAcceptsHoverEvents(false);
1938     item2->setAcceptsHoverEvents(false);
1939
1940     event.setScenePos(QPointF(-100, -100));
1941     QApplication::sendEvent(&scene, &event);
1942     event.setScenePos(QPointF(-2.5, -2.5));
1943     QApplication::sendEvent(&scene, &event);
1944
1945     QCOMPARE(item1->hoverInCount, 0);
1946     QCOMPARE(item2->hoverInCount, 1);
1947
1948     item1->setAcceptsHoverEvents(true);
1949     item2->setAcceptsHoverEvents(false);
1950
1951     event.setScenePos(QPointF(-100, -100));
1952     QApplication::sendEvent(&scene, &event);
1953     event.setScenePos(QPointF(-2.5, -2.5));
1954     QApplication::sendEvent(&scene, &event);
1955
1956     QCOMPARE(item1->hoverInCount, 1);
1957     QCOMPARE(item2->hoverInCount, 1);
1958 }
1959
1960 void tst_QGraphicsItem::childAcceptsHoverEvents()
1961 {
1962     QGraphicsScene scene;
1963     HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
1964     HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
1965
1966     scene.addItem(item1);
1967     scene.addItem(item2);
1968     item2->setParentItem(item1);
1969     item2->setAcceptHoverEvents(true);
1970
1971     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
1972     event.setScenePos(QPointF(-100, -100));
1973     QApplication::sendEvent(&scene, &event);
1974     QCOMPARE(item2->hoverInCount, 0);
1975     QCOMPARE(item2->hoverMoveCount, 0);
1976     QCOMPARE(item2->hoverOutCount, 0);
1977     QCOMPARE(item1->hoverInCount, 0);
1978     QCOMPARE(item1->hoverMoveCount, 0);
1979     QCOMPARE(item1->hoverOutCount, 0);
1980
1981     event.setScenePos(QPointF(-2.5, -2.5));
1982     QApplication::sendEvent(&scene, &event);
1983
1984     QCOMPARE(item2->hoverInCount, 1);
1985     QCOMPARE(item2->hoverMoveCount, 1);
1986     QCOMPARE(item2->hoverOutCount, 0);
1987     QCOMPARE(item1->hoverInCount, 0);
1988     QCOMPARE(item1->hoverMoveCount, 0);
1989     QCOMPARE(item1->hoverOutCount, 0);
1990
1991     event.setScenePos(QPointF(0, 0));
1992     QApplication::sendEvent(&scene, &event);
1993
1994     QCOMPARE(item2->hoverInCount, 1);
1995     QCOMPARE(item2->hoverMoveCount, 2);
1996     QCOMPARE(item2->hoverOutCount, 0);
1997     QCOMPARE(item1->hoverInCount, 0);
1998     QCOMPARE(item1->hoverMoveCount, 0);
1999     QCOMPARE(item1->hoverOutCount, 0);
2000
2001     event.setScenePos(QPointF(-7, -7));
2002     QApplication::sendEvent(&scene, &event);
2003
2004     QCOMPARE(item2->hoverInCount, 1);
2005     QCOMPARE(item2->hoverMoveCount, 2);
2006     QCOMPARE(item2->hoverOutCount, 1);
2007     QCOMPARE(item1->hoverInCount, 0);
2008     QCOMPARE(item1->hoverMoveCount, 0);
2009     QCOMPARE(item1->hoverOutCount, 0);
2010
2011     event.setScenePos(QPointF(0, 0));
2012     QApplication::sendEvent(&scene, &event);
2013
2014     QCOMPARE(item2->hoverInCount, 2);
2015     QCOMPARE(item2->hoverMoveCount, 3);
2016     QCOMPARE(item2->hoverOutCount, 1);
2017     QCOMPARE(item1->hoverInCount, 0);
2018     QCOMPARE(item1->hoverMoveCount, 0);
2019     QCOMPARE(item1->hoverOutCount, 0);
2020
2021     HoverItem *item0 = new HoverItem(QRectF(-20, -20, 20, 20));
2022     scene.addItem(item0);
2023     item1->setParentItem(item0);
2024     item0->setAcceptHoverEvents(true);
2025
2026     event.setScenePos(QPointF(-100, -100));
2027     QApplication::sendEvent(&scene, &event);
2028
2029     event.setScenePos(QPointF(-15, -15));
2030     QApplication::sendEvent(&scene, &event);
2031
2032     QCOMPARE(item2->hoverInCount, 2);
2033     QCOMPARE(item2->hoverMoveCount, 3);
2034     QCOMPARE(item2->hoverOutCount, 2);
2035     QCOMPARE(item1->hoverInCount, 0);
2036     QCOMPARE(item1->hoverMoveCount, 0);
2037     QCOMPARE(item1->hoverOutCount, 0);
2038     QCOMPARE(item0->hoverInCount, 1);
2039     QCOMPARE(item0->hoverMoveCount, 1);
2040     QCOMPARE(item0->hoverOutCount, 0);
2041 }
2042
2043 void tst_QGraphicsItem::hasFocus()
2044 {
2045     QGraphicsLineItem *line = new QGraphicsLineItem;
2046     QVERIFY(!line->hasFocus());
2047     line->setFocus();
2048     QVERIFY(!line->hasFocus());
2049
2050     QGraphicsScene scene;
2051     QEvent activate(QEvent::WindowActivate);
2052     QApplication::sendEvent(&scene, &activate);
2053
2054     scene.addItem(line);
2055
2056     line->setFocus();
2057     QVERIFY(!line->hasFocus());
2058     line->setFlag(QGraphicsItem::ItemIsFocusable);
2059     line->setFocus();
2060     QVERIFY(line->hasFocus());
2061
2062     QGraphicsScene scene2;
2063     QApplication::sendEvent(&scene2, &activate);
2064
2065     scene2.addItem(line);
2066     QVERIFY(!line->hasFocus());
2067
2068     QCOMPARE(scene.focusItem(), (QGraphicsItem *)0);
2069     QCOMPARE(scene2.focusItem(), (QGraphicsItem *)0);
2070
2071     line->setFocus();
2072     QVERIFY(line->hasFocus());
2073     line->clearFocus();
2074     QVERIFY(!line->hasFocus());
2075
2076     QGraphicsLineItem *line2 = new QGraphicsLineItem;
2077     line2->setFlag(QGraphicsItem::ItemIsFocusable);
2078     scene2.addItem(line2);
2079
2080     line2->setFocus();
2081     QVERIFY(!line->hasFocus());
2082     QVERIFY(line2->hasFocus());
2083     line->setFocus();
2084     QVERIFY(line->hasFocus());
2085     QVERIFY(!line2->hasFocus());
2086 }
2087
2088 void tst_QGraphicsItem::pos()
2089 {
2090     QGraphicsItem *child = new QGraphicsLineItem;
2091     QGraphicsItem *parent = new QGraphicsLineItem;
2092
2093     QCOMPARE(child->pos(), QPointF());
2094     QCOMPARE(parent->pos(), QPointF());
2095
2096     child->setParentItem(parent);
2097     child->setPos(10, 10);
2098
2099     QCOMPARE(child->pos(), QPointF(10, 10));
2100
2101     parent->setPos(10, 10);
2102
2103     QCOMPARE(parent->pos(), QPointF(10, 10));
2104     QCOMPARE(child->pos(), QPointF(10, 10));
2105
2106     delete child;
2107     delete parent;
2108 }
2109
2110 void tst_QGraphicsItem::scenePos()
2111 {
2112     QGraphicsItem *child = new QGraphicsLineItem;
2113     QGraphicsItem *parent = new QGraphicsLineItem;
2114
2115     QCOMPARE(child->scenePos(), QPointF());
2116     QCOMPARE(parent->scenePos(), QPointF());
2117
2118     child->setParentItem(parent);
2119     child->setPos(10, 10);
2120
2121     QCOMPARE(child->scenePos(), QPointF(10, 10));
2122
2123     parent->setPos(10, 10);
2124
2125     QCOMPARE(parent->scenePos(), QPointF(10, 10));
2126     QCOMPARE(child->scenePos(), QPointF(20, 20));
2127
2128     parent->setPos(20, 20);
2129
2130     QCOMPARE(parent->scenePos(), QPointF(20, 20));
2131     QCOMPARE(child->scenePos(), QPointF(30, 30));
2132
2133     delete child;
2134     delete parent;
2135 }
2136
2137 void tst_QGraphicsItem::matrix()
2138 {
2139     QGraphicsLineItem line;
2140     QCOMPARE(line.matrix(), QMatrix());
2141     line.setMatrix(QMatrix().rotate(90));
2142     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2143     line.setMatrix(QMatrix().rotate(90));
2144     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2145     line.setMatrix(QMatrix().rotate(90), true);
2146     QCOMPARE(line.matrix(), QMatrix().rotate(180));
2147     line.setMatrix(QMatrix().rotate(-90), true);
2148     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2149     line.resetMatrix();
2150     QCOMPARE(line.matrix(), QMatrix());
2151
2152     line.rotate(90);
2153     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2154     line.rotate(90);
2155     QCOMPARE(line.matrix(), QMatrix().rotate(90).rotate(90));
2156     line.resetMatrix();
2157
2158     line.scale(2, 4);
2159     QCOMPARE(line.matrix(), QMatrix().scale(2, 4));
2160     line.scale(2, 4);
2161     QCOMPARE(line.matrix(), QMatrix().scale(2, 4).scale(2, 4));
2162     line.resetMatrix();
2163
2164     line.shear(2, 4);
2165     QCOMPARE(line.matrix(), QMatrix().shear(2, 4));
2166     line.shear(2, 4);
2167     QCOMPARE(line.matrix(), QMatrix().shear(2, 4).shear(2, 4));
2168     line.resetMatrix();
2169
2170     line.translate(10, 10);
2171     QCOMPARE(line.matrix(), QMatrix().translate(10, 10));
2172     line.translate(10, 10);
2173     QCOMPARE(line.matrix(), QMatrix().translate(10, 10).translate(10, 10));
2174     line.resetMatrix();
2175 }
2176
2177 void tst_QGraphicsItem::sceneMatrix()
2178 {
2179     QGraphicsLineItem *parent = new QGraphicsLineItem;
2180     QGraphicsLineItem *child = new QGraphicsLineItem(QLineF(), parent);
2181
2182     QCOMPARE(parent->sceneMatrix(), QMatrix());
2183     QCOMPARE(child->sceneMatrix(), QMatrix());
2184
2185     parent->translate(10, 10);
2186     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
2187     QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10));
2188
2189     child->translate(10, 10);
2190     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
2191     QCOMPARE(child->sceneMatrix(), QMatrix().translate(20, 20));
2192
2193     parent->rotate(90);
2194     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10).rotate(90));
2195     QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10).rotate(90).translate(10, 10));
2196
2197     delete child;
2198     delete parent;
2199 }
2200
2201 void tst_QGraphicsItem::setMatrix()
2202 {
2203     QGraphicsScene scene;
2204     qRegisterMetaType<QList<QRectF> >("QList<QRectF>");
2205     QSignalSpy spy(&scene, SIGNAL(changed(QList<QRectF>)));
2206     QRectF unrotatedRect(-12, -34, 56, 78);
2207     QGraphicsRectItem item(unrotatedRect, 0, &scene);
2208     scene.update(scene.sceneRect());
2209     QApplication::instance()->processEvents();
2210
2211     QCOMPARE(spy.count(), 1);
2212
2213     item.setMatrix(QMatrix().rotate(qreal(12.34)));
2214     QRectF rotatedRect = scene.sceneRect();
2215     QVERIFY(unrotatedRect != rotatedRect);
2216     scene.update(scene.sceneRect());
2217     QApplication::instance()->processEvents();
2218
2219     QCOMPARE(spy.count(), 2);
2220
2221     item.setMatrix(QMatrix());
2222
2223     scene.update(scene.sceneRect());
2224     QApplication::instance()->processEvents();
2225
2226     QCOMPARE(spy.count(), 3);
2227     QList<QRectF> rlist = qVariantValue<QList<QRectF> >(spy.last().at(0));
2228
2229     QCOMPARE(rlist.size(), 3);
2230     QCOMPARE(rlist.at(0), rotatedRect);   // From item.setMatrix() (clearing rotated rect)
2231     QCOMPARE(rlist.at(1), rotatedRect);   // From scene.update()   (updating scene rect)
2232     QCOMPARE(rlist.at(2), unrotatedRect); // From post-update      (update current state)
2233 }
2234
2235 static QList<QGraphicsItem *> _paintedItems;
2236 class PainterItem : public QGraphicsItem
2237 {
2238 protected:
2239     QRectF boundingRect() const
2240     { return QRectF(-10, -10, 20, 20); }
2241
2242     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
2243     { _paintedItems << this; painter->fillRect(boundingRect(), Qt::red); }
2244 };
2245
2246 void tst_QGraphicsItem::zValue()
2247 {
2248     Q_CHECK_PAINTEVENTS
2249
2250     QGraphicsScene scene;
2251
2252     QGraphicsItem *item1 = new PainterItem;
2253     QGraphicsItem *item2 = new PainterItem;
2254     QGraphicsItem *item3 = new PainterItem;
2255     QGraphicsItem *item4 = new PainterItem;
2256     scene.addItem(item1);
2257     scene.addItem(item2);
2258     scene.addItem(item3);
2259     scene.addItem(item4);
2260     item2->setZValue(-3);
2261     item4->setZValue(-2);
2262     item1->setZValue(-1);
2263     item3->setZValue(0);
2264
2265     QGraphicsView view(&scene);
2266     view.show();
2267 #ifdef Q_WS_X11
2268     qt_x11_wait_for_window_manager(&view);
2269 #endif
2270     QApplication::processEvents();
2271 #ifdef Q_WS_QWS
2272     QApplication::sendPostedEvents(); //glib workaround
2273 #endif
2274
2275     QTRY_VERIFY(!_paintedItems.isEmpty());
2276     QVERIFY((_paintedItems.size() % 4) == 0);
2277     for (int i = 0; i < 3; ++i)
2278         QVERIFY(_paintedItems.at(i)->zValue() < _paintedItems.at(i + 1)->zValue());
2279 }
2280
2281 void tst_QGraphicsItem::shape()
2282 {
2283     QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
2284
2285     // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
2286     // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
2287     const qreal penWidthZero = qreal(0.00000001);
2288
2289     QPainterPathStroker ps;
2290     ps.setWidth(penWidthZero);
2291
2292     QPainterPath path(line.line().p1());
2293     path.lineTo(line.line().p2());
2294     QPainterPath p = ps.createStroke(path);
2295     p.addPath(path);
2296     QCOMPARE(line.shape(), p);
2297
2298     QPen linePen;
2299     linePen.setWidthF(5.0);
2300     linePen.setCapStyle(Qt::RoundCap);
2301     line.setPen(linePen);
2302
2303     ps.setCapStyle(line.pen().capStyle());
2304     ps.setWidth(line.pen().widthF());
2305     p = ps.createStroke(path);
2306     p.addPath(path);
2307     QCOMPARE(line.shape(), p);
2308
2309     linePen.setCapStyle(Qt::FlatCap);
2310     line.setPen(linePen);
2311     ps.setCapStyle(line.pen().capStyle());
2312     p = ps.createStroke(path);
2313     p.addPath(path);
2314     QCOMPARE(line.shape(), p);
2315
2316     linePen.setCapStyle(Qt::SquareCap);
2317     line.setPen(linePen);
2318     ps.setCapStyle(line.pen().capStyle());
2319     p = ps.createStroke(path);
2320     p.addPath(path);
2321     QCOMPARE(line.shape(), p);
2322
2323     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2324     QPainterPathStroker ps1;
2325     ps1.setWidth(penWidthZero);
2326     path = QPainterPath();
2327     path.addRect(rect.rect());
2328     p = ps1.createStroke(path);
2329     p.addPath(path);
2330     QCOMPARE(rect.shape(), p);
2331
2332     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2333     QPainterPathStroker ps2;
2334     ps2.setWidth(ellipse.pen().widthF() <= 0.0 ? penWidthZero : ellipse.pen().widthF());
2335     path = QPainterPath();
2336     path.addEllipse(ellipse.rect());
2337     p = ps2.createStroke(path);
2338     p.addPath(path);
2339     QCOMPARE(ellipse.shape(), p);
2340
2341     QPainterPathStroker ps3;
2342     ps3.setWidth(penWidthZero);
2343     p = ps3.createStroke(path);
2344     p.addPath(path);
2345     QGraphicsPathItem pathItem(path);
2346     QCOMPARE(pathItem.shape(), p);
2347
2348     QRegion region(QRect(0, 0, 300, 200));
2349     region = region.subtracted(QRect(50, 50, 200, 100));
2350
2351     QImage image(300, 200, QImage::Format_ARGB32_Premultiplied);
2352     image.fill(0);
2353     QPainter painter(&image);
2354     painter.setClipRegion(region);
2355     painter.fillRect(0, 0, 300, 200, Qt::green);
2356     painter.end();
2357     QPixmap pixmap = QPixmap::fromImage(image);
2358
2359     QGraphicsPixmapItem pixmapItem(pixmap);
2360     path = QPainterPath();
2361     path.addRegion(region);
2362
2363     {
2364         QBitmap bitmap(300, 200);
2365         bitmap.clear();
2366         QPainter painter(&bitmap);
2367         painter.setClipRegion(region);
2368         painter.fillRect(0, 0, 300, 200, Qt::color1);
2369         painter.end();
2370
2371         QBitmap bitmap2(300, 200);
2372         bitmap2.clear();
2373         painter.begin(&bitmap2);
2374         painter.setClipPath(pixmapItem.shape());
2375         painter.fillRect(0, 0, 300, 200, Qt::color1);
2376         painter.end();
2377
2378         QCOMPARE(bitmap.toImage(), bitmap2.toImage());
2379     }
2380
2381     QPolygonF poly;
2382     poly << QPointF(0, 0) << QPointF(10, 0) << QPointF(0, 10);
2383     QGraphicsPolygonItem polygon(poly);
2384     path = QPainterPath();
2385     path.addPolygon(poly);
2386
2387     QPainterPathStroker ps4;
2388     ps4.setWidth(penWidthZero);
2389     p = ps4.createStroke(path);
2390     p.addPath(path);
2391     QCOMPARE(polygon.shape(), p);
2392 }
2393
2394 void tst_QGraphicsItem::contains()
2395 {
2396     if (sizeof(qreal) != sizeof(double))
2397         QSKIP("Skipped due to rounding errors");
2398
2399     // Rect
2400     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2401     QVERIFY(!rect.contains(QPointF(-11, -10)));
2402     QVERIFY(rect.contains(QPointF(-10, -10)));
2403     QVERIFY(!rect.contains(QPointF(-11, 0)));
2404     QVERIFY(rect.contains(QPointF(-10, 0)));
2405     QVERIFY(rect.contains(QPointF(0, -10)));
2406     QVERIFY(rect.contains(QPointF(0, 0)));
2407     QVERIFY(rect.contains(QPointF(9, 9)));
2408
2409     // Ellipse
2410     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2411     QVERIFY(!ellipse.contains(QPointF(-10, -10)));
2412     QVERIFY(ellipse.contains(QPointF(-9, 0)));
2413     QVERIFY(ellipse.contains(QPointF(0, -9)));
2414     QVERIFY(ellipse.contains(QPointF(0, 0)));
2415     QVERIFY(!ellipse.contains(QPointF(9, 9)));
2416
2417     // Line
2418     QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
2419     QVERIFY(!line.contains(QPointF(-10, 0)));
2420     QVERIFY(!line.contains(QPointF(0, -10)));
2421     QVERIFY(!line.contains(QPointF(10, 0)));
2422     QVERIFY(!line.contains(QPointF(0, 10)));
2423     QVERIFY(line.contains(QPointF(0, 0)));
2424     QVERIFY(line.contains(QPointF(-9, -9)));
2425     QVERIFY(line.contains(QPointF(9, 9)));
2426
2427     // Polygon
2428     QGraphicsPolygonItem polygon(QPolygonF()
2429                                  << QPointF(0, 0)
2430                                  << QPointF(10, 0)
2431                                  << QPointF(0, 10));
2432     QVERIFY(polygon.contains(QPointF(1, 1)));
2433     QVERIFY(polygon.contains(QPointF(4, 4)));
2434     QVERIFY(polygon.contains(QPointF(1, 4)));
2435     QVERIFY(polygon.contains(QPointF(4, 1)));
2436     QVERIFY(!polygon.contains(QPointF(8, 8)));
2437     QVERIFY(polygon.contains(QPointF(1, 8)));
2438     QVERIFY(polygon.contains(QPointF(8, 1)));
2439 }
2440
2441 void tst_QGraphicsItem::collidesWith_item()
2442 {
2443     // Rectangle
2444     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2445     QGraphicsRectItem rect2(QRectF(-10, -10, 20, 20));
2446     QVERIFY(rect.collidesWithItem(&rect2));
2447     QVERIFY(rect2.collidesWithItem(&rect));
2448     rect2.setPos(21, 21);
2449     QVERIFY(!rect.collidesWithItem(&rect2));
2450     QVERIFY(!rect2.collidesWithItem(&rect));
2451     rect2.setPos(-21, -21);
2452     QVERIFY(!rect.collidesWithItem(&rect2));
2453     QVERIFY(!rect2.collidesWithItem(&rect));
2454     rect2.setPos(-17, -17);
2455     QVERIFY(rect.collidesWithItem(&rect2));
2456     QVERIFY(rect2.collidesWithItem(&rect));
2457
2458     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2459     QGraphicsEllipseItem ellipse2(QRectF(-10, -10, 20, 20));
2460     QVERIFY(ellipse.collidesWithItem(&ellipse2));
2461     QVERIFY(ellipse2.collidesWithItem(&ellipse));
2462     ellipse2.setPos(21, 21);
2463     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2464     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2465     ellipse2.setPos(-21, -21);
2466     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2467     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2468
2469     ellipse2.setPos(-17, -17);
2470     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2471     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2472
2473     {
2474         QGraphicsScene scene;
2475         QGraphicsRectItem rect(20, 20, 100, 100, 0, &scene);
2476         QGraphicsRectItem rect2(40, 40, 50, 50, 0, &scene);
2477         rect2.setZValue(1);
2478         QGraphicsLineItem line(0, 0, 200, 200, 0, &scene);
2479         line.setZValue(2);
2480
2481         QCOMPARE(scene.items().size(), 3);
2482
2483         QList<QGraphicsItem *> col1 = rect.collidingItems();
2484         QCOMPARE(col1.size(), 2);
2485         QCOMPARE(col1.first(), static_cast<QGraphicsItem *>(&line));
2486         QCOMPARE(col1.last(), static_cast<QGraphicsItem *>(&rect2));
2487
2488         QList<QGraphicsItem *> col2 = rect2.collidingItems();
2489         QCOMPARE(col2.size(), 2);
2490         QCOMPARE(col2.first(), static_cast<QGraphicsItem *>(&line));
2491         QCOMPARE(col2.last(), static_cast<QGraphicsItem *>(&rect));
2492
2493         QList<QGraphicsItem *> col3 = line.collidingItems();
2494         QCOMPARE(col3.size(), 2);
2495         QCOMPARE(col3.first(), static_cast<QGraphicsItem *>(&rect2));
2496         QCOMPARE(col3.last(), static_cast<QGraphicsItem *>(&rect));
2497     }
2498 }
2499
2500 void tst_QGraphicsItem::collidesWith_path_data()
2501 {
2502     QTest::addColumn<QPointF>("pos");
2503     QTest::addColumn<QMatrix>("matrix");
2504     QTest::addColumn<QPainterPath>("shape");
2505     QTest::addColumn<bool>("rectCollides");
2506     QTest::addColumn<bool>("ellipseCollides");
2507
2508     QTest::newRow("nothing") << QPointF(0, 0) << QMatrix() << QPainterPath() << false << false;
2509
2510     QPainterPath rect;
2511     rect.addRect(0, 0, 20, 20);
2512
2513     QTest::newRow("rect1") << QPointF(0, 0) << QMatrix() << rect << true << true;
2514     QTest::newRow("rect2") << QPointF(0, 0) << QMatrix().translate(21, 21) << rect << false << false;
2515     QTest::newRow("rect3") << QPointF(21, 21) << QMatrix() << rect << false << false;
2516 }
2517
2518 void tst_QGraphicsItem::collidesWith_path()
2519 {
2520     QFETCH(QPointF, pos);
2521     QFETCH(QMatrix, matrix);
2522     QFETCH(QPainterPath, shape);
2523     QFETCH(bool, rectCollides);
2524     QFETCH(bool, ellipseCollides);
2525
2526     QGraphicsRectItem rect(QRectF(0, 0, 20, 20));
2527     QGraphicsEllipseItem ellipse(QRectF(0, 0, 20, 20));
2528
2529     rect.setPos(pos);
2530     rect.setMatrix(matrix);
2531
2532     ellipse.setPos(pos);
2533     ellipse.setMatrix(matrix);
2534
2535     QPainterPath mappedShape = rect.sceneMatrix().inverted().map(shape);
2536
2537     if (rectCollides)
2538         QVERIFY(rect.collidesWithPath(mappedShape));
2539     else
2540         QVERIFY(!rect.collidesWithPath(mappedShape));
2541
2542     if (ellipseCollides)
2543         QVERIFY(ellipse.collidesWithPath(mappedShape));
2544     else
2545         QVERIFY(!ellipse.collidesWithPath(mappedShape));
2546 }
2547
2548 void tst_QGraphicsItem::collidesWithItemWithClip()
2549 {
2550     QGraphicsScene scene;
2551
2552     QGraphicsEllipseItem *ellipse = scene.addEllipse(0, 0, 100, 100);
2553     ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
2554     QGraphicsEllipseItem *ellipse2 = scene.addEllipse(0, 0, 10, 10);
2555     ellipse2->setParentItem(ellipse);
2556     QGraphicsEllipseItem *ellipse3 = scene.addEllipse(0, 0, 10, 10);
2557     ellipse3->setParentItem(ellipse);
2558     QGraphicsEllipseItem *ellipse5 = scene.addEllipse(50, 50, 10, 10);
2559     ellipse5->setParentItem(ellipse);
2560     QGraphicsEllipseItem *ellipse4 = scene.addEllipse(0, 0, 10, 10);
2561
2562     QVERIFY(ellipse2->collidesWithItem(ellipse3));
2563     QVERIFY(ellipse3->collidesWithItem(ellipse2));
2564     QVERIFY(!ellipse2->collidesWithItem(ellipse));
2565     QVERIFY(!ellipse->collidesWithItem(ellipse2));
2566     QVERIFY(!ellipse4->collidesWithItem(ellipse));
2567     QVERIFY(!ellipse4->collidesWithItem(ellipse2));
2568     QVERIFY(!ellipse4->collidesWithItem(ellipse3));
2569     QVERIFY(!ellipse->collidesWithItem(ellipse4));
2570     QVERIFY(!ellipse2->collidesWithItem(ellipse4));
2571     QVERIFY(!ellipse3->collidesWithItem(ellipse4));
2572     QVERIFY(ellipse->collidesWithItem(ellipse5));
2573     QVERIFY(ellipse5->collidesWithItem(ellipse));
2574 }
2575
2576 class MyItem : public QGraphicsEllipseItem
2577 {
2578 public:
2579     bool isObscuredBy(const QGraphicsItem *item) const
2580     {
2581         const MyItem *myItem = qgraphicsitem_cast<const MyItem *>(item);
2582         if (myItem) {
2583             if (item->zValue() > zValue()) {
2584                 QRectF r = rect();
2585                 QPointF topMid = (r.topRight()+r.topLeft())/2;
2586                 QPointF botMid = (r.bottomRight()+r.bottomLeft())/2;
2587                 QPointF leftMid = (r.topLeft()+r.bottomLeft())/2;
2588                 QPointF rightMid = (r.topRight()+r.bottomRight())/2;
2589
2590                 QPainterPath mappedShape = item->mapToItem(this, item->opaqueArea());
2591
2592                 if (mappedShape.contains(topMid) &&
2593                     mappedShape.contains(botMid) &&
2594                     mappedShape.contains(leftMid) &&
2595                     mappedShape.contains(rightMid))
2596                     return true;
2597                 else
2598                     return false;
2599             }
2600             else return false;
2601         }
2602         else
2603             return QGraphicsItem::isObscuredBy(item);
2604     }
2605
2606     QPainterPath opaqueArea() const
2607     {
2608         return shape();
2609     }
2610
2611     enum {
2612         Type = UserType+1
2613     };
2614     int type() const { return Type; }
2615 };
2616
2617 void tst_QGraphicsItem::isObscuredBy()
2618 {
2619     QGraphicsScene scene;
2620
2621     MyItem myitem1, myitem2;
2622
2623     myitem1.setRect(QRectF(50, 50, 40, 200));
2624     myitem1.rotate(67);
2625
2626     myitem2.setRect(QRectF(25, 25, 20, 20));
2627     myitem2.setZValue(-1.0);
2628     scene.addItem(&myitem1);
2629     scene.addItem(&myitem2);
2630
2631     QVERIFY(!myitem2.isObscuredBy(&myitem1));
2632     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2633
2634     myitem2.setRect(QRectF(-50, 85, 20, 20));
2635     QVERIFY(myitem2.isObscuredBy(&myitem1));
2636     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2637
2638     myitem2.setRect(QRectF(-30, 70, 20, 20));
2639     QVERIFY(!myitem2.isObscuredBy(&myitem1));
2640     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2641
2642     QGraphicsRectItem rect1, rect2;
2643
2644     rect1.setRect(QRectF(-40, -40, 50, 50));
2645     rect1.setBrush(QBrush(Qt::red));
2646     rect2.setRect(QRectF(-30, -20, 20, 20));
2647     rect2.setZValue(-1.0);
2648     rect2.setBrush(QBrush(Qt::blue));
2649
2650     QVERIFY(rect2.isObscuredBy(&rect1));
2651     QVERIFY(!rect1.isObscuredBy(&rect2));
2652
2653     rect2.setPos(QPointF(-20, -25));
2654
2655     QVERIFY(!rect2.isObscuredBy(&rect1));
2656     QVERIFY(!rect1.isObscuredBy(&rect2));
2657
2658     rect2.setPos(QPointF(-100, -100));
2659
2660     QVERIFY(!rect2.isObscuredBy(&rect1));
2661     QVERIFY(!rect1.isObscuredBy(&rect2));
2662 }
2663
2664 class OpaqueItem : public QGraphicsRectItem
2665 {
2666 protected:
2667     QPainterPath opaqueArea() const
2668     {
2669         return shape();
2670     }
2671 };
2672
2673 void tst_QGraphicsItem::isObscured()
2674 {
2675     if (sizeof(qreal) != sizeof(double))
2676         QSKIP("Skipped due to rounding errors");
2677
2678     OpaqueItem *item1 = new OpaqueItem;
2679     item1->setRect(0, 0, 100, 100);
2680     item1->setZValue(0);
2681
2682     OpaqueItem *item2 = new OpaqueItem;
2683     item2->setZValue(1);
2684     item2->setRect(0, 0, 100, 100);
2685
2686     QGraphicsScene scene;
2687     scene.addItem(item1);
2688     scene.addItem(item2);
2689
2690     QVERIFY(item1->isObscured());
2691     QVERIFY(item1->isObscuredBy(item2));
2692     QVERIFY(item1->isObscured(QRectF(0, 0, 50, 50)));
2693     QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
2694     QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
2695     QVERIFY(item1->isObscured(QRectF(0, 50, 50, 50)));
2696     QVERIFY(item1->isObscured(0, 0, 50, 50));
2697     QVERIFY(item1->isObscured(50, 0, 50, 50));
2698     QVERIFY(item1->isObscured(50, 50, 50, 50));
2699     QVERIFY(item1->isObscured(0, 50, 50, 50));
2700     QVERIFY(!item2->isObscured());
2701     QVERIFY(!item2->isObscuredBy(item1));
2702     QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
2703     QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
2704     QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
2705     QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
2706     QVERIFY(!item2->isObscured(0, 0, 50, 50));
2707     QVERIFY(!item2->isObscured(50, 0, 50, 50));
2708     QVERIFY(!item2->isObscured(50, 50, 50, 50));
2709     QVERIFY(!item2->isObscured(0, 50, 50, 50));
2710
2711     item2->moveBy(50, 0);
2712
2713     QVERIFY(!item1->isObscured());
2714     QVERIFY(!item1->isObscuredBy(item2));
2715     QVERIFY(!item1->isObscured(QRectF(0, 0, 50, 50)));
2716     QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
2717     QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
2718     QVERIFY(!item1->isObscured(QRectF(0, 50, 50, 50)));
2719     QVERIFY(!item1->isObscured(0, 0, 50, 50));
2720     QVERIFY(item1->isObscured(50, 0, 50, 50));
2721     QVERIFY(item1->isObscured(50, 50, 50, 50));
2722     QVERIFY(!item1->isObscured(0, 50, 50, 50));
2723     QVERIFY(!item2->isObscured());
2724     QVERIFY(!item2->isObscuredBy(item1));
2725     QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
2726     QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
2727     QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
2728     QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
2729     QVERIFY(!item2->isObscured(0, 0, 50, 50));
2730     QVERIFY(!item2->isObscured(50, 0, 50, 50));
2731     QVERIFY(!item2->isObscured(50, 50, 50, 50));
2732     QVERIFY(!item2->isObscured(0, 50, 50, 50));
2733 }
2734
2735 void tst_QGraphicsItem::mapFromToParent()
2736 {
2737     QPainterPath path1;
2738     path1.addRect(0, 0, 200, 200);
2739
2740     QPainterPath path2;
2741     path2.addRect(0, 0, 100, 100);
2742
2743     QPainterPath path3;
2744     path3.addRect(0, 0, 50, 50);
2745
2746     QPainterPath path4;
2747     path4.addRect(0, 0, 25, 25);
2748
2749     QGraphicsItem *item1 = new QGraphicsPathItem(path1);
2750     QGraphicsItem *item2 = new QGraphicsPathItem(path2, item1);
2751     QGraphicsItem *item3 = new QGraphicsPathItem(path3, item2);
2752     QGraphicsItem *item4 = new QGraphicsPathItem(path4, item3);
2753
2754     item1->setPos(10, 10);
2755     item2->setPos(10, 10);
2756     item3->setPos(10, 10);
2757     item4->setPos(10, 10);
2758
2759     for (int i = 0; i < 4; ++i) {
2760         QMatrix matrix;
2761         matrix.rotate(i * 90);
2762         matrix.translate(i * 100, -i * 100);
2763         matrix.scale(2, 4);
2764         item1->setMatrix(matrix);
2765
2766         QCOMPARE(item1->mapToParent(QPointF(0, 0)), item1->pos() + matrix.map(QPointF(0, 0)));
2767         QCOMPARE(item2->mapToParent(QPointF(0, 0)), item2->pos());
2768         QCOMPARE(item3->mapToParent(QPointF(0, 0)), item3->pos());
2769         QCOMPARE(item4->mapToParent(QPointF(0, 0)), item4->pos());
2770         QCOMPARE(item1->mapToParent(QPointF(10, -10)), item1->pos() + matrix.map(QPointF(10, -10)));
2771         QCOMPARE(item2->mapToParent(QPointF(10, -10)), item2->pos() + QPointF(10, -10));
2772         QCOMPARE(item3->mapToParent(QPointF(10, -10)), item3->pos() + QPointF(10, -10));
2773         QCOMPARE(item4->mapToParent(QPointF(10, -10)), item4->pos() + QPointF(10, -10));
2774         QCOMPARE(item1->mapToParent(QPointF(-10, 10)), item1->pos() + matrix.map(QPointF(-10, 10)));
2775         QCOMPARE(item2->mapToParent(QPointF(-10, 10)), item2->pos() + QPointF(-10, 10));
2776         QCOMPARE(item3->mapToParent(QPointF(-10, 10)), item3->pos() + QPointF(-10, 10));
2777         QCOMPARE(item4->mapToParent(QPointF(-10, 10)), item4->pos() + QPointF(-10, 10));
2778         QCOMPARE(item1->mapFromParent(item1->pos()), matrix.inverted().map(QPointF(0, 0)));
2779         QCOMPARE(item2->mapFromParent(item2->pos()), QPointF(0, 0));
2780         QCOMPARE(item3->mapFromParent(item3->pos()), QPointF(0, 0));
2781         QCOMPARE(item4->mapFromParent(item4->pos()), QPointF(0, 0));
2782         QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(10, -10)),
2783                  matrix.inverted().map(QPointF(10, -10)));
2784         QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(10, -10)), QPointF(10, -10));
2785         QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(10, -10)), QPointF(10, -10));
2786         QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(10, -10)), QPointF(10, -10));
2787         QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(-10, 10)),
2788                  matrix.inverted().map(QPointF(-10, 10)));
2789         QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2790         QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2791         QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2792     }
2793
2794     delete item1;
2795 }
2796
2797 void tst_QGraphicsItem::mapFromToScene()
2798 {
2799     QGraphicsItem *item1 = new QGraphicsPathItem(QPainterPath());
2800     QGraphicsItem *item2 = new QGraphicsPathItem(QPainterPath(), item1);
2801     QGraphicsItem *item3 = new QGraphicsPathItem(QPainterPath(), item2);
2802     QGraphicsItem *item4 = new QGraphicsPathItem(QPainterPath(), item3);
2803
2804     item1->setPos(100, 100);
2805     item2->setPos(100, 100);
2806     item3->setPos(100, 100);
2807     item4->setPos(100, 100);
2808     QCOMPARE(item1->pos(), QPointF(100, 100));
2809     QCOMPARE(item2->pos(), QPointF(100, 100));
2810     QCOMPARE(item3->pos(), QPointF(100, 100));
2811     QCOMPARE(item4->pos(), QPointF(100, 100));
2812     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2813     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2814     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2815     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2816     QCOMPARE(item1->mapToParent(10, 10), QPointF(110, 110));
2817     QCOMPARE(item2->mapToParent(10, 10), QPointF(110, 110));
2818     QCOMPARE(item3->mapToParent(10, 10), QPointF(110, 110));
2819     QCOMPARE(item4->mapToParent(10, 10), QPointF(110, 110));
2820     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2821     QCOMPARE(item2->mapToScene(0, 0), QPointF(200, 200));
2822     QCOMPARE(item3->mapToScene(0, 0), QPointF(300, 300));
2823     QCOMPARE(item4->mapToScene(0, 0), QPointF(400, 400));
2824     QCOMPARE(item1->mapToScene(10, 0), QPointF(110, 100));
2825     QCOMPARE(item2->mapToScene(10, 0), QPointF(210, 200));
2826     QCOMPARE(item3->mapToScene(10, 0), QPointF(310, 300));
2827     QCOMPARE(item4->mapToScene(10, 0), QPointF(410, 400));
2828     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2829     QCOMPARE(item2->mapFromScene(200, 200), QPointF(0, 0));
2830     QCOMPARE(item3->mapFromScene(300, 300), QPointF(0, 0));
2831     QCOMPARE(item4->mapFromScene(400, 400), QPointF(0, 0));
2832     QCOMPARE(item1->mapFromScene(110, 100), QPointF(10, 0));
2833     QCOMPARE(item2->mapFromScene(210, 200), QPointF(10, 0));
2834     QCOMPARE(item3->mapFromScene(310, 300), QPointF(10, 0));
2835     QCOMPARE(item4->mapFromScene(410, 400), QPointF(10, 0));
2836
2837     // Rotate item1 90 degrees clockwise
2838     QMatrix matrix; matrix.rotate(90);
2839     item1->setMatrix(matrix);
2840     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2841     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2842     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2843     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2844     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2845     QCOMPARE(item2->mapToParent(10, 0), QPointF(110, 100));
2846     QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
2847     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2848     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2849     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2850     QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 300));
2851     QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 400));
2852     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2853     QCOMPARE(item2->mapToScene(10, 0), QPointF(0, 210));
2854     QCOMPARE(item3->mapToScene(10, 0), QPointF(-100, 310));
2855     QCOMPARE(item4->mapToScene(10, 0), QPointF(-200, 410));
2856     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2857     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2858     QCOMPARE(item3->mapFromScene(-100, 300), QPointF(0, 0));
2859     QCOMPARE(item4->mapFromScene(-200, 400), QPointF(0, 0));
2860     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2861     QCOMPARE(item2->mapFromScene(0, 210), QPointF(10, 0));
2862     QCOMPARE(item3->mapFromScene(-100, 310), QPointF(10, 0));
2863     QCOMPARE(item4->mapFromScene(-200, 410), QPointF(10, 0));
2864
2865     // Rotate item2 90 degrees clockwise
2866     item2->setMatrix(matrix);
2867     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2868     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2869     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2870     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2871     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2872     QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
2873     QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
2874     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2875     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2876     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2877     QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 100));
2878     QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 0));
2879     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2880     QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
2881     QCOMPARE(item3->mapToScene(10, 0), QPointF(-110, 100));
2882     QCOMPARE(item4->mapToScene(10, 0), QPointF(-210, 0));
2883     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2884     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2885     QCOMPARE(item3->mapFromScene(-100, 100), QPointF(0, 0));
2886     QCOMPARE(item4->mapFromScene(-200, 0), QPointF(0, 0));
2887     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2888     QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
2889     QCOMPARE(item3->mapFromScene(-110, 100), QPointF(10, 0));
2890     QCOMPARE(item4->mapFromScene(-210, 0), QPointF(10, 0));
2891
2892     // Translate item3 50 points, then rotate 90 degrees counterclockwise
2893     QMatrix matrix2;
2894     matrix2.translate(50, 0);
2895     matrix2.rotate(-90);
2896     item3->setMatrix(matrix2);
2897     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2898     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2899     QCOMPARE(item3->pos(), item3->mapToParent(0, 0) - QPointF(50, 0));
2900     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2901     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2902     QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
2903     QCOMPARE(item3->mapToParent(10, 0), QPointF(150, 90));
2904     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2905     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2906     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2907     QCOMPARE(item3->mapToScene(0, 0), QPointF(-150, 100));
2908     QCOMPARE(item4->mapToScene(0, 0), QPointF(-250, 200));
2909     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2910     QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
2911     QCOMPARE(item3->mapToScene(10, 0), QPointF(-150, 110));
2912     QCOMPARE(item4->mapToScene(10, 0), QPointF(-250, 210));
2913     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2914     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2915     QCOMPARE(item3->mapFromScene(-150, 100), QPointF(0, 0));
2916     QCOMPARE(item4->mapFromScene(-250, 200), QPointF(0, 0));
2917     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2918     QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
2919     QCOMPARE(item3->mapFromScene(-150, 110), QPointF(10, 0));
2920     QCOMPARE(item4->mapFromScene(-250, 210), QPointF(10, 0));
2921
2922     delete item1;
2923 }
2924
2925 void tst_QGraphicsItem::mapFromToItem()
2926 {
2927     QGraphicsItem *item1 = new QGraphicsPathItem;
2928     QGraphicsItem *item2 = new QGraphicsPathItem;
2929     QGraphicsItem *item3 = new QGraphicsPathItem;
2930     QGraphicsItem *item4 = new QGraphicsPathItem;
2931
2932     item1->setPos(-100, -100);
2933     item2->setPos(100, -100);
2934     item3->setPos(100, 100);
2935     item4->setPos(-100, 100);
2936
2937     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(200, 0));
2938     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200));
2939     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0));
2940     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(0, -200));
2941     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(0, 200));
2942     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-200, 0));
2943     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
2944     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
2945
2946     QMatrix matrix;
2947     matrix.translate(100, 100);
2948     item1->setMatrix(matrix);
2949
2950     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(100, -100));
2951     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200));
2952     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0));
2953     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(100, -100));
2954     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(-100, 100));
2955     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-100, 100));
2956     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
2957     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
2958
2959     matrix.rotate(90);
2960     item1->setMatrix(matrix);
2961     item2->setMatrix(matrix);
2962     item3->setMatrix(matrix);
2963     item4->setMatrix(matrix);
2964
2965     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(0, -200));
2966     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(200, 0));
2967     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(0, 200));
2968     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(-200, 0));
2969     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(200, 0));
2970     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(0, 200));
2971     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(-200, 0));
2972     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(0, -200));
2973     QCOMPARE(item1->mapFromItem(item2, 10, -5), QPointF(10, -205));
2974     QCOMPARE(item2->mapFromItem(item3, 10, -5), QPointF(210, -5));
2975     QCOMPARE(item3->mapFromItem(item4, 10, -5), QPointF(10, 195));
2976     QCOMPARE(item4->mapFromItem(item1, 10, -5), QPointF(-190, -5));
2977     QCOMPARE(item1->mapFromItem(item4, 10, -5), QPointF(210, -5));
2978     QCOMPARE(item2->mapFromItem(item1, 10, -5), QPointF(10, 195));
2979     QCOMPARE(item3->mapFromItem(item2, 10, -5), QPointF(-190, -5));
2980     QCOMPARE(item4->mapFromItem(item3, 10, -5), QPointF(10, -205));
2981
2982     QCOMPARE(item1->mapFromItem(0, 10, -5), item1->mapFromScene(10, -5));
2983     QCOMPARE(item2->mapFromItem(0, 10, -5), item2->mapFromScene(10, -5));
2984     QCOMPARE(item3->mapFromItem(0, 10, -5), item3->mapFromScene(10, -5));
2985     QCOMPARE(item4->mapFromItem(0, 10, -5), item4->mapFromScene(10, -5));
2986     QCOMPARE(item1->mapToItem(0, 10, -5), item1->mapToScene(10, -5));
2987     QCOMPARE(item2->mapToItem(0, 10, -5), item2->mapToScene(10, -5));
2988     QCOMPARE(item3->mapToItem(0, 10, -5), item3->mapToScene(10, -5));
2989     QCOMPARE(item4->mapToItem(0, 10, -5), item4->mapToScene(10, -5));
2990
2991     delete item1;
2992     delete item2;
2993     delete item3;
2994     delete item4;
2995 }
2996
2997 void tst_QGraphicsItem::mapRectFromToParent_data()
2998 {
2999     QTest::addColumn<bool>("parent");
3000     QTest::addColumn<QPointF>("parentPos");
3001     QTest::addColumn<QTransform>("parentTransform");
3002     QTest::addColumn<QPointF>("pos");
3003     QTest::addColumn<QTransform>("transform");
3004     QTest::addColumn<QRectF>("inputRect");
3005     QTest::addColumn<QRectF>("outputRect");
3006
3007     QTest::newRow("nil") << false << QPointF() << QTransform() << QPointF() << QTransform() << QRectF() << QRectF();
3008     QTest::newRow("simple") << false << QPointF() << QTransform() << QPointF() << QTransform()
3009                             << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3010     QTest::newRow("simple w/parent") << true
3011                                      << QPointF() << QTransform()
3012                                      << QPointF() << QTransform()
3013                                      << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3014     QTest::newRow("simple w/parent parentPos") << true
3015                                                << QPointF(50, 50) << QTransform()
3016                                                << QPointF() << QTransform()
3017                                                << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3018     QTest::newRow("simple w/parent parentPos parentRotation") << true
3019                                                               << QPointF(50, 50) << QTransform().rotate(45)
3020                                                               << QPointF() << QTransform()
3021                                                               << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3022     QTest::newRow("pos w/parent") << true
3023                                   << QPointF() << QTransform()
3024                                   << QPointF(50, 50) << QTransform()
3025                                   << QRectF(0, 0, 10, 10) << QRectF(50, 50, 10, 10);
3026     QTest::newRow("rotation w/parent") << true
3027                                        << QPointF() << QTransform()
3028                                        << QPointF() << QTransform().rotate(90)
3029                                        << QRectF(0, 0, 10, 10) << QRectF(-10, 0, 10, 10);
3030     QTest::newRow("pos rotation w/parent") << true
3031                                            << QPointF() << QTransform()
3032                                            << QPointF(50, 50) << QTransform().rotate(90)
3033                                            << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
3034     QTest::newRow("pos rotation w/parent parentPos parentRotation") << true
3035                                                                     << QPointF(-170, -190) << QTransform().rotate(90)
3036                                                                     << QPointF(50, 50) << QTransform().rotate(90)
3037                                                                     << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
3038 }
3039
3040 void tst_QGraphicsItem::mapRectFromToParent()
3041 {
3042     QFETCH(bool, parent);
3043     QFETCH(QPointF, parentPos);
3044     QFETCH(QTransform, parentTransform);
3045     QFETCH(QPointF, pos);
3046     QFETCH(QTransform, transform);
3047     QFETCH(QRectF, inputRect);
3048     QFETCH(QRectF, outputRect);
3049
3050     QGraphicsRectItem *rect = new QGraphicsRectItem;
3051     rect->setPos(pos);
3052     rect->setTransform(transform);
3053
3054     if (parent) {
3055         QGraphicsRectItem *rectParent = new QGraphicsRectItem;
3056         rect->setParentItem(rectParent);
3057         rectParent->setPos(parentPos);
3058         rectParent->setTransform(parentTransform);
3059     }
3060
3061     // Make sure we use non-destructive transform operations (e.g., 90 degree
3062     // rotations).
3063     QCOMPARE(rect->mapRectToParent(inputRect), outputRect);
3064     QCOMPARE(rect->mapRectFromParent(outputRect), inputRect);
3065     QCOMPARE(rect->itemTransform(rect->parentItem()).mapRect(inputRect), outputRect);
3066     QCOMPARE(rect->mapToParent(inputRect).boundingRect(), outputRect);
3067     QCOMPARE(rect->mapToParent(QPolygonF(inputRect)).boundingRect(), outputRect);
3068     QCOMPARE(rect->mapFromParent(outputRect).boundingRect(), inputRect);
3069     QCOMPARE(rect->mapFromParent(QPolygonF(outputRect)).boundingRect(), inputRect);
3070     QPainterPath inputPath;
3071     inputPath.addRect(inputRect);
3072     QPainterPath outputPath;
3073     outputPath.addRect(outputRect);
3074     QCOMPARE(rect->mapToParent(inputPath).boundingRect(), outputPath.boundingRect());
3075     QCOMPARE(rect->mapFromParent(outputPath).boundingRect(), inputPath.boundingRect());
3076 }
3077
3078 void tst_QGraphicsItem::isAncestorOf()
3079 {
3080     QGraphicsItem *grandPa = new QGraphicsRectItem;
3081     QGraphicsItem *parent = new QGraphicsRectItem;
3082     QGraphicsItem *child = new QGraphicsRectItem;
3083
3084     QVERIFY(!parent->isAncestorOf(0));
3085     QVERIFY(!child->isAncestorOf(0));
3086     QVERIFY(!parent->isAncestorOf(child));
3087     QVERIFY(!child->isAncestorOf(parent));
3088     QVERIFY(!parent->isAncestorOf(parent));
3089
3090     child->setParentItem(parent);
3091     parent->setParentItem(grandPa);
3092
3093     QVERIFY(parent->isAncestorOf(child));
3094     QVERIFY(grandPa->isAncestorOf(parent));
3095     QVERIFY(grandPa->isAncestorOf(child));
3096     QVERIFY(!child->isAncestorOf(parent));
3097     QVERIFY(!parent->isAncestorOf(grandPa));
3098     QVERIFY(!child->isAncestorOf(grandPa));
3099     QVERIFY(!child->isAncestorOf(child));
3100     QVERIFY(!parent->isAncestorOf(parent));
3101     QVERIFY(!grandPa->isAncestorOf(grandPa));
3102
3103     parent->setParentItem(0);
3104
3105     delete child;
3106     delete parent;
3107     delete grandPa;
3108 }
3109
3110 void tst_QGraphicsItem::commonAncestorItem()
3111 {
3112     QGraphicsItem *ancestor = new QGraphicsRectItem;
3113     QGraphicsItem *grandMa = new QGraphicsRectItem;
3114     QGraphicsItem *grandPa = new QGraphicsRectItem;
3115     QGraphicsItem *brotherInLaw = new QGraphicsRectItem;
3116     QGraphicsItem *cousin = new QGraphicsRectItem;
3117     QGraphicsItem *husband = new QGraphicsRectItem;
3118     QGraphicsItem *child = new QGraphicsRectItem;
3119     QGraphicsItem *wife = new QGraphicsRectItem;
3120
3121     child->setParentItem(husband);
3122     husband->setParentItem(grandPa);
3123     brotherInLaw->setParentItem(grandPa);
3124     cousin->setParentItem(brotherInLaw);
3125     wife->setParentItem(grandMa);
3126     grandMa->setParentItem(ancestor);
3127     grandPa->setParentItem(ancestor);
3128
3129     QCOMPARE(grandMa->commonAncestorItem(grandMa), grandMa);
3130     QCOMPARE(grandMa->commonAncestorItem(0), (QGraphicsItem *)0);
3131     QCOMPARE(grandMa->commonAncestorItem(grandPa), ancestor);
3132     QCOMPARE(grandPa->commonAncestorItem(grandMa), ancestor);
3133     QCOMPARE(grandPa->commonAncestorItem(husband), grandPa);
3134     QCOMPARE(grandPa->commonAncestorItem(wife), ancestor);
3135     QCOMPARE(grandMa->commonAncestorItem(husband), ancestor);
3136     QCOMPARE(grandMa->commonAncestorItem(wife), grandMa);
3137     QCOMPARE(wife->commonAncestorItem(grandMa), grandMa);
3138     QCOMPARE(child->commonAncestorItem(cousin), grandPa);
3139     QCOMPARE(cousin->commonAncestorItem(child), grandPa);
3140     QCOMPARE(wife->commonAncestorItem(child), ancestor);
3141     QCOMPARE(child->commonAncestorItem(wife), ancestor);
3142 }
3143
3144 void tst_QGraphicsItem::data()
3145 {
3146     QGraphicsTextItem text;
3147
3148     QCOMPARE(text.data(0), QVariant());
3149     text.setData(0, "TextItem");
3150     QCOMPARE(text.data(0), QVariant(QString("TextItem")));
3151     text.setData(0, QVariant());
3152     QCOMPARE(text.data(0), QVariant());
3153 }
3154
3155 void tst_QGraphicsItem::type()
3156 {
3157     QCOMPARE(int(QGraphicsItem::Type), 1);
3158     QCOMPARE(int(QGraphicsPathItem::Type), 2);
3159     QCOMPARE(int(QGraphicsRectItem::Type), 3);
3160     QCOMPARE(int(QGraphicsEllipseItem::Type), 4);
3161     QCOMPARE(int(QGraphicsPolygonItem::Type), 5);
3162     QCOMPARE(int(QGraphicsLineItem::Type), 6);
3163     QCOMPARE(int(QGraphicsPixmapItem::Type), 7);
3164     QCOMPARE(int(QGraphicsTextItem::Type), 8);
3165
3166     QCOMPARE(QGraphicsPathItem().type(), 2);
3167     QCOMPARE(QGraphicsRectItem().type(), 3);
3168     QCOMPARE(QGraphicsEllipseItem().type(), 4);
3169     QCOMPARE(QGraphicsPolygonItem().type(), 5);
3170     QCOMPARE(QGraphicsLineItem().type(), 6);
3171     QCOMPARE(QGraphicsPixmapItem().type(), 7);
3172     QCOMPARE(QGraphicsTextItem().type(), 8);
3173 }
3174
3175 void tst_QGraphicsItem::graphicsitem_cast()
3176 {
3177     QGraphicsPathItem pathItem;
3178     const QGraphicsPathItem *pPathItem = &pathItem;
3179     QGraphicsRectItem rectItem;
3180     const QGraphicsRectItem *pRectItem = &rectItem;
3181     QGraphicsEllipseItem ellipseItem;
3182     const QGraphicsEllipseItem *pEllipseItem = &ellipseItem;
3183     QGraphicsPolygonItem polygonItem;
3184     const QGraphicsPolygonItem *pPolygonItem = &polygonItem;
3185     QGraphicsLineItem lineItem;
3186     const QGraphicsLineItem *pLineItem = &lineItem;
3187     QGraphicsPixmapItem pixmapItem;
3188     const QGraphicsPixmapItem *pPixmapItem = &pixmapItem;
3189     QGraphicsTextItem textItem;
3190     const QGraphicsTextItem *pTextItem = &textItem;
3191
3192     QVERIFY(qgraphicsitem_cast<QGraphicsPathItem *>(&pathItem));
3193     //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&pathItem));
3194     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pathItem));
3195     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPathItem));
3196     QVERIFY(qgraphicsitem_cast<const QGraphicsPathItem *>(pPathItem));
3197
3198     QVERIFY(qgraphicsitem_cast<QGraphicsRectItem *>(&rectItem));
3199     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&rectItem));
3200     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pRectItem));
3201     QVERIFY(qgraphicsitem_cast<const QGraphicsRectItem *>(pRectItem));
3202
3203     QVERIFY(qgraphicsitem_cast<QGraphicsEllipseItem *>(&ellipseItem));
3204     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&ellipseItem));
3205     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pEllipseItem));
3206     QVERIFY(qgraphicsitem_cast<const QGraphicsEllipseItem *>(pEllipseItem));
3207
3208     QVERIFY(qgraphicsitem_cast<QGraphicsPolygonItem *>(&polygonItem));
3209     //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&polygonItem));
3210     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&polygonItem));
3211     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPolygonItem));
3212     QVERIFY(qgraphicsitem_cast<const QGraphicsPolygonItem *>(pPolygonItem));
3213
3214     QVERIFY(qgraphicsitem_cast<QGraphicsLineItem *>(&lineItem));
3215     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&lineItem));
3216     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pLineItem));
3217     QVERIFY(qgraphicsitem_cast<const QGraphicsLineItem *>(pLineItem));
3218
3219     QVERIFY(qgraphicsitem_cast<QGraphicsPixmapItem *>(&pixmapItem));
3220     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pixmapItem));
3221     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPixmapItem));
3222     QVERIFY(qgraphicsitem_cast<const QGraphicsPixmapItem *>(pPixmapItem));
3223
3224     QVERIFY(qgraphicsitem_cast<QGraphicsTextItem *>(&textItem));
3225     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&textItem));
3226     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pTextItem));
3227     QVERIFY(qgraphicsitem_cast<const QGraphicsTextItem *>(pTextItem));
3228
3229     // and some casts that _should_ fail:
3230     QVERIFY(!qgraphicsitem_cast<QGraphicsEllipseItem *>(&pathItem));
3231     QVERIFY(!qgraphicsitem_cast<const QGraphicsTextItem *>(pPolygonItem));
3232
3233     // and this shouldn't crash
3234     QGraphicsItem *ptr = 0;
3235     QVERIFY(!qgraphicsitem_cast<QGraphicsTextItem *>(ptr));
3236     QVERIFY(!qgraphicsitem_cast<QGraphicsItem *>(ptr));
3237 }
3238
3239 void tst_QGraphicsItem::hoverEventsGenerateRepaints()
3240 {
3241     Q_CHECK_PAINTEVENTS
3242
3243     QGraphicsScene scene;
3244     QGraphicsView view(&scene);
3245     view.show();
3246     QTest::qWaitForWindowShown(&view);
3247     QTest::qWait(150);
3248
3249     EventTester *tester = new EventTester;
3250     scene.addItem(tester);
3251     tester->setAcceptsHoverEvents(true);
3252
3253     QTRY_COMPARE(tester->repaints, 1);
3254
3255     // Send a hover enter event
3256     QGraphicsSceneHoverEvent hoverEnterEvent(QEvent::GraphicsSceneHoverEnter);
3257     hoverEnterEvent.setScenePos(QPointF(0, 0));
3258     hoverEnterEvent.setPos(QPointF(0, 0));
3259     QApplication::sendEvent(&scene, &hoverEnterEvent);
3260
3261     // Check that we get a repaint
3262     int npaints = tester->repaints;
3263     qApp->processEvents();
3264     qApp->processEvents();
3265     QCOMPARE(tester->events.size(), 2); //  enter + move
3266     QCOMPARE(tester->repaints, npaints + 1);
3267     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
3268
3269     // Send a hover move event
3270     QGraphicsSceneHoverEvent hoverMoveEvent(QEvent::GraphicsSceneHoverMove);
3271     hoverMoveEvent.setScenePos(QPointF(0, 0));
3272     hoverMoveEvent.setPos(QPointF(0, 0));
3273     QApplication::sendEvent(&scene, &hoverMoveEvent);
3274
3275     // Check that we don't get a repaint
3276     qApp->processEvents();
3277     qApp->processEvents();
3278
3279     QCOMPARE(tester->events.size(), 3);
3280     QCOMPARE(tester->repaints, npaints + 1);
3281     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
3282
3283     // Send a hover leave event
3284     QGraphicsSceneHoverEvent hoverLeaveEvent(QEvent::GraphicsSceneHoverLeave);
3285     hoverLeaveEvent.setScenePos(QPointF(-100, -100));
3286     hoverLeaveEvent.setPos(QPointF(0, 0));
3287     QApplication::sendEvent(&scene, &hoverLeaveEvent);
3288
3289     // Check that we get a repaint
3290     qApp->processEvents();
3291     qApp->processEvents();
3292
3293     QCOMPARE(tester->events.size(), 4);
3294     QCOMPARE(tester->repaints, npaints + 2);
3295     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverLeave);
3296 }
3297
3298 void tst_QGraphicsItem::boundingRects_data()
3299 {
3300     QTest::addColumn<QGraphicsItem *>("item");
3301     QTest::addColumn<QRectF>("boundingRect");
3302
3303     QRectF rect(0, 0, 100, 100);
3304     QPainterPath path;
3305     path.addRect(rect);
3306
3307     QRectF adjustedRect(-0.5, -0.5, 101, 101);
3308
3309     QTest::newRow("path") << (QGraphicsItem *)new QGraphicsPathItem(path) << adjustedRect;
3310     QTest::newRow("rect") << (QGraphicsItem *)new QGraphicsRectItem(rect) << adjustedRect;
3311     QTest::newRow("ellipse") << (QGraphicsItem *)new QGraphicsEllipseItem(rect) << adjustedRect;
3312     QTest::newRow("polygon") << (QGraphicsItem *)new QGraphicsPolygonItem(rect) << adjustedRect;
3313 }
3314
3315 void tst_QGraphicsItem::boundingRects()
3316 {
3317     QFETCH(QGraphicsItem *, item);
3318     QFETCH(QRectF, boundingRect);
3319
3320     ((QAbstractGraphicsShapeItem *)item)->setPen(QPen(Qt::black, 1));
3321     QCOMPARE(item->boundingRect(), boundingRect);
3322 }
3323
3324 void tst_QGraphicsItem::boundingRects2()
3325 {
3326     QGraphicsPixmapItem pixmap(QPixmap::fromImage(QImage(100, 100, QImage::Format_ARGB32_Premultiplied)));
3327     QCOMPARE(pixmap.boundingRect(), QRectF(0, 0, 100, 100));
3328
3329     QGraphicsLineItem line(0, 0, 100, 0);
3330     line.setPen(QPen(Qt::black, 1));
3331     QCOMPARE(line.boundingRect(), QRectF(-0.5, -0.5, 101, 1));
3332 }
3333
3334 void tst_QGraphicsItem::sceneBoundingRect()
3335 {
3336     QGraphicsScene scene;
3337     QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3338     item->setPos(100, 100);
3339
3340     QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
3341     QCOMPARE(item->sceneBoundingRect(), QRectF(100, 100, 100, 100));
3342
3343     item->rotate(90);
3344
3345     QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
3346     QCOMPARE(item->sceneBoundingRect(), QRectF(0, 100, 100, 100));
3347 }
3348
3349 void tst_QGraphicsItem::childrenBoundingRect()
3350 {
3351     QGraphicsScene scene;
3352     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3353     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3354     child->setParentItem(parent);
3355     parent->setPos(100, 100);
3356     child->setPos(100, 100);
3357
3358     QCOMPARE(parent->boundingRect(), QRectF(0, 0, 100, 100));
3359     QCOMPARE(child->boundingRect(), QRectF(0, 0, 100, 100));
3360     QCOMPARE(child->childrenBoundingRect(), QRectF());
3361     QCOMPARE(parent->childrenBoundingRect(), QRectF(100, 100, 100, 100));
3362
3363     QGraphicsRectItem *child2 = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3364     child2->setParentItem(parent);
3365     child2->setPos(-100, -100);
3366     QCOMPARE(parent->childrenBoundingRect(), QRectF(-100, -100, 300, 300));
3367
3368     QGraphicsRectItem *childChild = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3369     childChild->setParentItem(child);
3370     childChild->setPos(500, 500);
3371     child->rotate(90);
3372
3373     scene.addPolygon(parent->mapToScene(parent->boundingRect() | parent->childrenBoundingRect()))->setPen(QPen(Qt::red));;
3374
3375     QGraphicsView view(&scene);
3376     view.show();
3377
3378     QTest::qWaitForWindowShown(&view);
3379     QTest::qWait(30);
3380
3381     QCOMPARE(parent->childrenBoundingRect(), QRectF(-500, -100, 600, 800));
3382 }
3383
3384 void tst_QGraphicsItem::childrenBoundingRectTransformed()
3385 {
3386     QGraphicsScene scene;
3387
3388     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
3389     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
3390     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
3391     QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
3392     QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
3393     rect2->setParentItem(rect);
3394     rect3->setParentItem(rect2);
3395     rect4->setParentItem(rect3);
3396     rect5->setParentItem(rect4);
3397
3398     rect2->setTransform(QTransform().translate(50, 50).rotate(45));
3399     rect2->setPos(25, 25);
3400     rect3->setTransform(QTransform().translate(50, 50).rotate(45));
3401     rect3->setPos(25, 25);
3402     rect4->setTransform(QTransform().translate(50, 50).rotate(45));
3403     rect4->setPos(25, 25);
3404     rect5->setTransform(QTransform().translate(50, 50).rotate(45));
3405     rect5->setPos(25, 25);
3406
3407     QRectF subTreeRect = rect->childrenBoundingRect();
3408     QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
3409     QCOMPARE(subTreeRect.top(), qreal(75.0));
3410     QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
3411     QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
3412
3413     rect->rotate(45);
3414     rect2->rotate(-45);
3415     rect3->rotate(45);
3416     rect4->rotate(-45);
3417     rect5->rotate(45);
3418
3419     subTreeRect = rect->childrenBoundingRect();
3420     QCOMPARE(rect->childrenBoundingRect(), QRectF(-100, 75, 275, 250));
3421 }
3422
3423 void tst_QGraphicsItem::childrenBoundingRect2()
3424 {
3425     QGraphicsItemGroup box;
3426     QGraphicsLineItem l1(0, 0, 100, 0, &box);
3427     QGraphicsLineItem l2(100, 0, 100, 100, &box);
3428     QGraphicsLineItem l3(0, 0, 0, 100, &box);
3429     // Make sure lines (zero with/height) are included in the childrenBoundingRect.
3430     QCOMPARE(box.childrenBoundingRect(), QRectF(0, 0, 100, 100));
3431 }
3432
3433 void tst_QGraphicsItem::childrenBoundingRect3()
3434 {
3435     QGraphicsScene scene;
3436
3437     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
3438     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
3439     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
3440     QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
3441     QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
3442     rect2->setParentItem(rect);
3443     rect3->setParentItem(rect2);
3444     rect4->setParentItem(rect3);
3445     rect5->setParentItem(rect4);
3446
3447     rect2->setTransform(QTransform().translate(50, 50).rotate(45));
3448     rect2->setPos(25, 25);
3449     rect3->setTransform(QTransform().translate(50, 50).rotate(45));
3450     rect3->setPos(25, 25);
3451     rect4->setTransform(QTransform().translate(50, 50).rotate(45));
3452     rect4->setPos(25, 25);
3453     rect5->setTransform(QTransform().translate(50, 50).rotate(45));
3454     rect5->setPos(25, 25);
3455
3456     // Try to mess up the cached bounding rect.
3457     (void)rect2->childrenBoundingRect();
3458
3459     QRectF subTreeRect = rect->childrenBoundingRect();
3460     QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
3461     QCOMPARE(subTreeRect.top(), qreal(75.0));
3462     QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
3463     QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
3464 }
3465
3466 void tst_QGraphicsItem::childrenBoundingRect4()
3467 {
3468     QGraphicsScene scene;
3469
3470     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 10, 10));
3471     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 20, 20));
3472     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 30, 30));
3473     rect2->setParentItem(rect);
3474     rect3->setParentItem(rect);
3475
3476     QGraphicsView view(&scene);
3477     view.show();
3478
3479     QTest::qWaitForWindowShown(&view);
3480
3481     // Try to mess up the cached bounding rect.
3482     rect->childrenBoundingRect();
3483     rect2->childrenBoundingRect();
3484
3485     rect3->setOpacity(0.0);
3486     rect3->setParentItem(rect2);
3487
3488     QCOMPARE(rect->childrenBoundingRect(), rect3->boundingRect());
3489     QCOMPARE(rect2->childrenBoundingRect(), rect3->boundingRect());
3490 }
3491
3492 void tst_QGraphicsItem::childrenBoundingRect5()
3493 {
3494     QGraphicsScene scene;
3495
3496     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
3497     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100));
3498     child->setParentItem(parent);
3499
3500     QGraphicsView view(&scene);
3501     view.show();
3502
3503     QTest::qWaitForWindowShown(&view);
3504
3505     // Try to mess up the cached bounding rect.
3506     QRectF expectedChildrenBoundingRect = parent->boundingRect();
3507     QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect);
3508
3509     // Apply some effects.
3510     QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect;
3511     dropShadow->setOffset(25, 25);
3512     child->setGraphicsEffect(dropShadow);
3513     parent->setGraphicsEffect(new QGraphicsOpacityEffect);
3514
3515     QVERIFY(parent->childrenBoundingRect() != expectedChildrenBoundingRect);
3516     expectedChildrenBoundingRect |= dropShadow->boundingRect();
3517     QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect);
3518 }
3519
3520 void tst_QGraphicsItem::group()
3521 {
3522     QGraphicsScene scene;
3523     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::green));
3524     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::blue));
3525     QGraphicsRectItem *parent2 = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::red));
3526     parent2->setPos(-50, 50);
3527     child->rotate(45);
3528     child->setParentItem(parent);
3529     parent->setPos(25, 25);
3530     child->setPos(25, 25);
3531
3532     QCOMPARE(parent->group(), (QGraphicsItemGroup *)0);
3533     QCOMPARE(parent2->group(), (QGraphicsItemGroup *)0);
3534     QCOMPARE(child->group(), (QGraphicsItemGroup *)0);
3535
3536     QGraphicsView view(&scene);
3537     view.show();
3538     QTest::qWaitForWindowShown(&view);
3539     QApplication::processEvents();
3540
3541     QGraphicsItemGroup *group = new QGraphicsItemGroup;
3542     group->setSelected(true);
3543     scene.addItem(group);
3544
3545     QRectF parentSceneBoundingRect = parent->sceneBoundingRect();
3546     group->addToGroup(parent);
3547     QCOMPARE(parent->group(), group);
3548     QCOMPARE(parent->sceneBoundingRect(), parentSceneBoundingRect);
3549
3550     QCOMPARE(parent->parentItem(), (QGraphicsItem *)group);
3551     QCOMPARE(group->children().size(), 1);
3552     QCOMPARE(scene.items().size(), 4);
3553     QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 3);
3554
3555     QTest::qWait(25);
3556
3557     QRectF parent2SceneBoundingRect = parent2->sceneBoundingRect();
3558     group->addToGroup(parent2);
3559     QCOMPARE(parent2->group(), group);
3560     QCOMPARE(parent2->sceneBoundingRect(), parent2SceneBoundingRect);
3561
3562     QCOMPARE(parent2->parentItem(), (QGraphicsItem *)group);
3563     QCOMPARE(group->children().size(), 2);
3564     QCOMPARE(scene.items().size(), 4);
3565     QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 4);
3566
3567     QTest::qWait(25);
3568
3569     QList<QGraphicsItem *> newItems;
3570     for (int i = 0; i < 100; ++i) {
3571         QGraphicsItem *item = scene.addRect(QRectF(-25, -25, 50, 50), QPen(Qt::black, 0),
3572                                             QBrush(QColor(rand() % 255, rand() % 255,
3573                                                           rand() % 255, rand() % 255)));
3574         newItems << item;
3575         item->setPos(-1000 + rand() % 2000,
3576                      -1000 + rand() % 2000);
3577         item->rotate(rand() % 90);
3578     }
3579
3580     view.fitInView(scene.itemsBoundingRect());
3581
3582     int n = 0;
3583     foreach (QGraphicsItem *item, newItems) {
3584         group->addToGroup(item);
3585         QCOMPARE(item->group(), group);
3586         if ((n++ % 100) == 0)
3587             QTest::qWait(10);
3588     }
3589 }
3590
3591 void tst_QGraphicsItem::setGroup()
3592 {
3593     QGraphicsItemGroup group1;
3594     QGraphicsItemGroup group2;
3595
3596     QGraphicsRectItem *rect = new QGraphicsRectItem;
3597     QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
3598     QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
3599     rect->setGroup(&group1);
3600     QCOMPARE(rect->group(), &group1);
3601     QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group1);
3602     rect->setGroup(&group2);
3603     QCOMPARE(rect->group(), &group2);
3604     QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group2);
3605     rect->setGroup(0);
3606     QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
3607     QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
3608 }
3609
3610 void tst_QGraphicsItem::setGroup2()
3611 {
3612     QGraphicsScene scene;
3613     QGraphicsItemGroup group;
3614     scene.addItem(&group);
3615
3616     QGraphicsRectItem *rect = scene.addRect(50,50,50,50,Qt::NoPen,Qt::black);
3617     rect->setTransformOriginPoint(50,50);
3618     rect->setRotation(45);
3619     rect->setScale(1.5);
3620     rect->translate(20,20);
3621     group.translate(-30,-40);
3622     group.setRotation(180);
3623     group.setScale(0.5);
3624
3625     QTransform oldSceneTransform = rect->sceneTransform();
3626     rect->setGroup(&group);
3627     QCOMPARE(rect->sceneTransform(), oldSceneTransform);
3628
3629     group.setRotation(20);
3630     group.setScale(2);
3631     rect->setRotation(90);
3632     rect->setScale(0.8);
3633
3634     oldSceneTransform = rect->sceneTransform();
3635     rect->setGroup(0);
3636     QCOMPARE(rect->sceneTransform(), oldSceneTransform);
3637 }
3638
3639 void tst_QGraphicsItem::nestedGroups()
3640 {
3641     QGraphicsItemGroup *group1 = new QGraphicsItemGroup;
3642     QGraphicsItemGroup *group2 = new QGraphicsItemGroup;
3643
3644     QGraphicsRectItem *rect = new QGraphicsRectItem;
3645     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
3646     rect2->setParentItem(rect);
3647
3648     group1->addToGroup(rect);
3649     QCOMPARE(rect->group(), group1);
3650     QCOMPARE(rect2->group(), group1);
3651
3652     group2->addToGroup(group1);
3653     QCOMPARE(rect->group(), group1);
3654     QCOMPARE(rect2->group(), group1);
3655     QCOMPARE(group1->group(), group2);
3656     QCOMPARE(group2->group(), (QGraphicsItemGroup *)0);
3657
3658     QGraphicsScene scene;
3659     scene.addItem(group1);
3660
3661     QCOMPARE(rect->group(), group1);
3662     QCOMPARE(rect2->group(), group1);
3663     QCOMPARE(group1->group(), (QGraphicsItemGroup *)0);
3664     QVERIFY(group2->children().isEmpty());
3665
3666     delete group2;
3667 }
3668
3669 void tst_QGraphicsItem::warpChildrenIntoGroup()
3670 {
3671     QGraphicsScene scene;
3672     QGraphicsRectItem *parentRectItem = scene.addRect(QRectF(0, 0, 100, 100));
3673     QGraphicsRectItem *childRectItem = scene.addRect(QRectF(0, 0, 100, 100));
3674     parentRectItem->rotate(90);
3675     childRectItem->setPos(-50, -25);
3676     childRectItem->setParentItem(parentRectItem);
3677
3678     QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
3679     QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
3680
3681     QGraphicsRectItem *parentOfGroup = scene.addRect(QRectF(0, 0, 100, 100));
3682     parentOfGroup->setPos(-200, -200);
3683     parentOfGroup->scale(2, 2);
3684
3685     QGraphicsItemGroup *group = new QGraphicsItemGroup;
3686     group->setPos(50, 50);
3687     group->setParentItem(parentOfGroup);
3688
3689     QCOMPARE(group->scenePos(), QPointF(-100, -100));
3690
3691     group->addToGroup(childRectItem);
3692
3693     QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
3694     QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
3695 }
3696
3697 void tst_QGraphicsItem::removeFromGroup()
3698 {
3699     QGraphicsScene scene;
3700     QGraphicsRectItem *rect1 = scene.addRect(QRectF(-100, -100, 200, 200));
3701     QGraphicsRectItem *rect2 = scene.addRect(QRectF(100, 100, 200, 200));
3702     rect1->setFlag(QGraphicsItem::ItemIsSelectable);
3703     rect2->setFlag(QGraphicsItem::ItemIsSelectable);
3704     rect1->setSelected(true);
3705     rect2->setSelected(true);
3706
3707     QGraphicsView view(&scene);
3708     view.show();
3709
3710     qApp->processEvents(); // index items
3711     qApp->processEvents(); // emit changed
3712
3713     QGraphicsItemGroup *group = scene.createItemGroup(scene.selectedItems());
3714     QVERIFY(group);
3715     QCOMPARE(group->children().size(), 2);
3716     qApp->processEvents(); // index items
3717     qApp->processEvents(); // emit changed
3718
3719     scene.destroyItemGroup(group); // calls removeFromGroup.
3720
3721     qApp->processEvents(); // index items
3722     qApp->processEvents(); // emit changed
3723
3724     QCOMPARE(scene.items().size(), 2);
3725     QVERIFY(!rect1->group());
3726     QVERIFY(!rect2->group());
3727 }
3728
3729 class ChildEventTester : public QGraphicsRectItem
3730 {
3731 public:
3732     ChildEventTester(const QRectF &rect, QGraphicsItem *parent = 0)
3733         : QGraphicsRectItem(rect, parent), counter(0)
3734     { }
3735
3736     int counter;
3737
3738 protected:
3739     void focusInEvent(QFocusEvent *event)
3740     { ++counter; QGraphicsRectItem::focusInEvent(event); }
3741     void mousePressEvent(QGraphicsSceneMouseEvent *)
3742     { ++counter; }
3743     void mouseMoveEvent(QGraphicsSceneMouseEvent *)
3744     { ++counter; }
3745     void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
3746     { ++counter; }
3747 };
3748
3749 void tst_QGraphicsItem::handlesChildEvents()
3750 {
3751     ChildEventTester *blue = new ChildEventTester(QRectF(0, 0, 100, 100));
3752     ChildEventTester *red = new ChildEventTester(QRectF(0, 0, 50, 50));
3753     ChildEventTester *green = new ChildEventTester(QRectF(0, 0, 25, 25));
3754     ChildEventTester *gray = new ChildEventTester(QRectF(0, 0, 25, 25));
3755     ChildEventTester *yellow = new ChildEventTester(QRectF(0, 0, 50, 50));
3756
3757     blue->setBrush(QBrush(Qt::blue));
3758     red->setBrush(QBrush(Qt::red));
3759     yellow->setBrush(QBrush(Qt::yellow));
3760     green->setBrush(QBrush(Qt::green));
3761     gray->setBrush(QBrush(Qt::gray));
3762     red->setPos(50, 0);
3763     yellow->setPos(50, 50);
3764     green->setPos(25, 0);
3765     gray->setPos(25, 25);
3766     red->setParentItem(blue);
3767     yellow->setParentItem(blue);
3768     green->setParentItem(red);
3769     gray->setParentItem(red);
3770
3771     QGraphicsScene scene;
3772     scene.addItem(blue);
3773
3774     QGraphicsView view(&scene);
3775     view.show();
3776     QTest::qWaitForWindowShown(&view);
3777     QTest::qWait(20);
3778
3779     // Pull out the items, closest item first
3780     QList<QGraphicsItem *> items = scene.items(scene.itemsBoundingRect());
3781     QCOMPARE(items.at(0), (QGraphicsItem *)yellow);
3782     QCOMPARE(items.at(1), (QGraphicsItem *)gray);
3783     QCOMPARE(items.at(2), (QGraphicsItem *)green);
3784     QCOMPARE(items.at(3), (QGraphicsItem *)red);
3785     QCOMPARE(items.at(4), (QGraphicsItem *)blue);
3786
3787     QCOMPARE(blue->counter, 0);
3788
3789     // Send events to the toplevel item
3790     QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
3791     QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
3792
3793     pressEvent.setButton(Qt::LeftButton);
3794     pressEvent.setScenePos(blue->mapToScene(5, 5));
3795     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3796     releaseEvent.setButton(Qt::LeftButton);
3797     releaseEvent.setScenePos(blue->mapToScene(5, 5));
3798     releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3799     QApplication::sendEvent(&scene, &pressEvent);
3800     QApplication::sendEvent(&scene, &releaseEvent);
3801
3802     QCOMPARE(blue->counter, 2);
3803
3804     // Send events to a level1 item
3805     pressEvent.setScenePos(red->mapToScene(5, 5));
3806     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3807     releaseEvent.setScenePos(red->mapToScene(5, 5));
3808     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3809     QApplication::sendEvent(&scene, &pressEvent);
3810     QApplication::sendEvent(&scene, &releaseEvent);
3811
3812     QCOMPARE(blue->counter, 2);
3813     QCOMPARE(red->counter, 2);
3814
3815     // Send events to a level2 item
3816     pressEvent.setScenePos(green->mapToScene(5, 5));
3817     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3818     releaseEvent.setScenePos(green->mapToScene(5, 5));
3819     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3820     QApplication::sendEvent(&scene, &pressEvent);
3821     QApplication::sendEvent(&scene, &releaseEvent);
3822
3823     QCOMPARE(blue->counter, 2);
3824     QCOMPARE(red->counter, 2);
3825     QCOMPARE(green->counter, 2);
3826
3827     blue->setHandlesChildEvents(true);
3828
3829     // Send events to a level1 item
3830     pressEvent.setScenePos(red->mapToScene(5, 5));
3831     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3832     releaseEvent.setScenePos(red->mapToScene(5, 5));
3833     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3834     QApplication::sendEvent(&scene, &pressEvent);
3835     QApplication::sendEvent(&scene, &releaseEvent);
3836
3837     QCOMPARE(blue->counter, 4);
3838     QCOMPARE(red->counter, 2);
3839
3840     // Send events to a level2 item
3841     pressEvent.setScenePos(green->mapToScene(5, 5));
3842     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3843     releaseEvent.setScenePos(green->mapToScene(5, 5));
3844     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3845     QApplication::sendEvent(&scene, &pressEvent);
3846     QApplication::sendEvent(&scene, &releaseEvent);
3847
3848     QCOMPARE(blue->counter, 6);
3849     QCOMPARE(red->counter, 2);
3850     QCOMPARE(green->counter, 2);
3851
3852     blue->setHandlesChildEvents(false);
3853
3854     // Send events to a level1 item
3855     pressEvent.setScenePos(red->mapToScene(5, 5));
3856     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3857     releaseEvent.setScenePos(red->mapToScene(5, 5));
3858     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3859     QApplication::sendEvent(&scene, &pressEvent);
3860     QApplication::sendEvent(&scene, &releaseEvent);
3861
3862     QCOMPARE(blue->counter, 6);
3863     QCOMPARE(red->counter, 4);
3864
3865     // Send events to a level2 item
3866     pressEvent.setScenePos(green->mapToScene(5, 5));
3867     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3868     releaseEvent.setScenePos(green->mapToScene(5, 5));
3869     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3870     QApplication::sendEvent(&scene, &pressEvent);
3871     QApplication::sendEvent(&scene, &releaseEvent);
3872
3873     QCOMPARE(blue->counter, 6);
3874     QCOMPARE(red->counter, 4);
3875     QCOMPARE(green->counter, 4);
3876 }
3877
3878 void tst_QGraphicsItem::handlesChildEvents2()
3879 {
3880     ChildEventTester *root = new ChildEventTester(QRectF(0, 0, 10, 10));
3881     root->setHandlesChildEvents(true);
3882     QVERIFY(root->handlesChildEvents());
3883
3884     ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
3885     QVERIFY(!child->handlesChildEvents());
3886
3887     ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10));
3888     ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2);
3889     ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3);
3890     child2->setParentItem(root);
3891     QVERIFY(!child2->handlesChildEvents());
3892     QVERIFY(!child3->handlesChildEvents());
3893     QVERIFY(!child4->handlesChildEvents());
3894
3895     QGraphicsScene scene;
3896     scene.addItem(root);
3897
3898     QGraphicsView view(&scene);
3899     view.show();
3900     QTest::qWaitForWindowShown(&view);
3901     QApplication::processEvents();
3902
3903     QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
3904                       view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
3905     QApplication::sendEvent(view.viewport(), &event);
3906
3907     QTRY_COMPARE(root->counter, 1);
3908 }
3909
3910 void tst_QGraphicsItem::handlesChildEvents3()
3911 {
3912     QGraphicsScene scene;
3913     QEvent activate(QEvent::WindowActivate);
3914     QApplication::sendEvent(&scene, &activate);
3915
3916     ChildEventTester *group2 = new ChildEventTester(QRectF(), 0);
3917     ChildEventTester *group1 = new ChildEventTester(QRectF(), group2);
3918     ChildEventTester *leaf = new ChildEventTester(QRectF(), group1);
3919     scene.addItem(group2);
3920
3921     leaf->setFlag(QGraphicsItem::ItemIsFocusable);
3922     group1->setFlag(QGraphicsItem::ItemIsFocusable);
3923     group1->setHandlesChildEvents(true);
3924     group2->setFlag(QGraphicsItem::ItemIsFocusable);
3925     group2->setHandlesChildEvents(true);
3926
3927     leaf->setFocus();
3928     QVERIFY(leaf->hasFocus()); // group2 stole the event, but leaf still got focus
3929     QVERIFY(!group1->hasFocus());
3930     QVERIFY(!group2->hasFocus());
3931     QCOMPARE(leaf->counter, 0);
3932     QCOMPARE(group1->counter, 0);
3933     QCOMPARE(group2->counter, 1);
3934
3935     group1->setFocus();
3936     QVERIFY(group1->hasFocus()); // group2 stole the event, but group1 still got focus
3937     QVERIFY(!leaf->hasFocus());
3938     QVERIFY(!group2->hasFocus());
3939     QCOMPARE(leaf->counter, 0);
3940     QCOMPARE(group1->counter, 0);
3941     QCOMPARE(group2->counter, 2);
3942
3943     group2->setFocus();
3944     QVERIFY(group2->hasFocus()); // group2 stole the event, and now group2 also has focus
3945     QVERIFY(!leaf->hasFocus());
3946     QVERIFY(!group1->hasFocus());
3947     QCOMPARE(leaf->counter, 0);
3948     QCOMPARE(group1->counter, 0);
3949     QCOMPARE(group2->counter, 3);
3950 }
3951
3952
3953 class ChildEventFilterTester : public ChildEventTester
3954 {
3955 public:
3956     ChildEventFilterTester(const QRectF &rect, QGraphicsItem *parent = 0)
3957         : ChildEventTester(rect, parent), filter(QEvent::None)
3958     { }
3959
3960     QEvent::Type filter;
3961
3962 protected:
3963     bool sceneEventFilter(QGraphicsItem *item, QEvent *event)
3964     {
3965         Q_UNUSED(item);
3966         if (event->type() == filter) {
3967             ++counter;
3968             return true;
3969         }
3970         return false;
3971     }
3972 };
3973
3974 void tst_QGraphicsItem::filtersChildEvents()
3975 {
3976     QGraphicsScene scene;
3977     ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
3978     ChildEventFilterTester *filter = new ChildEventFilterTester(QRectF(10, 10, 10, 10), root);
3979     ChildEventTester *child = new ChildEventTester(QRectF(20, 20, 10, 10), filter);
3980
3981     // setup filter
3982     filter->setFiltersChildEvents(true);
3983     filter->filter = QEvent::GraphicsSceneMousePress;
3984
3985     scene.addItem(root);
3986
3987     QGraphicsView view(&scene);
3988     view.show();
3989     QTest::qWaitForWindowShown(&view);
3990     QTest::qWait(20);
3991
3992     QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
3993     QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
3994
3995     // send event to child
3996     pressEvent.setButton(Qt::LeftButton);
3997     pressEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
3998     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3999     releaseEvent.setButton(Qt::LeftButton);
4000     releaseEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
4001     releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
4002     QApplication::sendEvent(&scene, &pressEvent);
4003     QApplication::sendEvent(&scene, &releaseEvent);
4004
4005     QTRY_COMPARE(child->counter, 1);  // mouse release is not filtered
4006     QCOMPARE(filter->counter, 1); // mouse press is filtered
4007     QCOMPARE(root->counter, 0);
4008
4009     // add another filter
4010     root->setFiltersChildEvents(true);
4011     root->filter = QEvent::GraphicsSceneMouseRelease;
4012
4013     // send event to child
4014     QApplication::sendEvent(&scene, &pressEvent);
4015     QApplication::sendEvent(&scene, &releaseEvent);
4016
4017     QCOMPARE(child->counter, 1);
4018     QCOMPARE(filter->counter, 2); // mouse press is filtered
4019     QCOMPARE(root->counter, 1); // mouse release is filtered
4020
4021     // reparent to another sub-graph
4022     ChildEventTester *parent = new ChildEventTester(QRectF(10, 10, 10, 10), root);
4023     child->setParentItem(parent);
4024
4025     // send event to child
4026     QApplication::sendEvent(&scene, &pressEvent);
4027     QApplication::sendEvent(&scene, &releaseEvent);
4028
4029     QCOMPARE(child->counter, 2); // mouse press is _not_ filtered
4030     QCOMPARE(parent->counter, 0);
4031     QCOMPARE(filter->counter, 2);
4032     QCOMPARE(root->counter, 2); // mouse release is filtered
4033 }
4034
4035 void tst_QGraphicsItem::filtersChildEvents2()
4036 {
4037     ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
4038     root->setFiltersChildEvents(true);
4039     root->filter = QEvent::GraphicsSceneMousePress;
4040     QVERIFY(root->filtersChildEvents());
4041
4042     ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
4043     QVERIFY(!child->filtersChildEvents());
4044
4045     ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10));
4046     ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2);
4047     ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3);
4048
4049     child2->setParentItem(root);
4050     QVERIFY(!child2->filtersChildEvents());
4051     QVERIFY(!child3->filtersChildEvents());
4052     QVERIFY(!child4->filtersChildEvents());
4053
4054     QGraphicsScene scene;
4055     scene.addItem(root);
4056
4057     QGraphicsView view(&scene);
4058     view.show();
4059
4060     QTest::qWaitForWindowShown(&view);
4061     QApplication::processEvents();
4062
4063     QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
4064                       view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
4065     QApplication::sendEvent(view.viewport(), &event);
4066
4067     QTRY_COMPARE(root->counter, 1);
4068     QCOMPARE(child->counter, 0);
4069     QCOMPARE(child2->counter, 0);
4070     QCOMPARE(child3->counter, 0);
4071     QCOMPARE(child4->counter, 0);
4072 }
4073
4074 class CustomItem : public QGraphicsItem
4075 {
4076 public:
4077     QRectF boundingRect() const
4078     { return QRectF(-110, -110, 220, 220); }
4079
4080     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
4081     {
4082         for (int x = -100; x <= 100; x += 25)
4083             painter->drawLine(x, -100, x, 100);
4084         for (int y = -100; y <= 100; y += 25)
4085             painter->drawLine(-100, y, 100, y);
4086
4087         QFont font = painter->font();
4088         font.setPointSize(4);
4089         painter->setFont(font);
4090         for (int x = -100; x < 100; x += 25) {
4091             for (int y = -100; y < 100; y += 25) {
4092                 painter->drawText(QRectF(x, y, 25, 25), Qt::AlignCenter, QString("%1x%2").arg(x).arg(y));
4093             }
4094         }
4095     }
4096 };
4097
4098 void tst_QGraphicsItem::ensureVisible()
4099 {
4100     QGraphicsScene scene;
4101     scene.setSceneRect(-200, -200, 400, 400);
4102     QGraphicsItem *item = new CustomItem;
4103     scene.addItem(item);
4104
4105     QGraphicsView view(&scene);
4106     view.setFixedSize(300, 300);
4107     view.show();
4108     QTest::qWaitForWindowShown(&view);
4109
4110     for (int i = 0; i < 25; ++i) {
4111         view.scale(qreal(1.06), qreal(1.06));
4112         QApplication::processEvents();
4113     }
4114
4115     item->ensureVisible(-100, -100, 25, 25);
4116     QTest::qWait(25);
4117
4118     for (int x = -100; x < 100; x += 25) {
4119         for (int y = -100; y < 100; y += 25) {
4120             int xmargin = rand() % 75;
4121             int ymargin = rand() % 75;
4122             item->ensureVisible(x, y, 25, 25, xmargin, ymargin);
4123             QApplication::processEvents();
4124
4125             QPolygonF viewScenePoly;
4126             viewScenePoly << view.mapToScene(view.rect().topLeft())
4127                           << view.mapToScene(view.rect().topRight())
4128                           << view.mapToScene(view.rect().bottomRight())
4129                           << view.mapToScene(view.rect().bottomLeft());
4130
4131             QVERIFY(scene.items(viewScenePoly).contains(item));
4132
4133             QPainterPath path;
4134             path.addPolygon(viewScenePoly);
4135             QVERIFY(path.contains(item->mapToScene(x + 12, y + 12)));
4136
4137             QPolygonF viewScenePolyMinusMargins;
4138             viewScenePolyMinusMargins << view.mapToScene(view.rect().topLeft() + QPoint(xmargin, ymargin))
4139                           << view.mapToScene(view.rect().topRight() + QPoint(-xmargin, ymargin))
4140                           << view.mapToScene(view.rect().bottomRight() + QPoint(-xmargin, -ymargin))
4141                           << view.mapToScene(view.rect().bottomLeft() + QPoint(xmargin, -ymargin));
4142
4143             QPainterPath path2;
4144             path2.addPolygon(viewScenePolyMinusMargins);
4145             QVERIFY(path2.contains(item->mapToScene(x + 12, y + 12)));
4146         }
4147     }
4148
4149     item->ensureVisible(100, 100, 25, 25);
4150     QTest::qWait(25);
4151 }
4152
4153 void tst_QGraphicsItem::cursor()
4154 {
4155 #ifndef QT_NO_CURSOR
4156     QGraphicsScene scene;
4157     QGraphicsRectItem *item1 = scene.addRect(QRectF(0, 0, 50, 50));
4158     QGraphicsRectItem *item2 = scene.addRect(QRectF(0, 0, 50, 50));
4159     item1->setPos(-100, 0);
4160     item2->setPos(50, 0);
4161
4162     QVERIFY(!item1->hasCursor());
4163     QVERIFY(!item2->hasCursor());
4164
4165     item1->setCursor(Qt::IBeamCursor);
4166     item2->setCursor(Qt::PointingHandCursor);
4167
4168     QVERIFY(item1->hasCursor());
4169     QVERIFY(item2->hasCursor());
4170
4171     item1->setCursor(QCursor());
4172     item2->setCursor(QCursor());
4173
4174     QVERIFY(item1->hasCursor());
4175     QVERIFY(item2->hasCursor());
4176
4177     item1->unsetCursor();
4178     item2->unsetCursor();
4179
4180     QVERIFY(!item1->hasCursor());
4181     QVERIFY(!item2->hasCursor());
4182
4183     item1->setCursor(Qt::IBeamCursor);
4184     item2->setCursor(Qt::PointingHandCursor);
4185
4186     QWidget topLevel;
4187     QGraphicsView view(&scene,&topLevel);
4188     view.setFixedSize(200, 100);
4189     topLevel.show();
4190     QTest::mouseMove(&view, view.rect().center());
4191
4192     QTest::qWait(25);
4193
4194     QCursor cursor = view.viewport()->cursor();
4195
4196     {
4197         QMouseEvent event(QEvent::MouseMove, QPoint(100, 50), Qt::NoButton, 0, 0);
4198         QApplication::sendEvent(view.viewport(), &event);
4199     }
4200
4201     QTest::qWait(25);
4202
4203     QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
4204
4205     {
4206         QTest::mouseMove(view.viewport(), view.mapFromScene(item1->sceneBoundingRect().center()));
4207         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
4208         QApplication::sendEvent(view.viewport(), &event);
4209     }
4210
4211     if (!PlatformQuirks::haveMouseCursor())
4212         return;
4213 #if !defined(Q_OS_WINCE)
4214     QTest::qWait(250);
4215 #else
4216     // Test environment does not have any cursor, therefore no shape
4217     return;
4218 #endif
4219
4220     QCOMPARE(view.viewport()->cursor().shape(), item1->cursor().shape());
4221
4222     {
4223         QTest::mouseMove(view.viewport(), view.mapFromScene(item2->sceneBoundingRect().center()));
4224         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item2->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
4225         QApplication::sendEvent(view.viewport(), &event);
4226     }
4227
4228     QTest::qWait(25);
4229
4230     QCOMPARE(view.viewport()->cursor().shape(), item2->cursor().shape());
4231
4232     {
4233         QTest::mouseMove(view.viewport(), view.rect().center());
4234         QMouseEvent event(QEvent::MouseMove, QPoint(100, 25), Qt::NoButton, 0, 0);
4235         QApplication::sendEvent(view.viewport(), &event);
4236     }
4237
4238     QTest::qWait(25);
4239
4240     QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
4241 #endif
4242 }
4243 /*
4244 void tst_QGraphicsItem::textControlGetterSetter()
4245 {
4246     QGraphicsTextItem *item = new QGraphicsTextItem;
4247     QVERIFY(item->textControl()->parent() == item);
4248     QPointer<QTextControl> control = item->textControl();
4249     delete item;
4250     QVERIFY(!control);
4251
4252     item = new QGraphicsTextItem;
4253
4254     QPointer<QTextControl> oldControl = control;
4255     control = new QTextControl;
4256
4257     item->setTextControl(control);
4258     QVERIFY(item->textControl() == control);
4259     QVERIFY(!control->parent());
4260     QVERIFY(!oldControl);
4261
4262     // set some text to give it a size, to test that
4263     // setTextControl (re)connects signals
4264     const QRectF oldBoundingRect = item->boundingRect();
4265     QVERIFY(oldBoundingRect.isValid());
4266     item->setPlainText("Some text");
4267     item->adjustSize();
4268     QVERIFY(item->boundingRect().isValid());
4269     QVERIFY(item->boundingRect() != oldBoundingRect);
4270
4271     // test that on setting a control the item size
4272     // is adjusted
4273     oldControl = control;
4274     control = new QTextControl;
4275     control->setPlainText("foo!");
4276     item->setTextControl(control);
4277     QCOMPARE(item->boundingRect().size(), control->document()->documentLayout()->documentSize());
4278
4279     QVERIFY(oldControl);
4280     delete oldControl;
4281
4282     delete item;
4283     QVERIFY(control);
4284     delete control;
4285 }
4286 */
4287
4288 void tst_QGraphicsItem::defaultItemTest_QGraphicsLineItem()
4289 {
4290     QGraphicsLineItem item;
4291     QCOMPARE(item.line(), QLineF());
4292     QCOMPARE(item.pen(), QPen());
4293     QCOMPARE(item.shape(), QPainterPath());
4294
4295     item.setPen(QPen(Qt::black, 1));
4296     QCOMPARE(item.pen(), QPen(Qt::black, 1));
4297     item.setLine(QLineF(0, 0, 10, 0));
4298     QCOMPARE(item.line(), QLineF(0, 0, 10, 0));
4299     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 11, 1));
4300     QCOMPARE(item.shape().elementCount(), 11);
4301
4302     QPainterPath path;
4303     path.moveTo(0, -0.5);
4304     path.lineTo(10, -0.5);
4305     path.lineTo(10.5, -0.5);
4306     path.lineTo(10.5, 0.5);
4307     path.lineTo(10, 0.5);
4308     path.lineTo(0, 0.5);
4309     path.lineTo(-0.5, 0.5);
4310     path.lineTo(-0.5, -0.5);
4311     path.lineTo(0, -0.5);
4312     path.lineTo(0, 0);
4313     path.lineTo(10, 0);
4314     path.closeSubpath();
4315
4316     for (int i = 0; i < 11; ++i)
4317         QCOMPARE(QPointF(item.shape().elementAt(i)), QPointF(path.elementAt(i)));
4318 }
4319
4320 void tst_QGraphicsItem::defaultItemTest_QGraphicsPixmapItem()
4321 {
4322     QGraphicsPixmapItem item;
4323     QVERIFY(item.pixmap().isNull());
4324     QCOMPARE(item.offset(), QPointF());
4325     QCOMPARE(item.transformationMode(), Qt::FastTransformation);
4326
4327     QPixmap pixmap(300, 200);
4328     pixmap.fill(Qt::red);
4329     item.setPixmap(pixmap);
4330     QCOMPARE(item.pixmap(), pixmap);
4331
4332     item.setTransformationMode(Qt::FastTransformation);
4333     QCOMPARE(item.transformationMode(), Qt::FastTransformation);
4334     item.setTransformationMode(Qt::SmoothTransformation);
4335     QCOMPARE(item.transformationMode(), Qt::SmoothTransformation);
4336
4337     item.setOffset(-15, -15);
4338     QCOMPARE(item.offset(), QPointF(-15, -15));
4339     item.setOffset(QPointF(-10, -10));
4340     QCOMPARE(item.offset(), QPointF(-10, -10));
4341
4342     QCOMPARE(item.boundingRect(), QRectF(-10, -10, 300, 200));
4343 }
4344
4345 void tst_QGraphicsItem::defaultItemTest_QGraphicsTextItem()
4346 {
4347     QGraphicsTextItem *text = new QGraphicsTextItem;
4348     QVERIFY(!text->openExternalLinks());
4349     QVERIFY(text->textCursor().isNull());
4350     QCOMPARE(text->defaultTextColor(), QPalette().color(QPalette::Text));
4351     QVERIFY(text->document() != 0);
4352     QCOMPARE(text->font(), QApplication::font());
4353     QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::NoTextInteraction));
4354     QCOMPARE(text->textWidth(), -1.0);
4355     QCOMPARE(text->toPlainText(), QString(""));
4356
4357     QGraphicsScene scene;
4358     scene.addItem(text);
4359     text->setPlainText("Hello world");
4360     text->setFlag(QGraphicsItem::ItemIsMovable);
4361
4362     {
4363         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
4364         event.setScenePos(QPointF(1, 1));
4365         event.setButton(Qt::LeftButton);
4366         event.setButtons(Qt::LeftButton);
4367         QApplication::sendEvent(&scene, &event);
4368         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
4369         event2.setScenePos(QPointF(11, 11));
4370         event2.setButton(Qt::LeftButton);
4371         event2.setButtons(Qt::LeftButton);
4372         QApplication::sendEvent(&scene, &event2);
4373     }
4374
4375     QCOMPARE(text->pos(), QPointF(10, 10));
4376
4377     text->setTextInteractionFlags(Qt::NoTextInteraction);
4378     QVERIFY(!(text->flags() & QGraphicsItem::ItemAcceptsInputMethod));
4379     text->setTextInteractionFlags(Qt::TextEditorInteraction);
4380     QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::TextEditorInteraction));
4381     QVERIFY(text->flags() & QGraphicsItem::ItemAcceptsInputMethod);
4382
4383     {
4384         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
4385         event2.setScenePos(QPointF(21, 21));
4386         event2.setButton(Qt::LeftButton);
4387         event2.setButtons(Qt::LeftButton);
4388         QApplication::sendEvent(&scene, &event2);
4389     }
4390
4391     QCOMPARE(text->pos(), QPointF(20, 20)); // clicked on edge, item moved
4392 }
4393
4394 void tst_QGraphicsItem::defaultItemTest_QGraphicsEllipseItem()
4395 {
4396     QGraphicsEllipseItem item;
4397     QVERIFY(item.rect().isNull());
4398     QVERIFY(item.boundingRect().isNull());
4399     QVERIFY(item.shape().isEmpty());
4400     QCOMPARE(item.spanAngle(), 360 * 16);
4401     QCOMPARE(item.startAngle(), 0);
4402
4403     item.setRect(0, 0, 100, 100);
4404     QCOMPARE(item.boundingRect(), QRectF(0, 0, 100, 100));
4405
4406     item.setSpanAngle(90 * 16);
4407     qFuzzyCompare(item.boundingRect().left(), qreal(50.0));
4408     qFuzzyCompare(item.boundingRect().top(), qreal(0.0));
4409     qFuzzyCompare(item.boundingRect().width(), qreal(50.0));
4410     qFuzzyCompare(item.boundingRect().height(), qreal(50.0));
4411
4412     item.setPen(QPen(Qt::black, 1));
4413     QCOMPARE(item.boundingRect(), QRectF(49.5, -0.5, 51, 51));
4414
4415     item.setSpanAngle(180 * 16);
4416     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 51));
4417
4418     item.setSpanAngle(360 * 16);
4419     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 101));
4420 }
4421
4422 class ItemChangeTester : public QGraphicsRectItem
4423 {
4424 public:
4425     ItemChangeTester()
4426     { setFlag(ItemSendsGeometryChanges); clear(); }
4427     ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent)
4428     { setFlag(ItemSendsGeometryChanges); clear(); }
4429
4430     void clear()
4431     {
4432         itemChangeReturnValue = QVariant();
4433         itemSceneChangeTargetScene = 0;
4434         changes.clear();
4435         values.clear();
4436         oldValues.clear();
4437     }
4438
4439     QVariant itemChangeReturnValue;
4440     QGraphicsScene *itemSceneChangeTargetScene;
4441
4442     QList<GraphicsItemChange> changes;
4443     QList<QVariant> values;
4444     QList<QVariant> oldValues;
4445 protected:
4446     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
4447     {
4448         changes << change;
4449         values << value;
4450         switch (change) {
4451         case QGraphicsItem::ItemPositionChange:
4452             oldValues << pos();
4453             break;
4454         case QGraphicsItem::ItemPositionHasChanged:
4455             break;
4456         case QGraphicsItem::ItemMatrixChange: {
4457             QVariant variant;
4458             qVariantSetValue<QMatrix>(variant, matrix());
4459             oldValues << variant;
4460         }
4461             break;
4462         case QGraphicsItem::ItemTransformChange: {
4463             QVariant variant;
4464             qVariantSetValue<QTransform>(variant, transform());
4465             oldValues << variant;
4466         }
4467             break;
4468         case QGraphicsItem::ItemTransformHasChanged:
4469             break;
4470         case QGraphicsItem::ItemVisibleChange:
4471             oldValues << isVisible();
4472             break;
4473         case QGraphicsItem::ItemVisibleHasChanged:
4474             break;
4475         case QGraphicsItem::ItemEnabledChange:
4476             oldValues << isEnabled();
4477             break;
4478         case QGraphicsItem::ItemEnabledHasChanged:
4479             break;
4480         case QGraphicsItem::ItemSelectedChange:
4481             oldValues << isSelected();
4482             break;
4483         case QGraphicsItem::ItemSelectedHasChanged:
4484             break;
4485         case QGraphicsItem::ItemParentChange:
4486             oldValues << qVariantFromValue<void *>(parentItem());
4487             break;
4488         case QGraphicsItem::ItemParentHasChanged:
4489             break;
4490         case QGraphicsItem::ItemChildAddedChange:
4491             oldValues << children().size();
4492             break;
4493         case QGraphicsItem::ItemChildRemovedChange:
4494             oldValues << children().size();
4495             break;
4496         case QGraphicsItem::ItemSceneChange:
4497             oldValues << qVariantFromValue<QGraphicsScene *>(scene());
4498             if (itemSceneChangeTargetScene
4499                 && qVariantValue<QGraphicsScene *>(value)
4500                 && itemSceneChangeTargetScene != qVariantValue<QGraphicsScene *>(value)) {
4501                 return qVariantFromValue<QGraphicsScene *>(itemSceneChangeTargetScene);
4502             }
4503             return value;
4504         case QGraphicsItem::ItemSceneHasChanged:
4505             break;
4506         case QGraphicsItem::ItemCursorChange:
4507 #ifndef QT_NO_CURSOR
4508             oldValues << cursor();
4509 #endif
4510             break;
4511         case QGraphicsItem::ItemCursorHasChanged:
4512             break;
4513         case QGraphicsItem::ItemToolTipChange:
4514             oldValues << toolTip();
4515             break;
4516         case QGraphicsItem::ItemToolTipHasChanged:
4517             break;
4518         case QGraphicsItem::ItemFlagsChange:
4519             oldValues << quint32(flags());
4520             break;
4521         case QGraphicsItem::ItemFlagsHaveChanged:
4522             break;
4523         case QGraphicsItem::ItemZValueChange:
4524             oldValues << zValue();
4525             break;
4526         case QGraphicsItem::ItemZValueHasChanged:
4527             break;
4528         case QGraphicsItem::ItemOpacityChange:
4529             oldValues << opacity();
4530             break;
4531         case QGraphicsItem::ItemOpacityHasChanged:
4532             break;
4533         case QGraphicsItem::ItemScenePositionHasChanged:
4534             break;
4535         case QGraphicsItem::ItemRotationChange:
4536             oldValues << rotation();
4537             break;
4538         case QGraphicsItem::ItemRotationHasChanged:
4539             break;
4540         case QGraphicsItem::ItemScaleChange:
4541             oldValues << scale();
4542             break;
4543         case QGraphicsItem::ItemScaleHasChanged:
4544             break;
4545         case QGraphicsItem::ItemTransformOriginPointChange:
4546             oldValues << transformOriginPoint();
4547             break;
4548         case QGraphicsItem::ItemTransformOriginPointHasChanged:
4549             break;
4550         }
4551         return itemChangeReturnValue.isValid() ? itemChangeReturnValue : value;
4552     }
4553 };
4554
4555 void tst_QGraphicsItem::itemChange()
4556 {
4557     ItemChangeTester tester;
4558     tester.itemSceneChangeTargetScene = 0;
4559
4560     ItemChangeTester testerHelper;
4561     QVERIFY(tester.changes.isEmpty());
4562     QVERIFY(tester.values.isEmpty());
4563
4564     int changeCount = 0;
4565     {
4566         // ItemEnabledChange
4567         tester.itemChangeReturnValue = true;
4568         tester.setEnabled(false);
4569         ++changeCount;
4570         ++changeCount; // HasChanged
4571         QCOMPARE(tester.changes.size(), changeCount);
4572         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemEnabledChange);
4573         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemEnabledHasChanged);
4574         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
4575         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
4576         QCOMPARE(tester.oldValues.last(), QVariant(true));
4577         QCOMPARE(tester.isEnabled(), true);
4578     }
4579     {
4580         // ItemMatrixChange / ItemTransformHasChanged
4581         qVariantSetValue<QMatrix>(tester.itemChangeReturnValue, QMatrix().rotate(90));
4582         tester.setMatrix(QMatrix().translate(50, 0), true);
4583         ++changeCount; // notification sent too
4584         QCOMPARE(tester.changes.size(), ++changeCount);
4585         QCOMPARE(int(tester.changes.at(tester.changes.size() - 2)), int(QGraphicsItem::ItemMatrixChange));
4586         QCOMPARE(int(tester.changes.last()), int(QGraphicsItem::ItemTransformHasChanged));
4587         QCOMPARE(qVariantValue<QMatrix>(tester.values.at(tester.values.size() - 2)),
4588                  QMatrix().translate(50, 0));
4589         QCOMPARE(tester.values.last(), QVariant(QTransform(QMatrix().rotate(90))));
4590         QVariant variant;
4591         qVariantSetValue<QMatrix>(variant, QMatrix());
4592         QCOMPARE(tester.oldValues.last(), variant);
4593         QCOMPARE(tester.matrix(), QMatrix().rotate(90));
4594     }
4595     {
4596         tester.resetTransform();
4597         ++changeCount;
4598         ++changeCount; // notification sent too
4599
4600         // ItemTransformChange / ItemTransformHasChanged
4601         qVariantSetValue<QTransform>(tester.itemChangeReturnValue, QTransform().rotate(90));
4602         tester.translate(50, 0);
4603         ++changeCount; // notification sent too
4604         ++changeCount;
4605         QCOMPARE(tester.changes.size(), changeCount);
4606         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformChange);
4607         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformHasChanged);
4608         QCOMPARE(qVariantValue<QTransform>(tester.values.at(tester.values.size() - 2)),
4609                  QTransform().translate(50, 0));
4610         QCOMPARE(qVariantValue<QTransform>(tester.values.at(tester.values.size() - 1)),
4611                  QTransform().rotate(90));
4612         QVariant variant;
4613         qVariantSetValue<QTransform>(variant, QTransform());
4614         QCOMPARE(tester.oldValues.last(), variant);
4615         QCOMPARE(tester.transform(), QTransform().rotate(90));
4616     }
4617     {
4618         // ItemPositionChange / ItemPositionHasChanged
4619         tester.itemChangeReturnValue = QPointF(42, 0);
4620         tester.setPos(0, 42);
4621         ++changeCount; // notification sent too
4622         ++changeCount;
4623         QCOMPARE(tester.changes.size(), changeCount);
4624         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemPositionChange);
4625         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemPositionHasChanged);
4626         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(0, 42)));
4627         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(42, 0)));
4628         QCOMPARE(tester.oldValues.last(), QVariant(QPointF()));
4629         QCOMPARE(tester.pos(), QPointF(42, 0));
4630     }
4631     {
4632         // ItemZValueChange / ItemZValueHasChanged
4633         tester.itemChangeReturnValue = qreal(2.0);
4634         tester.setZValue(1.0);
4635         ++changeCount; // notification sent too
4636         ++changeCount;
4637         QCOMPARE(tester.changes.size(), changeCount);
4638         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemZValueChange);
4639         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemZValueHasChanged);
4640         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.0)));
4641         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0)));
4642         QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0)));
4643         QCOMPARE(tester.zValue(), qreal(2.0));
4644     }
4645     {
4646         // ItemRotationChange / ItemRotationHasChanged
4647         tester.itemChangeReturnValue = qreal(15.0);
4648         tester.setRotation(10.0);
4649         ++changeCount; // notification sent too
4650         ++changeCount;
4651         QCOMPARE(tester.changes.size(), changeCount);
4652         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemRotationChange);
4653         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemRotationHasChanged);
4654         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(10.0)));
4655         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(15.0)));
4656         QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0)));
4657         QCOMPARE(tester.rotation(), qreal(15.0));
4658     }
4659     {
4660         // ItemScaleChange / ItemScaleHasChanged
4661         tester.itemChangeReturnValue = qreal(2.0);
4662         tester.setScale(1.5);
4663         ++changeCount; // notification sent too
4664         ++changeCount;
4665         QCOMPARE(tester.changes.size(), changeCount);
4666         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemScaleChange);
4667         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemScaleHasChanged);
4668         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.5)));
4669         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0)));
4670         QCOMPARE(tester.oldValues.last(), QVariant(qreal(1.0)));
4671         QCOMPARE(tester.scale(), qreal(2.0));
4672     }
4673     {
4674         // ItemTransformOriginPointChange / ItemTransformOriginPointHasChanged
4675         tester.itemChangeReturnValue = QPointF(2.0, 2.0);
4676         tester.setTransformOriginPoint(1.0, 1.0);
4677         ++changeCount; // notification sent too
4678         ++changeCount;
4679         QCOMPARE(tester.changes.size(), changeCount);
4680         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformOriginPointChange);
4681         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformOriginPointHasChanged);
4682         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(1.0, 1.0)));
4683         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(2.0, 2.0)));
4684         QCOMPARE(tester.oldValues.last(), QVariant(QPointF(0.0, 0.0)));
4685         QCOMPARE(tester.transformOriginPoint(), QPointF(2.0, 2.0));
4686     }
4687     {
4688         // ItemFlagsChange
4689         tester.itemChangeReturnValue = QGraphicsItem::ItemIsSelectable;
4690         tester.setFlag(QGraphicsItem::ItemIsSelectable, false);
4691         QCOMPARE(tester.changes.size(), changeCount);  // No change
4692         tester.setFlag(QGraphicsItem::ItemIsSelectable, true);
4693         ++changeCount;
4694         ++changeCount; // ItemFlagsHasChanged
4695         QCOMPARE(tester.changes.size(), changeCount);
4696         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemFlagsChange);
4697         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemFlagsHaveChanged);
4698         QVariant expectedFlags = qVariantFromValue<quint32>(QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges));
4699         QCOMPARE(tester.values.at(tester.values.size() - 2), expectedFlags);
4700         QCOMPARE(tester.values.at(tester.values.size() - 1), qVariantFromValue<quint32>((quint32)QGraphicsItem::ItemIsSelectable));
4701     }
4702     {
4703         // ItemSelectedChange
4704         tester.setSelected(false);
4705         QCOMPARE(tester.changes.size(), changeCount); // No change :-)
4706         tester.itemChangeReturnValue = true;
4707         tester.setSelected(true);
4708         ++changeCount;
4709         ++changeCount; // ItemSelectedHasChanged
4710         QCOMPARE(tester.changes.size(), changeCount);
4711         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedChange);
4712         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSelectedHasChanged);
4713         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(true));
4714         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
4715         QCOMPARE(tester.oldValues.last(), QVariant(false));
4716         QCOMPARE(tester.isSelected(), true);
4717
4718         tester.itemChangeReturnValue = false;
4719         tester.setSelected(true);
4720
4721         // the value hasn't changed to the itemChange return value
4722         // bacause itemChange is never called (true -> true is a noop).
4723         QCOMPARE(tester.isSelected(), true);
4724     }
4725     {
4726         // ItemVisibleChange
4727         tester.itemChangeReturnValue = false;
4728         QVERIFY(tester.isVisible());
4729         tester.setVisible(false);
4730         ++changeCount; // ItemVisibleChange
4731         ++changeCount; // ItemSelectedChange
4732         ++changeCount; // ItemSelectedHasChanged
4733         ++changeCount; // ItemVisibleHasChanged
4734         QCOMPARE(tester.changes.size(), changeCount);
4735         QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemVisibleChange);
4736         QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSelectedChange);
4737         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedHasChanged);
4738         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemVisibleHasChanged);
4739         QCOMPARE(tester.values.at(tester.values.size() - 4), QVariant(false));
4740         QCOMPARE(tester.values.at(tester.values.size() - 3), QVariant(false));
4741         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
4742         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(false));
4743         QCOMPARE(tester.isVisible(), false);
4744     }
4745     {
4746         // ItemParentChange
4747         qVariantSetValue<QGraphicsItem *>(tester.itemChangeReturnValue, 0);
4748         tester.setParentItem(&testerHelper);
4749         QCOMPARE(tester.changes.size(), ++changeCount);
4750         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemParentChange);
4751         QCOMPARE(qVariantValue<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4752         QCOMPARE(qVariantValue<QGraphicsItem *>(tester.oldValues.last()), (QGraphicsItem *)0);
4753         QCOMPARE(tester.parentItem(), (QGraphicsItem *)0);
4754     }
4755     {
4756         // ItemOpacityChange
4757         tester.itemChangeReturnValue = 1.0;
4758         tester.setOpacity(0.7);
4759         QCOMPARE(tester.changes.size(), ++changeCount);
4760         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemOpacityChange);
4761         QVERIFY(qFuzzyCompare(qreal(tester.values.last().toDouble()), qreal(0.7)));
4762         QCOMPARE(tester.oldValues.last().toDouble(), double(1.0));
4763         QCOMPARE(tester.opacity(), qreal(1.0));
4764         tester.itemChangeReturnValue = 0.7;
4765         tester.setOpacity(0.7);
4766         ++changeCount; // ItemOpacityChange
4767         ++changeCount; // ItemOpacityHasChanged
4768         QCOMPARE(tester.changes.size(), changeCount);
4769         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemOpacityChange);
4770         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemOpacityHasChanged);
4771         QCOMPARE(tester.opacity(), qreal(0.7));
4772     }
4773     {
4774         // ItemChildAddedChange
4775         tester.itemChangeReturnValue.clear();
4776         testerHelper.setParentItem(&tester);
4777         QCOMPARE(tester.changes.size(), ++changeCount);
4778         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildAddedChange);
4779         QCOMPARE(qVariantValue<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4780     }
4781     {
4782         // ItemChildRemovedChange 1
4783         testerHelper.setParentItem(0);
4784         QCOMPARE(tester.changes.size(), ++changeCount);
4785         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildRemovedChange);
4786         QCOMPARE(qVariantValue<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4787
4788         // ItemChildRemovedChange 1
4789         ItemChangeTester *test = new ItemChangeTester;
4790         test->itemSceneChangeTargetScene = 0;
4791         int count = 0;
4792         QGraphicsScene *scene = new QGraphicsScene;
4793         scene->addItem(test);
4794         count = test->changes.size();
4795         //We test here the fact that when a child is deleted the parent receive only one ItemChildRemovedChange
4796         QGraphicsRectItem *child = new QGraphicsRectItem(test);
4797         //We received ItemChildAddedChange
4798         QCOMPARE(test->changes.size(), ++count);
4799         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildAddedChange);
4800         delete child;
4801         child = 0;
4802         QCOMPARE(test->changes.size(), ++count);
4803         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
4804
4805         ItemChangeTester *childTester = new ItemChangeTester(test);
4806         //Changes contains all sceneHasChanged and so on, we don't want to test that
4807         int childCount = childTester->changes.size();
4808         //We received ItemChildAddedChange
4809         QCOMPARE(test->changes.size(), ++count);
4810         child = new QGraphicsRectItem(childTester);
4811         //We received ItemChildAddedChange
4812         QCOMPARE(childTester->changes.size(), ++childCount);
4813         QCOMPARE(childTester->changes.last(), QGraphicsItem::ItemChildAddedChange);
4814         //Delete the child of the top level with all its children
4815         delete childTester;
4816         //Only one removal
4817         QCOMPARE(test->changes.size(), ++count);
4818         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
4819         delete scene;
4820     }
4821     {
4822         // ItemChildRemovedChange 2
4823         ItemChangeTester parent;
4824         ItemChangeTester *child = new ItemChangeTester;
4825         child->setParentItem(&parent);
4826         QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildAddedChange);
4827         QCOMPARE(qVariantValue<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
4828         delete child;
4829         QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildRemovedChange);
4830         QCOMPARE(qVariantValue<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
4831     }
4832     {
4833         // !!! Note: If this test crashes because of double-deletion, there's
4834         // a bug somewhere in QGraphicsScene or QGraphicsItem.
4835
4836         // ItemSceneChange
4837         QGraphicsScene scene;
4838         QGraphicsScene scene2;
4839         scene.addItem(&tester);
4840         ++changeCount; // ItemSceneChange (scene)
4841         ++changeCount; // ItemSceneHasChanged (scene)
4842         QCOMPARE(tester.changes.size(), changeCount);
4843
4844         QCOMPARE(tester.scene(), &scene);
4845         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4846         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4847         // Item's old value was 0
4848         // Item's current value is scene
4849         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
4850         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene);
4851         scene2.addItem(&tester);
4852         ++changeCount; // ItemSceneChange (0) was: (scene)
4853         ++changeCount; // ItemSceneHasChanged (0)
4854         ++changeCount; // ItemSceneChange (scene2) was: (0)
4855         ++changeCount; // ItemSceneHasChanged (scene2)
4856         QCOMPARE(tester.changes.size(), changeCount);
4857
4858         QCOMPARE(tester.scene(), &scene2);
4859         QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemSceneChange);
4860         QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSceneHasChanged);
4861         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4862         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4863         // Item's last old value was scene
4864         // Item's last current value is 0
4865
4866         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 2)), (QGraphicsScene *)&scene);
4867         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 1)), (QGraphicsScene *)0);
4868         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 4)), (QGraphicsScene *)0);
4869         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)0);
4870         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene2);
4871         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene2);
4872         // Item's last old value was 0
4873         // Item's last current value is scene2
4874         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
4875         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene2);
4876
4877         scene2.removeItem(&tester);
4878         ++changeCount; // ItemSceneChange (0) was: (scene2)
4879         ++changeCount; // ItemSceneHasChanged (0)
4880         QCOMPARE(tester.changes.size(), changeCount);
4881
4882         QCOMPARE(tester.scene(), (QGraphicsScene *)0);
4883         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4884         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4885         // Item's last old value was scene2
4886         // Item's last current value is 0
4887         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)&scene2);
4888         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)0);
4889         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)0);
4890
4891         tester.itemSceneChangeTargetScene = &scene;
4892         scene2.addItem(&tester);
4893         ++changeCount; // ItemSceneChange (scene2) was: (0)
4894         ++changeCount; // ItemSceneChange (scene) was: (0)
4895         ++changeCount; // ItemSceneHasChanged (scene)
4896         QCOMPARE(tester.values.size(), changeCount);
4897
4898         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)&scene2);
4899         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene);
4900         QCOMPARE(qVariantValue<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene);
4901
4902         QCOMPARE(tester.scene(), &scene);
4903         tester.itemSceneChangeTargetScene = 0;
4904         tester.itemChangeReturnValue = QVariant();
4905         scene.removeItem(&tester);
4906         ++changeCount; // ItemSceneChange
4907         ++changeCount; // ItemSceneHasChanged
4908         QCOMPARE(tester.scene(), (QGraphicsScene *)0);
4909     }
4910     {
4911         // ItemToolTipChange/ItemToolTipHasChanged
4912         const QString toolTip(QLatin1String("I'm soo cool"));
4913         const QString overridenToolTip(QLatin1String("No, you are not soo cool"));
4914         tester.itemChangeReturnValue = overridenToolTip;
4915         tester.setToolTip(toolTip);
4916         ++changeCount; // ItemToolTipChange
4917         ++changeCount; // ItemToolTipHasChanged
4918         QCOMPARE(tester.changes.size(), changeCount);
4919         QCOMPARE(tester.changes.at(changeCount - 2), QGraphicsItem::ItemToolTipChange);
4920         QCOMPARE(tester.values.at(changeCount - 2).toString(), toolTip);
4921         QCOMPARE(tester.changes.at(changeCount - 1), QGraphicsItem::ItemToolTipHasChanged);
4922         QCOMPARE(tester.values.at(changeCount - 1).toString(), overridenToolTip);
4923         QCOMPARE(tester.toolTip(), overridenToolTip);
4924         tester.itemChangeReturnValue = QVariant();
4925     }
4926 }
4927
4928 class EventFilterTesterItem : public QGraphicsLineItem
4929 {
4930 public:
4931     QList<QEvent::Type> filteredEvents;
4932     QList<QGraphicsItem *> filteredEventReceivers;
4933     bool handlesSceneEvents;
4934
4935     QList<QEvent::Type> receivedEvents;
4936
4937     EventFilterTesterItem() : handlesSceneEvents(false) {}
4938
4939 protected:
4940     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
4941     {
4942         filteredEvents << event->type();
4943         filteredEventReceivers << watched;
4944         return handlesSceneEvents;
4945     }
4946
4947     bool sceneEvent(QEvent *event)
4948     {
4949         return QGraphicsLineItem::sceneEvent(event);
4950     }
4951 };
4952
4953 void tst_QGraphicsItem::sceneEventFilter()
4954 {
4955     QGraphicsScene scene;
4956
4957     QGraphicsView view(&scene);
4958     view.show();
4959     QApplication::setActiveWindow(&view);
4960     QTest::qWaitForWindowShown(&view);
4961     QTest::qWait(25);
4962
4963     QGraphicsTextItem *text1 = scene.addText(QLatin1String("Text1"));
4964     QGraphicsTextItem *text2 = scene.addText(QLatin1String("Text2"));
4965     QGraphicsTextItem *text3 = scene.addText(QLatin1String("Text3"));
4966     text1->setFlag(QGraphicsItem::ItemIsFocusable);
4967     text2->setFlag(QGraphicsItem::ItemIsFocusable);
4968     text3->setFlag(QGraphicsItem::ItemIsFocusable);
4969
4970     EventFilterTesterItem *tester = new EventFilterTesterItem;
4971     scene.addItem(tester);
4972
4973     QTRY_VERIFY(!text1->hasFocus());
4974     text1->installSceneEventFilter(tester);
4975     text1->setFocus();
4976     QTRY_VERIFY(text1->hasFocus());
4977
4978     QCOMPARE(tester->filteredEvents.size(), 1);
4979     QCOMPARE(tester->filteredEvents.at(0), QEvent::FocusIn);
4980     QCOMPARE(tester->filteredEventReceivers.at(0), static_cast<QGraphicsItem *>(text1));
4981
4982     text2->installSceneEventFilter(tester);
4983     text3->installSceneEventFilter(tester);
4984
4985     text2->setFocus();
4986     text3->setFocus();
4987
4988     QCOMPARE(tester->filteredEvents.size(), 5);
4989     QCOMPARE(tester->filteredEvents.at(1), QEvent::FocusOut);
4990     QCOMPARE(tester->filteredEventReceivers.at(1), static_cast<QGraphicsItem *>(text1));
4991     QCOMPARE(tester->filteredEvents.at(2), QEvent::FocusIn);
4992     QCOMPARE(tester->filteredEventReceivers.at(2), static_cast<QGraphicsItem *>(text2));
4993     QCOMPARE(tester->filteredEvents.at(3), QEvent::FocusOut);
4994     QCOMPARE(tester->filteredEventReceivers.at(3), static_cast<QGraphicsItem *>(text2));
4995     QCOMPARE(tester->filteredEvents.at(4), QEvent::FocusIn);
4996     QCOMPARE(tester->filteredEventReceivers.at(4), static_cast<QGraphicsItem *>(text3));
4997
4998     text1->removeSceneEventFilter(tester);
4999     text1->setFocus();
5000
5001     QCOMPARE(tester->filteredEvents.size(), 6);
5002     QCOMPARE(tester->filteredEvents.at(5), QEvent::FocusOut);
5003     QCOMPARE(tester->filteredEventReceivers.at(5), static_cast<QGraphicsItem *>(text3));
5004
5005     tester->handlesSceneEvents = true;
5006     text2->setFocus();
5007
5008     QCOMPARE(tester->filteredEvents.size(), 7);
5009     QCOMPARE(tester->filteredEvents.at(6), QEvent::FocusIn);
5010     QCOMPARE(tester->filteredEventReceivers.at(6), static_cast<QGraphicsItem *>(text2));
5011
5012     QVERIFY(text2->hasFocus());
5013
5014     //Let check if the items are correctly removed from the sceneEventFilters array
5015     //to avoid stale pointers.
5016     QGraphicsView gv;
5017     QGraphicsScene *anotherScene = new QGraphicsScene;
5018     QGraphicsTextItem *ti = anotherScene->addText("This is a test #1");
5019     ti->moveBy(50, 50);
5020     QGraphicsTextItem *ti2 = anotherScene->addText("This is a test #2");
5021     QGraphicsTextItem *ti3 = anotherScene->addText("This is a test #3");
5022     gv.setScene(anotherScene);
5023     gv.show();
5024     QTest::qWaitForWindowShown(&gv);
5025     QTest::qWait(25);
5026     ti->installSceneEventFilter(ti2);
5027     ti3->installSceneEventFilter(ti);
5028     delete ti2;
5029     //we souldn't crash
5030     QTest::mouseMove(gv.viewport(), gv.mapFromScene(ti->scenePos()));
5031     QTest::qWait(30);
5032     delete ti;
5033 }
5034
5035 class GeometryChanger : public QGraphicsItem
5036 {
5037 public:
5038     void changeGeometry()
5039     { prepareGeometryChange(); }
5040 };
5041
5042 void tst_QGraphicsItem::prepareGeometryChange()
5043 {
5044     {
5045         QGraphicsScene scene;
5046         QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
5047         QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
5048         ((GeometryChanger *)item)->changeGeometry();
5049         QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
5050     }
5051 }
5052
5053
5054 class PaintTester : public QGraphicsRectItem
5055 {
5056 public:
5057     PaintTester() : widget(NULL), painted(0) { setRect(QRectF(10, 10, 20, 20));}
5058
5059     void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *w)
5060     {
5061         widget = w;
5062         painted++;
5063     }
5064
5065     QWidget*  widget;
5066     int painted;
5067 };
5068
5069 void tst_QGraphicsItem::paint()
5070 {
5071     QGraphicsScene scene;
5072
5073     PaintTester paintTester;
5074     scene.addItem(&paintTester);
5075
5076     QGraphicsView view(&scene);
5077
5078     if(PlatformQuirks::isAutoMaximizing())
5079         view.showFullScreen();
5080     else
5081         view.show();
5082     QTest::qWaitForWindowShown(&view);
5083     QApplication::processEvents();
5084 #ifdef Q_OS_WIN32
5085     //we try to switch the desktop: if it fails, we skip the test
5086     if (::SwitchDesktop( ::GetThreadDesktop( ::GetCurrentThreadId() ) ) == 0) {
5087         QSKIP("The Graphics View doesn't get the paint events");
5088     }
5089 #endif
5090
5091     QTRY_COMPARE(paintTester.widget, view.viewport());
5092
5093     view.hide();
5094
5095     QGraphicsScene scene2;
5096     QGraphicsView view2(&scene2);
5097     view2.show();
5098     QTest::qWaitForWindowShown(&view2);
5099     QTest::qWait(25);
5100
5101     PaintTester tester2;
5102     scene2.addItem(&tester2);
5103     qApp->processEvents();
5104
5105     //First show one paint
5106     QTRY_COMPARE(tester2.painted, 1);
5107
5108     //nominal case, update call paint
5109     tester2.update();
5110     qApp->processEvents();
5111     QTRY_VERIFY(tester2.painted == 2);
5112
5113     //we remove the item from the scene, number of updates is still the same
5114     tester2.update();
5115     scene2.removeItem(&tester2);
5116     qApp->processEvents();
5117     QTRY_VERIFY(tester2.painted == 2);
5118
5119     //We re-add the item, the number of paint should increase
5120     scene2.addItem(&tester2);
5121     tester2.update();
5122     qApp->processEvents();
5123     QTRY_VERIFY(tester2.painted == 3);
5124 }
5125
5126 class HarakiriItem : public QGraphicsRectItem
5127 {
5128 public:
5129     HarakiriItem(int harakiriPoint)
5130         : QGraphicsRectItem(QRectF(0, 0, 100, 100)), harakiri(harakiriPoint)
5131     { dead = 0; }
5132
5133     static int dead;
5134
5135     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
5136     {
5137         QGraphicsRectItem::paint(painter, option, widget);
5138         if (harakiri == 0) {
5139             // delete unsupported since 4.5
5140             /*
5141             dead = 1;
5142             delete this;
5143             */
5144         }
5145     }
5146
5147     void advance(int n)
5148     {
5149         if (harakiri == 1 && n == 0) {
5150             // delete unsupported
5151             /*
5152             dead = 1;
5153             delete this;
5154             */
5155         }
5156         if (harakiri == 2 && n == 1) {
5157             dead = 1;
5158             delete this;
5159         }
5160     }
5161
5162 protected:
5163     void contextMenuEvent(QGraphicsSceneContextMenuEvent *)
5164     {
5165         if (harakiri == 3) {
5166             dead = 1;
5167             delete this;
5168         }
5169     }
5170
5171     void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
5172     {
5173         // ??
5174         QGraphicsRectItem::dragEnterEvent(event);
5175     }
5176
5177     void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
5178     {
5179         // ??
5180         QGraphicsRectItem::dragLeaveEvent(event);
5181     }
5182
5183     void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
5184     {
5185         // ??
5186         QGraphicsRectItem::dragMoveEvent(event);
5187     }
5188
5189     void dropEvent(QGraphicsSceneDragDropEvent *event)
5190     {
5191         // ??
5192         QGraphicsRectItem::dropEvent(event);
5193     }
5194
5195     void focusInEvent(QFocusEvent *)
5196     {
5197         if (harakiri == 4) {
5198             dead = 1;
5199             delete this;
5200         }
5201     }
5202
5203     void focusOutEvent(QFocusEvent *)
5204     {
5205         if (harakiri == 5) {
5206             dead = 1;
5207             delete this;
5208         }
5209     }
5210
5211     void hoverEnterEvent(QGraphicsSceneHoverEvent *)
5212     {
5213         if (harakiri == 6) {
5214             dead = 1;
5215             delete this;
5216         }
5217     }
5218
5219     void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
5220     {
5221         if (harakiri == 7) {
5222             dead = 1;
5223             delete this;
5224         }
5225     }
5226
5227     void hoverMoveEvent(QGraphicsSceneHoverEvent *)
5228     {
5229         if (harakiri == 8) {
5230             dead = 1;
5231             delete this;
5232         }
5233     }
5234
5235     void inputMethodEvent(QInputMethodEvent *event)
5236     {
5237         // ??
5238         QGraphicsRectItem::inputMethodEvent(event);
5239     }
5240
5241     QVariant inputMethodQuery(Qt::InputMethodQuery query) const
5242     {
5243         // ??
5244         return QGraphicsRectItem::inputMethodQuery(query);
5245     }
5246
5247     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
5248     {
5249         // deletion not supported
5250         return QGraphicsRectItem::itemChange(change, value);
5251     }
5252
5253     void keyPressEvent(QKeyEvent *)
5254     {
5255         if (harakiri == 9) {
5256             dead = 1;
5257             delete this;
5258         }
5259     }
5260
5261     void keyReleaseEvent(QKeyEvent *)
5262     {
5263         if (harakiri == 10) {
5264             dead = 1;
5265             delete this;
5266         }
5267     }
5268
5269     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *)
5270     {
5271         if (harakiri == 11) {
5272             dead = 1;
5273             delete this;
5274         }
5275     }
5276
5277     void mouseMoveEvent(QGraphicsSceneMouseEvent *)
5278     {
5279         if (harakiri == 12) {
5280             dead = 1;
5281             delete this;
5282         }
5283     }
5284
5285     void mousePressEvent(QGraphicsSceneMouseEvent *)
5286     {
5287         if (harakiri == 13) {
5288             dead = 1;
5289             delete this;
5290         }
5291     }
5292
5293     void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
5294     {
5295         if (harakiri == 14) {
5296             dead = 1;
5297             delete this;
5298         }
5299     }
5300
5301     bool sceneEvent(QEvent *event)
5302     {
5303         // deletion not supported
5304         return QGraphicsRectItem::sceneEvent(event);
5305     }
5306
5307     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
5308     {
5309         // deletion not supported
5310         return QGraphicsRectItem::sceneEventFilter(watched, event);
5311     }
5312
5313     void wheelEvent(QGraphicsSceneWheelEvent *)
5314     {
5315         if (harakiri == 16) {
5316             dead = 1;
5317             delete this;
5318         }
5319     }
5320
5321 private:
5322     int harakiri;
5323 };
5324
5325 int HarakiriItem::dead;
5326
5327 void tst_QGraphicsItem::deleteItemInEventHandlers()
5328 {
5329     for (int i = 0; i < 17; ++i) {
5330         QGraphicsScene scene;
5331         HarakiriItem *item = new HarakiriItem(i);
5332         item->setAcceptsHoverEvents(true);
5333         item->setFlag(QGraphicsItem::ItemIsFocusable);
5334
5335         scene.addItem(item);
5336
5337         item->installSceneEventFilter(item); // <- ehey!
5338
5339         QGraphicsView view(&scene);
5340         view.show();
5341
5342         qApp->processEvents();
5343         qApp->processEvents();
5344
5345         if (!item->dead)
5346             scene.advance();
5347
5348         if (!item->dead) {
5349             QContextMenuEvent event(QContextMenuEvent::Other,
5350                                     view.mapFromScene(item->scenePos()));
5351             QCoreApplication::sendEvent(view.viewport(), &event);
5352         }
5353         if (!item->dead)
5354             QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos()));
5355         if (!item->dead)
5356             QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
5357         if (!item->dead)
5358             QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
5359         if (!item->dead)
5360             QTest::mouseClick(view.viewport(), Qt::RightButton, 0, view.mapFromScene(item->scenePos()));
5361         if (!item->dead)
5362             QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos() + QPointF(20, -20)));
5363         if (!item->dead)
5364             item->setFocus();
5365         if (!item->dead)
5366             item->clearFocus();
5367         if (!item->dead)
5368             item->setFocus();
5369         if (!item->dead)
5370             QTest::keyPress(view.viewport(), Qt::Key_A);
5371         if (!item->dead)
5372             QTest::keyRelease(view.viewport(), Qt::Key_A);
5373         if (!item->dead)
5374             QTest::keyPress(view.viewport(), Qt::Key_A);
5375         if (!item->dead)
5376             QTest::keyRelease(view.viewport(), Qt::Key_A);
5377     }
5378 }
5379
5380 class ItemPaintsOutsideShape : public QGraphicsItem
5381 {
5382 public:
5383     QRectF boundingRect() const
5384     {
5385         return QRectF(0, 0, 100, 100);
5386     }
5387
5388     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
5389     {
5390         painter->fillRect(-50, -50, 200, 200, Qt::red);
5391         painter->fillRect(0, 0, 100, 100, Qt::blue);
5392     }
5393 };
5394
5395 void tst_QGraphicsItem::itemClipsToShape()
5396 {
5397     QGraphicsItem *clippedItem = new ItemPaintsOutsideShape;
5398     clippedItem->setFlag(QGraphicsItem::ItemClipsToShape);
5399
5400     QGraphicsItem *unclippedItem = new ItemPaintsOutsideShape;
5401     unclippedItem->setPos(200, 0);
5402
5403     QGraphicsScene scene(-50, -50, 400, 200);
5404     scene.addItem(clippedItem);
5405     scene.addItem(unclippedItem);
5406
5407     QImage image(400, 200, QImage::Format_ARGB32_Premultiplied);
5408     image.fill(0);
5409     QPainter painter(&image);
5410     painter.setRenderHint(QPainter::Antialiasing);
5411     scene.render(&painter);
5412     painter.end();
5413
5414     QCOMPARE(image.pixel(45, 100), QRgb(0));
5415     QCOMPARE(image.pixel(100, 45), QRgb(0));
5416     QCOMPARE(image.pixel(155, 100), QRgb(0));
5417     QCOMPARE(image.pixel(45, 155), QRgb(0));
5418     QCOMPARE(image.pixel(55, 100), QColor(Qt::blue).rgba());
5419     QCOMPARE(image.pixel(100, 55), QColor(Qt::blue).rgba());
5420     QCOMPARE(image.pixel(145, 100), QColor(Qt::blue).rgba());
5421     QCOMPARE(image.pixel(55, 145), QColor(Qt::blue).rgba());
5422     QCOMPARE(image.pixel(245, 100), QColor(Qt::red).rgba());
5423     QCOMPARE(image.pixel(300, 45), QColor(Qt::red).rgba());
5424     QCOMPARE(image.pixel(355, 100), QColor(Qt::red).rgba());
5425     QCOMPARE(image.pixel(245, 155), QColor(Qt::red).rgba());
5426     QCOMPARE(image.pixel(255, 100), QColor(Qt::blue).rgba());
5427     QCOMPARE(image.pixel(300, 55), QColor(Qt::blue).rgba());
5428     QCOMPARE(image.pixel(345, 100), QColor(Qt::blue).rgba());
5429     QCOMPARE(image.pixel(255, 145), QColor(Qt::blue).rgba());
5430 }
5431
5432 void tst_QGraphicsItem::itemClipsChildrenToShape()
5433 {
5434     QGraphicsScene scene;
5435     QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::yellow));
5436
5437     QGraphicsItem *ellipse = scene.addEllipse(0, 0, 100, 100, QPen(Qt::NoPen), QBrush(Qt::green));
5438     ellipse->setParentItem(rect);
5439
5440     QGraphicsItem *clippedEllipse = scene.addEllipse(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::blue));
5441     clippedEllipse->setParentItem(ellipse);
5442
5443     QGraphicsItem *clippedEllipse2 = scene.addEllipse(0, 0, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
5444     clippedEllipse2->setParentItem(clippedEllipse);
5445
5446     QGraphicsItem *clippedEllipse3 = scene.addEllipse(50, 50, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
5447     clippedEllipse3->setParentItem(clippedEllipse);
5448
5449     QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
5450     ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5451     QVERIFY((ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
5452
5453     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
5454     image.fill(0);
5455     QPainter painter(&image);
5456     painter.setRenderHint(QPainter::Antialiasing);
5457     scene.render(&painter);
5458     painter.end();
5459
5460     QCOMPARE(image.pixel(16, 16), QColor(255, 0, 0).rgba());
5461     QCOMPARE(image.pixel(32, 32), QColor(0, 0, 255).rgba());
5462     QCOMPARE(image.pixel(50, 50), QColor(0, 255, 0).rgba());
5463     QCOMPARE(image.pixel(12, 12), QColor(255, 255, 0).rgba());
5464     QCOMPARE(image.pixel(60, 60), QColor(255, 0, 0).rgba());
5465 }
5466
5467 void tst_QGraphicsItem::itemClipsChildrenToShape2()
5468 {
5469     QGraphicsRectItem *parent = new QGraphicsRectItem(QRectF(0, 0, 10, 10));
5470     QGraphicsEllipseItem *child1 = new QGraphicsEllipseItem(QRectF(50, 50, 100, 100));
5471     QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(15, 15, 80, 80));
5472
5473     child1->setParentItem(parent);
5474     child1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5475     child2->setParentItem(child1);
5476
5477     parent->setBrush(Qt::blue);
5478     child1->setBrush(Qt::green);
5479     child2->setBrush(Qt::red);
5480
5481     QGraphicsScene scene;
5482     scene.addItem(parent);
5483
5484     QCOMPARE(scene.itemAt(5, 5), (QGraphicsItem *)parent);
5485     QCOMPARE(scene.itemAt(15, 5), (QGraphicsItem *)0);
5486     QCOMPARE(scene.itemAt(5, 15), (QGraphicsItem *)0);
5487     QCOMPARE(scene.itemAt(60, 60), (QGraphicsItem *)0);
5488     QCOMPARE(scene.itemAt(140, 60), (QGraphicsItem *)0);
5489     QCOMPARE(scene.itemAt(60, 140), (QGraphicsItem *)0);
5490     QCOMPARE(scene.itemAt(140, 140), (QGraphicsItem *)0);
5491     QCOMPARE(scene.itemAt(75, 75), (QGraphicsItem *)child2);
5492     QCOMPARE(scene.itemAt(75, 100), (QGraphicsItem *)child1);
5493     QCOMPARE(scene.itemAt(100, 75), (QGraphicsItem *)child1);
5494
5495 #if 1
5496     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
5497     image.fill(0);
5498     QPainter painter(&image);
5499     scene.render(&painter);
5500     painter.end();
5501
5502     QCOMPARE(image.pixel(5, 5), QColor(0, 0, 255).rgba());
5503     QCOMPARE(image.pixel(5, 10), QRgb(0));
5504     QCOMPARE(image.pixel(10, 5), QRgb(0));
5505     QCOMPARE(image.pixel(40, 40), QRgb(0));
5506     QCOMPARE(image.pixel(90, 40), QRgb(0));
5507     QCOMPARE(image.pixel(40, 90), QRgb(0));
5508     QCOMPARE(image.pixel(95, 95), QRgb(0));
5509     QCOMPARE(image.pixel(50, 70), QColor(0, 255, 0).rgba());
5510     QCOMPARE(image.pixel(70, 50), QColor(0, 255, 0).rgba());
5511     QCOMPARE(image.pixel(50, 60), QColor(255, 0, 0).rgba());
5512     QCOMPARE(image.pixel(60, 50), QColor(255, 0, 0).rgba());
5513 #else
5514     QGraphicsView view(&scene);
5515     view.show();
5516     QTest::qWait(5000);
5517 #endif
5518 }
5519
5520 void tst_QGraphicsItem::itemClipsChildrenToShape3()
5521 {
5522     // Construct a scene with nested children, each 50 pixels offset from the elder.
5523     // Set a top-level clipping flag
5524     QGraphicsScene scene;
5525     QGraphicsRectItem *parent = scene.addRect( 0, 0, 150, 150 );
5526     QGraphicsRectItem *child = scene.addRect( 0, 0, 150, 150 );
5527     QGraphicsRectItem *grandchild = scene.addRect( 0, 0, 150, 150 );
5528     child->setParentItem(parent);
5529     grandchild->setParentItem(child);
5530     child->setPos( 50, 50 );
5531     grandchild->setPos( 50, 50 );
5532     parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5533
5534     QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)parent);
5535     QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)child);
5536     QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
5537     QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
5538
5539     // Move child to fully overlap the parent.  The grandchild should
5540     // now occupy two-thirds of the scene
5541     child->prepareGeometryChange();
5542     child->setPos( 0, 0 );
5543
5544     QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)child);
5545     QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)grandchild);
5546     QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
5547     QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
5548 }
5549
5550 class MyProxyWidget : public QGraphicsProxyWidget
5551 {
5552 public:
5553     MyProxyWidget(QGraphicsItem *parent) : QGraphicsProxyWidget(parent)
5554     {
5555         painted = false;
5556     }
5557
5558     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
5559     {
5560         QGraphicsProxyWidget::paint(painter, option, widget);
5561         painted = true;
5562     }
5563     bool painted;
5564 };
5565
5566 void tst_QGraphicsItem::itemClipsChildrenToShape4()
5567 {
5568     QGraphicsScene scene;
5569     QGraphicsView view(&scene);
5570
5571     QGraphicsWidget * outerWidget = new QGraphicsWidget();
5572     outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
5573     MyProxyWidget * innerWidget = new MyProxyWidget(outerWidget);
5574     QLabel * label = new QLabel();
5575     label->setText("Welcome back my friends to the show that never ends...");
5576     innerWidget->setWidget(label);
5577     view.resize(300, 300);
5578     scene.addItem(outerWidget);
5579     outerWidget->resize( 200, 100 );
5580     scene.addEllipse( 100, 100, 100, 50 );   // <-- this is important to trigger the right codepath*
5581     //now the label is shown
5582     outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false );
5583     QApplication::setActiveWindow(&view);
5584     view.show();
5585     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
5586     QTRY_COMPARE(innerWidget->painted, true);
5587 }
5588
5589 //#define DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
5590 static inline void renderSceneToImage(QGraphicsScene *scene, QImage *image, const QString &filename)
5591 {
5592     image->fill(0);
5593     QPainter painter(image);
5594     scene->render(&painter);
5595     painter.end();
5596 #ifdef DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
5597     image->save(filename);
5598 #else
5599     Q_UNUSED(filename);
5600 #endif
5601 }
5602
5603 void tst_QGraphicsItem::itemClipsChildrenToShape5()
5604 {
5605     class ParentItem : public QGraphicsRectItem
5606     {
5607     public:
5608         ParentItem(qreal x, qreal y, qreal width, qreal height)
5609             : QGraphicsRectItem(x, y, width, height) {}
5610
5611         QPainterPath shape() const
5612         {
5613             QPainterPath path;
5614             path.addRect(50, 50, 200, 200);
5615             return path;
5616         }
5617     };
5618
5619     ParentItem *parent = new ParentItem(0, 0, 300, 300);
5620     parent->setBrush(Qt::blue);
5621     parent->setOpacity(0.5);
5622
5623     const QRegion parentRegion(0, 0, 300, 300);
5624     const QRegion clippedParentRegion = parentRegion & QRect(50, 50, 200, 200);
5625     QRegion childRegion;
5626     QRegion grandChildRegion;
5627
5628     QGraphicsRectItem *topLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
5629     topLeftChild->setBrush(Qt::red);
5630     topLeftChild->setParentItem(parent);
5631     childRegion += QRect(0, 0, 100, 100);
5632
5633     QGraphicsRectItem *topRightChild = new QGraphicsRectItem(0, 0, 100, 100);
5634     topRightChild->setBrush(Qt::red);
5635     topRightChild->setParentItem(parent);
5636     topRightChild->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5637     topRightChild->setPos(200, 0);
5638     childRegion += QRect(200, 0, 100, 100);
5639
5640     QGraphicsRectItem *topRightGrandChild = new QGraphicsRectItem(0, 0, 100, 100);
5641     topRightGrandChild->setBrush(Qt::green);
5642     topRightGrandChild->setParentItem(topRightChild);
5643     topRightGrandChild->setPos(-40, 40);
5644     grandChildRegion += QRect(200 - 40, 0 + 40, 100, 100) & QRect(200, 0, 100, 100);
5645
5646     QGraphicsRectItem *bottomLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
5647     bottomLeftChild->setBrush(Qt::red);
5648     bottomLeftChild->setParentItem(parent);
5649     bottomLeftChild->setFlag(QGraphicsItem::ItemClipsToShape);
5650     bottomLeftChild->setPos(0, 200);
5651     childRegion += QRect(0, 200, 100, 100);
5652
5653     QGraphicsRectItem *bottomLeftGrandChild = new QGraphicsRectItem(0, 0, 160, 160);
5654     bottomLeftGrandChild->setBrush(Qt::green);
5655     bottomLeftGrandChild->setParentItem(bottomLeftChild);
5656     bottomLeftGrandChild->setFlag(QGraphicsItem::ItemClipsToShape);
5657     bottomLeftGrandChild->setPos(0, -60);
5658     grandChildRegion += QRect(0, 200 - 60, 160, 160);
5659
5660     QGraphicsRectItem *bottomRightChild = new QGraphicsRectItem(0, 0, 100, 100);
5661     bottomRightChild->setBrush(Qt::red);
5662     bottomRightChild->setParentItem(parent);
5663     bottomRightChild->setPos(200, 200);
5664     childRegion += QRect(200, 200, 100, 100);
5665
5666     QPoint controlPoints[17] = {
5667         QPoint(5, 5)  , QPoint(95, 5)  , QPoint(205, 5)  , QPoint(295, 5)  ,
5668         QPoint(5, 95) , QPoint(95, 95) , QPoint(205, 95) , QPoint(295, 95) ,
5669                              QPoint(150, 150),
5670         QPoint(5, 205), QPoint(95, 205), QPoint(205, 205), QPoint(295, 205),
5671         QPoint(5, 295), QPoint(95, 295), QPoint(205, 295), QPoint(295, 295),
5672     };
5673
5674     const QRegion clippedChildRegion = childRegion & QRect(50, 50, 200, 200);
5675     const QRegion clippedGrandChildRegion = grandChildRegion & QRect(50, 50, 200, 200);
5676
5677     QGraphicsScene scene;
5678     scene.addItem(parent);
5679     QImage sceneImage(300, 300, QImage::Format_ARGB32);
5680
5681 #define VERIFY_CONTROL_POINTS(pRegion, cRegion, gRegion) \
5682     for (int i = 0; i < 17; ++i) { \
5683         QPoint controlPoint = controlPoints[i]; \
5684         QRgb pixel = sceneImage.pixel(controlPoint.x(), controlPoint.y()); \
5685         if (pRegion.contains(controlPoint)) \
5686             QVERIFY(qBlue(pixel) != 0); \
5687         else \
5688             QVERIFY(qBlue(pixel) == 0); \
5689         if (cRegion.contains(controlPoint)) \
5690             QVERIFY(qRed(pixel) != 0); \
5691         else \
5692             QVERIFY(qRed(pixel) == 0); \
5693         if (gRegion.contains(controlPoint)) \
5694             QVERIFY(qGreen(pixel) != 0); \
5695         else \
5696             QVERIFY(qGreen(pixel) == 0); \
5697     }
5698
5699     const QList<QGraphicsItem *> children = parent->childItems();
5700     const int childrenCount = children.count();
5701
5702     for (int i = 0; i < 5; ++i) {
5703         QString clipString;
5704         QString childString;
5705         switch (i) {
5706         case 0:
5707             // All children stacked in front.
5708             childString = QLatin1String("ChildrenInFront.png");
5709             foreach (QGraphicsItem *child, children)
5710                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
5711             break;
5712         case 1:
5713             // All children stacked behind.
5714             childString = QLatin1String("ChildrenBehind.png");
5715             foreach (QGraphicsItem *child, children)
5716                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
5717             break;
5718         case 2:
5719             // First half of the children behind, second half in front.
5720             childString = QLatin1String("FirstHalfBehind_SecondHalfInFront.png");
5721             for (int j = 0; j < childrenCount; ++j) {
5722                 QGraphicsItem *child = children.at(j);
5723                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j < childrenCount / 2));
5724             }
5725             break;
5726         case 3:
5727             // First half of the children in front, second half behind.
5728             childString = QLatin1String("FirstHalfInFront_SecondHalfBehind.png");
5729             for (int j = 0; j < childrenCount; ++j) {
5730                 QGraphicsItem *child = children.at(j);
5731                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j >= childrenCount / 2));
5732             }
5733             break;
5734         case 4:
5735             // Child2 and child4 behind, rest in front.
5736             childString = QLatin1String("Child2And4Behind_RestInFront.png");
5737             for (int j = 0; j < childrenCount; ++j) {
5738                 QGraphicsItem *child = children.at(j);
5739                 if (j == 1 || j == 3)
5740                     child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
5741                 else
5742                     child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
5743             }
5744             break;
5745         default:
5746             qFatal("internal error");
5747         }
5748
5749         // Nothing is clipped.
5750         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
5751         parent->setFlag(QGraphicsItem::ItemClipsToShape, false);
5752         clipString = QLatin1String("nothingClipped_");
5753         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5754         VERIFY_CONTROL_POINTS(parentRegion, childRegion, grandChildRegion);
5755
5756         // Parent clips children to shape.
5757         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5758         clipString = QLatin1String("parentClipsChildrenToShape_");
5759         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5760         VERIFY_CONTROL_POINTS(parentRegion, clippedChildRegion, clippedGrandChildRegion);
5761
5762         // Parent clips itself and children to shape.
5763         parent->setFlag(QGraphicsItem::ItemClipsToShape);
5764         clipString = QLatin1String("parentClipsItselfAndChildrenToShape_");
5765         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5766         VERIFY_CONTROL_POINTS(clippedParentRegion, clippedChildRegion, clippedGrandChildRegion);
5767
5768         // Parent clips itself to shape.
5769         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
5770         clipString = QLatin1String("parentClipsItselfToShape_");
5771         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5772         VERIFY_CONTROL_POINTS(clippedParentRegion, childRegion, grandChildRegion);
5773     }
5774 }
5775
5776 void tst_QGraphicsItem::itemClipsTextChildToShape()
5777 {
5778     // Construct a scene with a rect that clips its children, with one text
5779     // child that has text that exceeds the size of the rect.
5780     QGraphicsScene scene;
5781     QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::black), Qt::black);
5782     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5783     QGraphicsTextItem *text = new QGraphicsTextItem("This is a long sentence that's wider than 50 pixels.");
5784     text->setParentItem(rect);
5785
5786     // Render this scene to a transparent image.
5787     QRectF sr = scene.itemsBoundingRect();
5788     QImage image(sr.size().toSize(), QImage::Format_ARGB32_Premultiplied);
5789     image.fill(0);
5790     QPainter painter(&image);
5791     scene.render(&painter);
5792
5793     // Erase the area immediately underneath the rect.
5794     painter.setCompositionMode(QPainter::CompositionMode_Source);
5795     painter.fillRect(rect->sceneBoundingRect().translated(-sr.topLeft()).adjusted(-0.5, -0.5, 0.5, 0.5),
5796                      Qt::transparent);
5797     painter.end();
5798
5799     // Check that you get a truly transparent image back (i.e., the text was
5800     // clipped away, so there should be no trails left after erasing only the
5801     // rect's area).
5802     QImage emptyImage(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
5803     emptyImage.fill(0);
5804     QCOMPARE(image, emptyImage);
5805 }
5806
5807 void tst_QGraphicsItem::itemClippingDiscovery()
5808 {
5809     // A simple scene with an ellipse parent and two rect children, one a
5810     // child of the other.
5811     QGraphicsScene scene;
5812     QGraphicsEllipseItem *clipItem = scene.addEllipse(0, 0, 100, 100);
5813     QGraphicsRectItem *leftRectItem = scene.addRect(0, 0, 50, 100);
5814     QGraphicsRectItem *rightRectItem = scene.addRect(50, 0, 50, 100);
5815     leftRectItem->setParentItem(clipItem);
5816     rightRectItem->setParentItem(clipItem);
5817
5818     // The rects item are both visible at these points.
5819     QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)leftRectItem);
5820     QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)rightRectItem);
5821
5822     // The ellipse clips the rects now.
5823     clipItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5824
5825     // The rect items are no longer visible at these points.
5826     QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
5827     if (sizeof(qreal) != sizeof(double))
5828         QSKIP("This fails due to internal rounding errors");
5829     QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)0);
5830 }
5831
5832 void tst_QGraphicsItem::ancestorFlags()
5833 {
5834     QGraphicsItem *level1 = new QGraphicsRectItem;
5835     QGraphicsItem *level21 = new QGraphicsRectItem;
5836     level21->setParentItem(level1);
5837     QGraphicsItem *level22 = new QGraphicsRectItem;
5838     level22->setParentItem(level1);
5839     QGraphicsItem *level31 = new QGraphicsRectItem;
5840     level31->setParentItem(level21);
5841     QGraphicsItem *level32 = new QGraphicsRectItem;
5842     level32->setParentItem(level21);
5843
5844     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5845     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5846     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5847     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5848     QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5849
5850     // HandlesChildEvents: 1) Root level sets a flag
5851     level1->setHandlesChildEvents(true);
5852     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5853     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5854     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5855     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5856     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5857
5858     // HandlesChildEvents: 2) Root level set it again
5859     level1->setHandlesChildEvents(true);
5860     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5861     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5862     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5863     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5864     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5865
5866     // HandlesChildEvents: 3) Root level unsets a flag
5867     level1->setHandlesChildEvents(false);
5868     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5869     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5870     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5871     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5872     QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5873
5874     // HandlesChildEvents: 4) Child item sets a flag
5875     level21->setHandlesChildEvents(true);
5876     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5877     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5878     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5879     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5880     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5881
5882     // HandlesChildEvents: 5) Parent item sets a flag
5883     level1->setHandlesChildEvents(true);
5884     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5885     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5886     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5887     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5888     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5889
5890     // HandlesChildEvents: 6) Child item unsets a flag
5891     level21->setHandlesChildEvents(false);
5892     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5893     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5894     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5895     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5896     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5897
5898     // HandlesChildEvents: 7) Parent item unsets a flag
5899     level21->setHandlesChildEvents(true);
5900     level1->setHandlesChildEvents(false);
5901     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5902     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5903     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5904     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5905     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5906
5907     // Reparent the child to root
5908     level21->setParentItem(0);
5909     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5910     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5911     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5912     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5913
5914     // Reparent the child to level1 again.
5915     level1->setHandlesChildEvents(true);
5916     level21->setParentItem(level1);
5917     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5918     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5919     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5920     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5921     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5922
5923     // Reparenting level31 back to level1.
5924     level31->setParentItem(level1);
5925     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5926     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5927     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5928     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5929     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5930
5931     // Reparenting level31 back to level21.
5932     level31->setParentItem(0);
5933     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5934     level31->setParentItem(level21);
5935     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5936     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5937     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5938     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5939     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5940
5941     // Level1 doesn't handle child events
5942     level1->setHandlesChildEvents(false);
5943     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5944     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5945     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5946     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5947     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5948
5949     // Nobody handles child events
5950     level21->setHandlesChildEvents(false);
5951
5952     for (int i = 0; i < 2; ++i) {
5953         QGraphicsItem::GraphicsItemFlag flag = !i ? QGraphicsItem::ItemClipsChildrenToShape
5954                                                : QGraphicsItem::ItemIgnoresTransformations;
5955         int ancestorFlag = !i ? QGraphicsItemPrivate::AncestorClipsChildren
5956                            : QGraphicsItemPrivate::AncestorIgnoresTransformations;
5957
5958         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5959         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5960         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5961         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5962         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5963
5964         // HandlesChildEvents: 1) Root level sets a flag
5965         level1->setFlag(flag, true);
5966         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5967         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
5968         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
5969         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5970         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5971
5972         // HandlesChildEvents: 2) Root level set it again
5973         level1->setFlag(flag, true);
5974         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5975         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
5976         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
5977         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5978         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5979
5980         // HandlesChildEvents: 3) Root level unsets a flag
5981         level1->setFlag(flag, false);
5982         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5983         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5984         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5985         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5986         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5987
5988         // HandlesChildEvents: 4) Child item sets a flag
5989         level21->setFlag(flag, true);
5990         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5991         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5992         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5993         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5994         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5995
5996         // HandlesChildEvents: 5) Parent item sets a flag
5997         level1->setFlag(flag, true);
5998         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5999         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6000         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6001         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6002         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6003
6004         // HandlesChildEvents: 6) Child item unsets a flag
6005         level21->setFlag(flag, false);
6006         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6007         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6008         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6009         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6010         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6011
6012         // HandlesChildEvents: 7) Parent item unsets a flag
6013         level21->setFlag(flag, true);
6014         level1->setFlag(flag, false);
6015         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6016         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6017         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6018         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6019         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6020
6021         // Reparent the child to root
6022         level21->setParentItem(0);
6023         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6024         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6025         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6026         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6027
6028         // Reparent the child to level1 again.
6029         level1->setFlag(flag, true);
6030         level21->setParentItem(level1);
6031         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6032         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6033         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6034         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6035         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6036
6037         // Reparenting level31 back to level1.
6038         level31->setParentItem(level1);
6039         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6040         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6041         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6042         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6043         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6044
6045         // Reparenting level31 back to level21.
6046         level31->setParentItem(0);
6047         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
6048         level31->setParentItem(level21);
6049         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6050         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6051         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6052         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6053         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6054
6055         // Level1 doesn't handle child events
6056         level1->setFlag(flag, false);
6057         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6058         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6059         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6060         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6061         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6062
6063         // Nobody handles child events
6064         level21->setFlag(flag, false);
6065         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6066         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6067         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6068         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
6069         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
6070     }
6071
6072     delete level1;
6073 }
6074
6075 void tst_QGraphicsItem::untransformable()
6076 {
6077     QGraphicsItem *item1 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6078     item1->setZValue(1);
6079     item1->setFlag(QGraphicsItem::ItemIgnoresTransformations);
6080     item1->rotate(45);
6081     ((QGraphicsEllipseItem *)item1)->setBrush(Qt::red);
6082
6083     QGraphicsItem *item2 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6084     item2->setParentItem(item1);
6085     item2->rotate(45);
6086     item2->setPos(100, 0);
6087     ((QGraphicsEllipseItem *)item2)->setBrush(Qt::green);
6088
6089     QGraphicsItem *item3 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6090     item3->setParentItem(item2);
6091     item3->setPos(100, 0);
6092     ((QGraphicsEllipseItem *)item3)->setBrush(Qt::blue);
6093
6094     QGraphicsScene scene(-500, -500, 1000, 1000);
6095     scene.addItem(item1);
6096
6097     QWidget topLevel;
6098     QGraphicsView view(&scene,&topLevel);
6099     view.resize(300, 300);
6100     topLevel.show();
6101     view.scale(8, 8);
6102     view.centerOn(0, 0);
6103
6104 // Painting with the DiagCrossPattern is really slow on Mac
6105 // when zoomed out. (The test times out). Task to fix is 155567.
6106 #if !defined(Q_WS_MAC) || 1
6107     view.setBackgroundBrush(QBrush(Qt::black, Qt::DiagCrossPattern));
6108 #endif
6109
6110     QTest::qWaitForWindowShown(&view);
6111
6112     for (int i = 0; i < 10; ++i) {
6113         QPoint center = view.viewport()->rect().center();
6114         QCOMPARE(view.itemAt(center), item1);
6115         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item1);
6116         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item1);
6117         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item1);
6118         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item1);
6119
6120         center += QPoint(70, 70);
6121         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item2);
6122         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item2);
6123         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item2);
6124         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item2);
6125
6126         center += QPoint(0, 100);
6127         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item3);
6128         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item3);
6129         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item3);
6130         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item3);
6131
6132         view.scale(0.5, 0.5);
6133         view.rotate(13);
6134         view.shear(qreal(0.01), qreal(0.01));
6135         view.translate(10, 10);
6136         QTest::qWait(25);
6137     }
6138 }
6139
6140 class ContextMenuItem : public QGraphicsRectItem
6141 {
6142 public:
6143     ContextMenuItem()
6144         : ignoreEvent(true), gotEvent(false), eventWasAccepted(false)
6145     { }
6146     bool ignoreEvent;
6147     bool gotEvent;
6148     bool eventWasAccepted;
6149 protected:
6150     void contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
6151     {
6152         gotEvent = true;
6153         eventWasAccepted = event->isAccepted();
6154         if (ignoreEvent)
6155             event->ignore();
6156     }
6157 };
6158
6159 void tst_QGraphicsItem::contextMenuEventPropagation()
6160 {
6161     ContextMenuItem *bottomItem = new ContextMenuItem;
6162     bottomItem->setRect(0, 0, 100, 100);
6163     ContextMenuItem *topItem = new ContextMenuItem;
6164     topItem->setParentItem(bottomItem);
6165     topItem->setRect(0, 0, 100, 100);
6166
6167     QGraphicsScene scene;
6168
6169     QGraphicsView view(&scene);
6170     view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
6171     view.show();
6172     view.resize(200, 200);
6173     QTest::qWaitForWindowShown(&view);
6174     QTest::qWait(20);
6175
6176     QContextMenuEvent event(QContextMenuEvent::Mouse, QPoint(10, 10),
6177                             view.viewport()->mapToGlobal(QPoint(10, 10)));
6178     event.ignore();
6179     QApplication::sendEvent(view.viewport(), &event);
6180     QVERIFY(!event.isAccepted());
6181
6182     scene.addItem(bottomItem);
6183     topItem->ignoreEvent = true;
6184     bottomItem->ignoreEvent = true;
6185
6186     QApplication::sendEvent(view.viewport(), &event);
6187     QVERIFY(!event.isAccepted());
6188     QCOMPARE(topItem->gotEvent, true);
6189     QCOMPARE(topItem->eventWasAccepted, true);
6190     QCOMPARE(bottomItem->gotEvent, true);
6191     QCOMPARE(bottomItem->eventWasAccepted, true);
6192
6193     topItem->ignoreEvent = false;
6194     topItem->gotEvent = false;
6195     bottomItem->gotEvent = false;
6196
6197     QApplication::sendEvent(view.viewport(), &event);
6198     QVERIFY(event.isAccepted());
6199     QCOMPARE(topItem->gotEvent, true);
6200     QCOMPARE(bottomItem->gotEvent, false);
6201     QCOMPARE(topItem->eventWasAccepted, true);
6202 }
6203
6204 void tst_QGraphicsItem::itemIsMovable()
6205 {
6206     QGraphicsRectItem *rect = new QGraphicsRectItem(-50, -50, 100, 100);
6207     rect->setFlag(QGraphicsItem::ItemIsMovable);
6208
6209     QGraphicsScene scene;
6210     scene.addItem(rect);
6211
6212     {
6213         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6214         event.setButton(Qt::LeftButton);
6215         event.setButtons(Qt::LeftButton);
6216         qApp->sendEvent(&scene, &event);
6217     }
6218     {
6219         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6220         event.setButton(Qt::LeftButton);
6221         event.setButtons(Qt::LeftButton);
6222         qApp->sendEvent(&scene, &event);
6223     }
6224     QCOMPARE(rect->pos(), QPointF(0, 0));
6225     {
6226         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6227         event.setButtons(Qt::LeftButton);
6228         event.setScenePos(QPointF(10, 10));
6229         qApp->sendEvent(&scene, &event);
6230     }
6231     QCOMPARE(rect->pos(), QPointF(10, 10));
6232     {
6233         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6234         event.setButtons(Qt::RightButton);
6235         event.setScenePos(QPointF(20, 20));
6236         qApp->sendEvent(&scene, &event);
6237     }
6238     QCOMPARE(rect->pos(), QPointF(10, 10));
6239     {
6240         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6241         event.setButtons(Qt::LeftButton);
6242         event.setScenePos(QPointF(30, 30));
6243         qApp->sendEvent(&scene, &event);
6244     }
6245     QCOMPARE(rect->pos(), QPointF(30, 30));
6246 }
6247
6248 class ItemAddScene : public QGraphicsScene
6249 {
6250     Q_OBJECT
6251 public:
6252     ItemAddScene()
6253     {
6254         QTimer::singleShot(500, this, SLOT(newTextItem()));
6255     }
6256
6257 public slots:
6258     void newTextItem()
6259     {
6260         // Add a text item
6261         QGraphicsItem *item = new QGraphicsTextItem("This item will not ensure that it's visible", 0, this);
6262         item->setPos(.0, .0);
6263         item->show();
6264     }
6265 };
6266
6267 void tst_QGraphicsItem::task141694_textItemEnsureVisible()
6268 {
6269     ItemAddScene scene;
6270     scene.setSceneRect(-1000, -1000, 2000, 2000);
6271
6272     QGraphicsView view(&scene);
6273     view.setFixedSize(200, 200);
6274     view.show();
6275     QTest::qWaitForWindowShown(&view);
6276
6277     view.ensureVisible(-1000, -1000, 5, 5);
6278     int hscroll = view.horizontalScrollBar()->value();
6279     int vscroll = view.verticalScrollBar()->value();
6280
6281     QTest::qWait(10);
6282
6283     // This should not cause the view to scroll
6284     QTRY_COMPARE(view.horizontalScrollBar()->value(), hscroll);
6285     QCOMPARE(view.verticalScrollBar()->value(), vscroll);
6286 }
6287
6288 void tst_QGraphicsItem::task128696_textItemEnsureMovable()
6289 {
6290     QGraphicsTextItem *item = new QGraphicsTextItem;
6291     item->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
6292     item->setTextInteractionFlags(Qt::TextEditorInteraction);
6293     item->setPlainText("abc de\nf ghi\n   j k l");
6294
6295     QGraphicsScene scene;
6296     scene.setSceneRect(-100, -100, 200, 200);
6297     scene.addItem(item);
6298
6299     QGraphicsView view(&scene);
6300     view.setFixedSize(200, 200);
6301     view.show();
6302
6303     QGraphicsSceneMouseEvent event1(QEvent::GraphicsSceneMousePress);
6304     event1.setScenePos(QPointF(0, 0));
6305     event1.setButton(Qt::LeftButton);
6306     event1.setButtons(Qt::LeftButton);
6307     QApplication::sendEvent(&scene, &event1);
6308     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6309
6310     QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
6311     event2.setScenePos(QPointF(10, 10));
6312     event2.setButton(Qt::LeftButton);
6313     event2.setButtons(Qt::LeftButton);
6314     QApplication::sendEvent(&scene, &event2);
6315     QCOMPARE(item->pos(), QPointF(10, 10));
6316 }
6317
6318 void tst_QGraphicsItem::task177918_lineItemUndetected()
6319 {
6320     QGraphicsScene scene;
6321     QGraphicsLineItem *line = scene.addLine(10, 10, 10, 10);
6322     QCOMPARE(line->boundingRect(), QRectF(10, 10, 0, 0));
6323
6324     QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemShape).isEmpty());
6325     QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemShape).isEmpty());
6326     QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemBoundingRect).isEmpty());
6327     QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemBoundingRect).isEmpty());
6328 }
6329
6330 void tst_QGraphicsItem::task240400_clickOnTextItem_data()
6331 {
6332     QTest::addColumn<int>("flags");
6333     QTest::addColumn<int>("textFlags");
6334     QTest::newRow("editor, noflags") << 0 << int(Qt::TextEditorInteraction);
6335     QTest::newRow("editor, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::TextEditorInteraction);
6336     QTest::newRow("editor, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::TextEditorInteraction);
6337     QTest::newRow("editor, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
6338                                                   << int(Qt::TextEditorInteraction);
6339     QTest::newRow("noninteractive, noflags") << 0 << int(Qt::NoTextInteraction);
6340     QTest::newRow("noninteractive, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::NoTextInteraction);
6341     QTest::newRow("noninteractive, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::NoTextInteraction);
6342     QTest::newRow("noninteractive, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
6343                                                           << int(Qt::NoTextInteraction);
6344 }
6345
6346 void tst_QGraphicsItem::task240400_clickOnTextItem()
6347 {
6348     QFETCH(int, flags);
6349     QFETCH(int, textFlags);
6350
6351     QGraphicsScene scene;
6352     QEvent activate(QEvent::WindowActivate);
6353     QApplication::sendEvent(&scene, &activate);
6354
6355     QGraphicsTextItem *item = scene.addText("Hello");
6356     item->setFlags(QGraphicsItem::GraphicsItemFlags(flags));
6357     item->setTextInteractionFlags(Qt::TextInteractionFlags(textFlags));
6358     bool focusable = (item->flags() & QGraphicsItem::ItemIsFocusable);
6359     QVERIFY(textFlags ? focusable : !focusable);
6360
6361     int column = item->textCursor().columnNumber();
6362     QCOMPARE(column, 0);
6363
6364     QVERIFY(!item->hasFocus());
6365
6366     // Click in the top-left corner of the item
6367     {
6368         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6369         event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
6370         event.setButton(Qt::LeftButton);
6371         event.setButtons(Qt::LeftButton);
6372         QApplication::sendEvent(&scene, &event);
6373     }
6374     if (flags || textFlags)
6375         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6376     else
6377         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
6378     {
6379         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
6380         event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
6381         event.setButton(Qt::LeftButton);
6382         event.setButtons(0);
6383         QApplication::sendEvent(&scene, &event);
6384     }
6385     if (textFlags)
6386         QVERIFY(item->hasFocus());
6387     else
6388         QVERIFY(!item->hasFocus());
6389     QVERIFY(!scene.mouseGrabberItem());
6390     bool selectable = (flags & QGraphicsItem::ItemIsSelectable);
6391     QVERIFY(selectable ? item->isSelected() : !item->isSelected());
6392
6393     // Now click in the middle and check that the cursor moved.
6394     {
6395         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6396         event.setScenePos(item->sceneBoundingRect().center());
6397         event.setButton(Qt::LeftButton);
6398         event.setButtons(Qt::LeftButton);
6399         QApplication::sendEvent(&scene, &event);
6400     }
6401     if (flags || textFlags)
6402         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6403     else
6404         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
6405     {
6406         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
6407         event.setScenePos(item->sceneBoundingRect().center());
6408         event.setButton(Qt::LeftButton);
6409         event.setButtons(0);
6410         QApplication::sendEvent(&scene, &event);
6411     }
6412     if (textFlags)
6413         QVERIFY(item->hasFocus());
6414     else
6415         QVERIFY(!item->hasFocus());
6416     QVERIFY(!scene.mouseGrabberItem());
6417
6418     QVERIFY(selectable ? item->isSelected() : !item->isSelected());
6419
6420     //
6421     if (textFlags & Qt::TextEditorInteraction)
6422         QVERIFY(item->textCursor().columnNumber() > column);
6423     else
6424         QCOMPARE(item->textCursor().columnNumber(), 0);
6425 }
6426
6427 class TextItem : public QGraphicsSimpleTextItem
6428 {
6429 public:
6430     TextItem(const QString& text) : QGraphicsSimpleTextItem(text)
6431     {
6432         updates = 0;
6433     }
6434
6435     void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
6436     {
6437         updates++;
6438         QGraphicsSimpleTextItem::paint(painter, option, widget);
6439     }
6440
6441     int updates;
6442 };
6443
6444 void tst_QGraphicsItem::ensureUpdateOnTextItem()
6445 {
6446     QGraphicsScene scene;
6447     QGraphicsView view(&scene);
6448     view.show();
6449     QTest::qWaitForWindowShown(&view);
6450     QTest::qWait(25);
6451     TextItem *text1 = new TextItem(QLatin1String("123"));
6452     scene.addItem(text1);
6453     qApp->processEvents();
6454     QTRY_COMPARE(text1->updates,1);
6455
6456     //same bouding rect but we have to update
6457     text1->setText(QLatin1String("321"));
6458     qApp->processEvents();
6459     QTRY_COMPARE(text1->updates,2);
6460 }
6461
6462 void tst_QGraphicsItem::task243707_addChildBeforeParent()
6463 {
6464     // Task reports that adding the child before the parent leads to an
6465     // inconsistent internal state that can cause a crash.  This test shows
6466     // one such crash.
6467     QGraphicsScene scene;
6468     QGraphicsWidget *widget = new QGraphicsWidget;
6469     QGraphicsWidget *widget2 = new QGraphicsWidget(widget);
6470     scene.addItem(widget2);
6471     QVERIFY(!widget2->parentItem());
6472     scene.addItem(widget);
6473     QVERIFY(!widget->commonAncestorItem(widget2));
6474     QVERIFY(!widget2->commonAncestorItem(widget));
6475 }
6476
6477 void tst_QGraphicsItem::task197802_childrenVisibility()
6478 {
6479     QGraphicsScene scene;
6480     QGraphicsRectItem item(QRectF(0,0,20,20));
6481
6482     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(0,0,10,10), &item);
6483     scene.addItem(&item);
6484
6485     //freshly created: both visible
6486     QVERIFY(item.isVisible());
6487     QVERIFY(item2->isVisible());
6488
6489     //hide child: parent visible, child not
6490     item2->hide();
6491     QVERIFY(item.isVisible());
6492     QVERIFY(!item2->isVisible());
6493
6494     //hide parent: parent and child invisible
6495     item.hide();
6496     QVERIFY(!item.isVisible());
6497     QVERIFY(!item2->isVisible());
6498
6499     //ask to show the child: parent and child invisible anyways
6500     item2->show();
6501     QVERIFY(!item.isVisible());
6502     QVERIFY(!item2->isVisible());
6503
6504     //show the parent: both parent and child visible
6505     item.show();
6506     QVERIFY(item.isVisible());
6507     QVERIFY(item2->isVisible());
6508
6509     delete item2;
6510 }
6511
6512 void tst_QGraphicsItem::boundingRegion_data()
6513 {
6514     QTest::addColumn<QLineF>("line");
6515     QTest::addColumn<qreal>("granularity");
6516     QTest::addColumn<QTransform>("transform");
6517     QTest::addColumn<QRegion>("expectedRegion");
6518
6519     QTest::newRow("(0, 0, 10, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.0) << QTransform()
6520                                                                         << QRegion(QRect(0, 0, 10, 10));
6521 #if 0
6522     {
6523         QRegion r;
6524         r += QRect(0, 0, 6, 2);
6525         r += QRect(0, 2, 8, 2);
6526         r += QRect(0, 4, 10, 2);
6527         r += QRect(2, 6, 8, 2);
6528         r += QRect(4, 8, 6, 2);
6529         QTest::newRow("(0, 0, 10, 10) | 0.5 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.5) << QTransform() << r;
6530     }
6531     {
6532         QRegion r;
6533         r += QRect(0, 0, 4, 1); r += QRect(0, 1, 5, 1); r += QRect(0, 2, 6, 1);
6534         r += QRect(0, 3, 7, 1); r += QRect(1, 4, 7, 1); r += QRect(2, 5, 7, 1);
6535         r += QRect(3, 6, 7, 1); r += QRect(4, 7, 6, 1); r += QRect(5, 8, 5, 1);
6536         r += QRect(6, 9, 4, 1);
6537         QTest::newRow("(0, 0, 10, 10) | 1.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(1.0) << QTransform() << r;
6538     }
6539 #endif
6540     QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform()
6541                                                                        << QRegion(QRect(0, 0, 10, 1));
6542     QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform()
6543                                                                       << QRegion(QRect(0, 0, 10, 1));
6544     QTest::newRow("(0, 0, 10, 0) | 1.0 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(1.0) << QTransform()
6545                                                                       << QRegion(QRect(0, 0, 10, 1));
6546     QTest::newRow("(0, 0, 0, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.0) << QTransform()
6547                                                                        << QRegion(QRect(0, 0, 1, 10));
6548     QTest::newRow("(0, 0, 0, 10) | 0.5 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.5) << QTransform()
6549                                                                       << QRegion(QRect(0, 0, 1, 10));
6550     QTest::newRow("(0, 0, 0, 10) | 1.0 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(1.0) << QTransform()
6551                                                                       << QRegion(QRect(0, 0, 1, 10));
6552 }
6553
6554 void tst_QGraphicsItem::boundingRegion()
6555 {
6556     QFETCH(QLineF, line);
6557     QFETCH(qreal, granularity);
6558     QFETCH(QTransform, transform);
6559     QFETCH(QRegion, expectedRegion);
6560
6561     QGraphicsLineItem item(line);
6562     QCOMPARE(item.boundingRegionGranularity(), qreal(0.0));
6563     item.setBoundingRegionGranularity(granularity);
6564     QCOMPARE(item.boundingRegionGranularity(), granularity);
6565     QCOMPARE(item.boundingRegion(transform), expectedRegion);
6566 }
6567
6568 void tst_QGraphicsItem::itemTransform_parentChild()
6569 {
6570     QGraphicsScene scene;
6571     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6572     QGraphicsItem *child = scene.addRect(0, 0, 100, 100);
6573     child->setParentItem(parent);
6574     child->setPos(10, 10);
6575     child->scale(2, 2);
6576     child->rotate(90);
6577
6578     QCOMPARE(child->itemTransform(parent).map(QPointF(10, 10)), QPointF(-10, 30));
6579     QCOMPARE(parent->itemTransform(child).map(QPointF(-10, 30)), QPointF(10, 10));
6580 }
6581
6582 void tst_QGraphicsItem::itemTransform_siblings()
6583 {
6584     QGraphicsScene scene;
6585     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6586     QGraphicsItem *brother = scene.addRect(0, 0, 100, 100);
6587     QGraphicsItem *sister = scene.addRect(0, 0, 100, 100);
6588     parent->scale(10, 5);
6589     parent->rotate(-180);
6590     parent->shear(2, 3);
6591
6592     brother->setParentItem(parent);
6593     sister->setParentItem(parent);
6594
6595     brother->setPos(10, 10);
6596     brother->scale(2, 2);
6597     brother->rotate(90);
6598     sister->setPos(10, 10);
6599     sister->scale(2, 2);
6600     sister->rotate(90);
6601
6602     QCOMPARE(brother->itemTransform(sister).map(QPointF(10, 10)), QPointF(10, 10));
6603     QCOMPARE(sister->itemTransform(brother).map(QPointF(10, 10)), QPointF(10, 10));
6604 }
6605
6606 void tst_QGraphicsItem::itemTransform_unrelated()
6607 {
6608     QGraphicsScene scene;
6609     QGraphicsItem *stranger1 = scene.addRect(0, 0, 100, 100);
6610     QGraphicsItem *stranger2 = scene.addRect(0, 0, 100, 100);
6611     stranger1->setPos(10, 10);
6612     stranger1->scale(2, 2);
6613     stranger1->rotate(90);
6614     stranger2->setPos(10, 10);
6615     stranger2->scale(2, 2);
6616     stranger2->rotate(90);
6617
6618     QCOMPARE(stranger1->itemTransform(stranger2).map(QPointF(10, 10)), QPointF(10, 10));
6619     QCOMPARE(stranger2->itemTransform(stranger1).map(QPointF(10, 10)), QPointF(10, 10));
6620 }
6621
6622 void tst_QGraphicsItem::opacity_data()
6623 {
6624     QTest::addColumn<qreal>("p_opacity");
6625     QTest::addColumn<int>("p_opacityFlags");
6626     QTest::addColumn<qreal>("c1_opacity");
6627     QTest::addColumn<int>("c1_opacityFlags");
6628     QTest::addColumn<qreal>("c2_opacity");
6629     QTest::addColumn<int>("c2_opacityFlags");
6630     QTest::addColumn<qreal>("p_effectiveOpacity");
6631     QTest::addColumn<qreal>("c1_effectiveOpacity");
6632     QTest::addColumn<qreal>("c2_effectiveOpacity");
6633     QTest::addColumn<qreal>("c3_effectiveOpacity");
6634
6635     // Modify the opacity and see how it propagates
6636     QTest::newRow("A: 1.0 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0
6637                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6638     QTest::newRow("B: 0.5 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0
6639                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6640     QTest::newRow("C: 0.5 0 0.1 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(0.1) << 0 << qreal(1.0) << 0
6641                                                         << qreal(0.5) << qreal(0.05) << qreal(0.05) << qreal(0.05);
6642     QTest::newRow("D: 0.0 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0
6643                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6644
6645     // Parent doesn't propagate to children - now modify the opacity and see how it propagates
6646     int flags = QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6647     QTest::newRow("E: 1.0 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << flags << qreal(1.0) << 0 << qreal(1.0) << 0
6648                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6649     QTest::newRow("F: 0.5 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << flags << qreal(1.0) << 0 << qreal(1.0) << 0
6650                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6651     QTest::newRow("G: 0.5 2 0.1 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << flags << qreal(0.1) << 0 << qreal(1.0) << 0
6652                                                         << qreal(0.5) << qreal(0.1) << qreal(0.1) << qreal(0.1);
6653     QTest::newRow("H: 0.0 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << flags << qreal(1.0) << 0 << qreal(1.0) << 0
6654                                                         << qreal(0.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6655
6656     // Child ignores parent - now modify the opacity and see how it propagates
6657     flags = QGraphicsItem::ItemIgnoresParentOpacity;
6658     QTest::newRow("I: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 << qreal(1.0) << flags << qreal(1.0) << 0
6659                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6660     QTest::newRow("J: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(0.5) << flags << qreal(0.5) << 0
6661                                                         << qreal(0.5) << qreal(0.5) << qreal(0.25) << qreal(0.25);
6662     QTest::newRow("K: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.2) << 0 << qreal(0.2) << flags << qreal(0.2) << 0
6663                                                         << qreal(0.2) << qreal(0.2) << qreal(0.04) << qreal(0.04);
6664     QTest::newRow("L: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << 0 << qreal(0.0) << flags << qreal(0.0) << 0
6665                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6666
6667     // Child ignores parent and doesn't propagate - now modify the opacity and see how it propagates
6668     flags = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6669     QTest::newRow("M: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6670                                                         << qreal(1.0) << flags // c1 (no prop)
6671                                                         << qreal(1.0) << 0 // c2
6672                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6673     QTest::newRow("M: 0.5 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6674                                                         << qreal(1.0) << flags // c1 (no prop)
6675                                                         << qreal(1.0) << 0 // c2
6676                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6677     QTest::newRow("M: 0.5 0 0.5 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6678                                                         << qreal(0.5) << flags // c1 (no prop)
6679                                                         << qreal(1.0) << 0 // c2
6680                                                         << qreal(0.5) << qreal(0.5) << qreal(1.0) << qreal(1.0);
6681     QTest::newRow("M: 0.5 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6682                                                         << qreal(0.5) << flags // c1 (no prop)
6683                                                         << qreal(0.5) << 0 // c2
6684                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6685     QTest::newRow("M: 1.0 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6686                                                         << qreal(0.5) << flags // c1 (no prop)
6687                                                         << qreal(0.5) << 0 // c2
6688                                                         << qreal(1.0) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6689 }
6690
6691 void tst_QGraphicsItem::opacity()
6692 {
6693     QFETCH(qreal, p_opacity);
6694     QFETCH(int, p_opacityFlags);
6695     QFETCH(qreal, p_effectiveOpacity);
6696     QFETCH(qreal, c1_opacity);
6697     QFETCH(int, c1_opacityFlags);
6698     QFETCH(qreal, c1_effectiveOpacity);
6699     QFETCH(qreal, c2_opacity);
6700     QFETCH(int, c2_opacityFlags);
6701     QFETCH(qreal, c2_effectiveOpacity);
6702     QFETCH(qreal, c3_effectiveOpacity);
6703
6704     QGraphicsRectItem *p = new QGraphicsRectItem;
6705     QGraphicsRectItem *c1 = new QGraphicsRectItem(p);
6706     QGraphicsRectItem *c2 = new QGraphicsRectItem(c1);
6707     QGraphicsRectItem *c3 = new QGraphicsRectItem(c2);
6708
6709     QCOMPARE(p->opacity(), qreal(1.0));
6710     QCOMPARE(p->effectiveOpacity(), qreal(1.0));
6711     int opacityMask = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6712     QVERIFY(!(p->flags() & opacityMask));
6713
6714     p->setOpacity(p_opacity);
6715     c1->setOpacity(c1_opacity);
6716     c2->setOpacity(c2_opacity);
6717     p->setFlags(QGraphicsItem::GraphicsItemFlags(p->flags() | p_opacityFlags));
6718     c1->setFlags(QGraphicsItem::GraphicsItemFlags(c1->flags() | c1_opacityFlags));
6719     c2->setFlags(QGraphicsItem::GraphicsItemFlags(c2->flags() | c2_opacityFlags));
6720
6721     QCOMPARE(int(p->flags() & opacityMask), p_opacityFlags);
6722     QCOMPARE(int(c1->flags() & opacityMask), c1_opacityFlags);
6723     QCOMPARE(int(c2->flags() & opacityMask), c2_opacityFlags);
6724     QCOMPARE(p->opacity(), p_opacity);
6725     QCOMPARE(p->effectiveOpacity(), p_effectiveOpacity);
6726     QCOMPARE(c1->effectiveOpacity(), c1_effectiveOpacity);
6727     QCOMPARE(c2->effectiveOpacity(), c2_effectiveOpacity);
6728     QCOMPARE(c3->effectiveOpacity(), c3_effectiveOpacity);
6729 }
6730
6731 void tst_QGraphicsItem::opacity2()
6732 {
6733     EventTester *parent = new EventTester;
6734     EventTester *child = new EventTester(parent);
6735     EventTester *grandChild = new EventTester(child);
6736
6737     QGraphicsScene scene;
6738     scene.addItem(parent);
6739
6740     MyGraphicsView view(&scene);
6741     if(PlatformQuirks::isAutoMaximizing())
6742         view.showFullScreen();
6743     else
6744         view.show();
6745     QTest::qWaitForWindowShown(&view);
6746     QTRY_VERIFY(view.repaints >= 1);
6747
6748 #define RESET_REPAINT_COUNTERS \
6749     parent->repaints = 0; \
6750     child->repaints = 0; \
6751     grandChild->repaints = 0; \
6752     view.repaints = 0;
6753
6754     RESET_REPAINT_COUNTERS
6755
6756     child->setOpacity(0.0);
6757     QTest::qWait(10);
6758     QTRY_COMPARE(view.repaints, 1);
6759     QCOMPARE(parent->repaints, 1);
6760     QCOMPARE(child->repaints, 0);
6761     QCOMPARE(grandChild->repaints, 0);
6762
6763     RESET_REPAINT_COUNTERS
6764
6765     child->setOpacity(1.0);
6766     QTest::qWait(10);
6767     QTRY_COMPARE(view.repaints, 1);
6768     QCOMPARE(parent->repaints, 1);
6769     QCOMPARE(child->repaints, 1);
6770     QCOMPARE(grandChild->repaints, 1);
6771
6772     RESET_REPAINT_COUNTERS
6773
6774     parent->setOpacity(0.0);
6775     QTest::qWait(10);
6776     QTRY_COMPARE(view.repaints, 1);
6777     QCOMPARE(parent->repaints, 0);
6778     QCOMPARE(child->repaints, 0);
6779     QCOMPARE(grandChild->repaints, 0);
6780
6781     RESET_REPAINT_COUNTERS
6782
6783     parent->setOpacity(1.0);
6784     QTest::qWait(10);
6785     QTRY_COMPARE(view.repaints, 1);
6786     QCOMPARE(parent->repaints, 1);
6787     QCOMPARE(child->repaints, 1);
6788     QCOMPARE(grandChild->repaints, 1);
6789
6790     grandChild->setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
6791     RESET_REPAINT_COUNTERS
6792
6793     child->setOpacity(0.0);
6794     QTest::qWait(10);
6795     QTRY_COMPARE(view.repaints, 1);
6796     QCOMPARE(parent->repaints, 1);
6797     QCOMPARE(child->repaints, 0);
6798     QCOMPARE(grandChild->repaints, 1);
6799
6800     RESET_REPAINT_COUNTERS
6801
6802     child->setOpacity(0.0); // Already 0.0; no change.
6803     QTest::qWait(10);
6804     QTRY_COMPARE(view.repaints, 0);
6805     QCOMPARE(parent->repaints, 0);
6806     QCOMPARE(child->repaints, 0);
6807     QCOMPARE(grandChild->repaints, 0);
6808 }
6809
6810 void tst_QGraphicsItem::opacityZeroUpdates()
6811 {
6812     EventTester *parent = new EventTester;
6813     EventTester *child = new EventTester(parent);
6814
6815     child->setPos(10, 10);
6816
6817     QGraphicsScene scene;
6818     scene.addItem(parent);
6819
6820     MyGraphicsView view(&scene);
6821     view.show();
6822     QTest::qWaitForWindowShown(&view);
6823     QTRY_VERIFY(view.repaints > 0);
6824
6825     view.reset();
6826     parent->setOpacity(0.0);
6827
6828     QTest::qWait(20);
6829
6830     // transforming items bounding rect to view coordinates
6831     const QRect childDeviceBoundingRect = child->deviceTransform(view.viewportTransform())
6832                                            .mapRect(child->boundingRect()).toRect();
6833     const QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
6834                                            .mapRect(parent->boundingRect()).toRect();
6835
6836     QRegion expectedRegion = parentDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6837     expectedRegion += childDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6838
6839     COMPARE_REGIONS(view.paintedRegion, expectedRegion);
6840 }
6841
6842 class StacksBehindParentHelper : public QGraphicsRectItem
6843 {
6844 public:
6845     StacksBehindParentHelper(QList<QGraphicsItem *> *paintedItems, const QRectF &rect, QGraphicsItem *parent = 0)
6846         : QGraphicsRectItem(rect, parent), paintedItems(paintedItems)
6847     { }
6848
6849     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
6850     {
6851         QGraphicsRectItem::paint(painter, option, widget);
6852         paintedItems->append(this);
6853     }
6854
6855 private:
6856     QList<QGraphicsItem *> *paintedItems;
6857 };
6858
6859 void tst_QGraphicsItem::itemStacksBehindParent()
6860 {
6861     StacksBehindParentHelper *parent1 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6862     StacksBehindParentHelper *child11 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent1);
6863     StacksBehindParentHelper *grandChild111 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child11);
6864     StacksBehindParentHelper *child12 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent1);
6865     StacksBehindParentHelper *grandChild121 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child12);
6866
6867     StacksBehindParentHelper *parent2 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6868     StacksBehindParentHelper *child21 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent2);
6869     StacksBehindParentHelper *grandChild211 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child21);
6870     StacksBehindParentHelper *child22 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent2);
6871     StacksBehindParentHelper *grandChild221 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child22);
6872
6873     parent1->setData(0, "parent1");
6874     child11->setData(0, "child11");
6875     grandChild111->setData(0, "grandChild111");
6876     child12->setData(0, "child12");
6877     grandChild121->setData(0, "grandChild121");
6878     parent2->setData(0, "parent2");
6879     child21->setData(0, "child21");
6880     grandChild211->setData(0, "grandChild211");
6881     child22->setData(0, "child22");
6882     grandChild221->setData(0, "grandChild221");
6883
6884     // Disambiguate siblings
6885     parent1->setZValue(1);
6886     child11->setZValue(1);
6887     child21->setZValue(1);
6888
6889     QGraphicsScene scene;
6890     scene.addItem(parent1);
6891     scene.addItem(parent2);
6892
6893     QGraphicsView view(&scene);
6894     view.show();
6895     QTest::qWaitForWindowShown(&view);
6896     QTRY_VERIFY(!paintedItems.isEmpty());
6897     QTest::qWait(100);
6898     paintedItems.clear();
6899     view.viewport()->update();
6900     QApplication::processEvents();
6901     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6902                                            << grandChild111 << child11
6903                                            << grandChild121 << child12 << parent1
6904                                            << grandChild211 << child21
6905                                            << grandChild221 << child22 << parent2));
6906     QTRY_COMPARE(paintedItems, QList<QGraphicsItem *>()
6907              << parent2 << child22 << grandChild221
6908              << child21 << grandChild211
6909              << parent1 << child12 << grandChild121
6910              << child11 << grandChild111);
6911
6912     child11->setFlag(QGraphicsItem::ItemStacksBehindParent);
6913     scene.update();
6914     paintedItems.clear();
6915     QApplication::processEvents();
6916
6917     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6918                                            << grandChild121 << child12 << parent1
6919                                            << grandChild111 << child11
6920                                            << grandChild211 << child21
6921                                            << grandChild221 << child22 << parent2));
6922     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6923              << parent2 << child22 << grandChild221
6924              << child21 << grandChild211
6925              << child11 << grandChild111
6926              << parent1 << child12 << grandChild121);
6927
6928     child12->setFlag(QGraphicsItem::ItemStacksBehindParent);
6929     paintedItems.clear();
6930     scene.update();
6931     QApplication::processEvents();
6932
6933     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6934                                            << parent1 << grandChild111 << child11
6935                                            << grandChild121 << child12
6936                                            << grandChild211 << child21
6937                                            << grandChild221 << child22 << parent2));
6938     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6939              << parent2 << child22 << grandChild221
6940              << child21 << grandChild211
6941              << child12 << grandChild121
6942              << child11 << grandChild111 << parent1);
6943 }
6944
6945 class ClippingAndTransformsScene : public QGraphicsScene
6946 {
6947 public:
6948     QList<QGraphicsItem *> drawnItems;
6949 protected:
6950     void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[],
6951                    const QStyleOptionGraphicsItem options[], QWidget *widget = 0)
6952     {
6953         drawnItems.clear();
6954         for (int i = 0; i < numItems; ++i)
6955             drawnItems << items[i];
6956         QGraphicsScene::drawItems(painter, numItems, items, options, widget);
6957     }
6958 };
6959
6960 void tst_QGraphicsItem::nestedClipping()
6961 {
6962     ClippingAndTransformsScene scene;
6963     scene.setSceneRect(-50, -50, 200, 200);
6964
6965     QGraphicsRectItem *root = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6966     root->setBrush(QColor(0, 0, 255));
6967     root->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6968     QGraphicsRectItem *l1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6969     l1->setParentItem(root);
6970     l1->setPos(-50, 0);
6971     l1->setBrush(QColor(255, 0, 0));
6972     l1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6973     QGraphicsEllipseItem *l2 = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100));
6974     l2->setParentItem(l1);
6975     l2->setPos(50, 50);
6976     l2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6977     l2->setBrush(QColor(255, 255, 0));
6978     QGraphicsRectItem *l3 = new QGraphicsRectItem(QRectF(0, 0, 25, 25));
6979     l3->setParentItem(l2);
6980     l3->setBrush(QColor(0, 255, 0));
6981     l3->setPos(50 - 12, -12);
6982
6983     scene.addItem(root);
6984
6985     root->setData(0, "root");
6986     l1->setData(0, "l1");
6987     l2->setData(0, "l2");
6988     l3->setData(0, "l3");
6989
6990     QGraphicsView view(&scene);
6991     view.setOptimizationFlag(QGraphicsView::IndirectPainting);
6992     view.show();
6993     QTest::qWaitForWindowShown(&view);
6994     QTest::qWait(25);
6995
6996     QList<QGraphicsItem *> expected;
6997     expected << root << l1 << l2 << l3;
6998     QTRY_COMPARE(scene.drawnItems, expected);
6999
7000     QImage image(200, 200, QImage::Format_ARGB32_Premultiplied);
7001     image.fill(0);
7002
7003     QPainter painter(&image);
7004     scene.render(&painter);
7005     painter.end();
7006
7007     // Check transparent areas
7008     QCOMPARE(image.pixel(100, 25), qRgba(0, 0, 0, 0));
7009     QCOMPARE(image.pixel(100, 175), qRgba(0, 0, 0, 0));
7010     QCOMPARE(image.pixel(25, 100), qRgba(0, 0, 0, 0));
7011     QCOMPARE(image.pixel(175, 100), qRgba(0, 0, 0, 0));
7012     QCOMPARE(image.pixel(70, 80), qRgba(255, 0, 0, 255));
7013     QCOMPARE(image.pixel(80, 130), qRgba(255, 255, 0, 255));
7014     QCOMPARE(image.pixel(92, 105), qRgba(0, 255, 0, 255));
7015     QCOMPARE(image.pixel(105, 105), qRgba(0, 0, 255, 255));
7016 #if 0
7017     // Enable this to compare if the test starts failing.
7018     image.save("nestedClipping_reference.png");
7019 #endif
7020 }
7021
7022 class TransformDebugItem : public QGraphicsRectItem
7023 {
7024 public:
7025     TransformDebugItem()
7026         : QGraphicsRectItem(QRectF(-10, -10, 20, 20))
7027     {
7028         setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
7029     }
7030
7031     QTransform x;
7032
7033     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
7034                QWidget *widget = 0)
7035     {
7036         x = painter->worldTransform();
7037         QGraphicsRectItem::paint(painter, option, widget);
7038     }
7039 };
7040
7041 void tst_QGraphicsItem::nestedClippingTransforms()
7042 {
7043     TransformDebugItem *rootClipper = new TransformDebugItem;
7044     rootClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7045     TransformDebugItem *child = new TransformDebugItem;
7046     child->setParentItem(rootClipper);
7047     child->setPos(2, 2);
7048     TransformDebugItem *grandChildClipper = new TransformDebugItem;
7049     grandChildClipper->setParentItem(child);
7050     grandChildClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7051     grandChildClipper->setPos(4, 4);
7052     TransformDebugItem *greatGrandChild = new TransformDebugItem;
7053     greatGrandChild->setPos(2, 2);
7054     greatGrandChild->setParentItem(grandChildClipper);
7055     TransformDebugItem *grandChildClipper2 = new TransformDebugItem;
7056     grandChildClipper2->setParentItem(child);
7057     grandChildClipper2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7058     grandChildClipper2->setPos(8, 8);
7059     TransformDebugItem *greatGrandChild2 = new TransformDebugItem;
7060     greatGrandChild2->setPos(2, 2);
7061     greatGrandChild2->setParentItem(grandChildClipper2);
7062     TransformDebugItem *grandChildClipper3 = new TransformDebugItem;
7063     grandChildClipper3->setParentItem(child);
7064     grandChildClipper3->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7065     grandChildClipper3->setPos(12, 12);
7066     TransformDebugItem *greatGrandChild3 = new TransformDebugItem;
7067     greatGrandChild3->setPos(2, 2);
7068     greatGrandChild3->setParentItem(grandChildClipper3);
7069
7070     QGraphicsScene scene;
7071     scene.addItem(rootClipper);
7072
7073     QImage image(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
7074     image.fill(0);
7075     QPainter p(&image);
7076     scene.render(&p);
7077     p.end();
7078
7079     QCOMPARE(rootClipper->x, QTransform(1, 0, 0, 0, 1, 0, 10, 10, 1));
7080     QCOMPARE(child->x, QTransform(1, 0, 0, 0, 1, 0, 12, 12, 1));
7081     QCOMPARE(grandChildClipper->x, QTransform(1, 0, 0, 0, 1, 0, 16, 16, 1));
7082     QCOMPARE(greatGrandChild->x, QTransform(1, 0, 0, 0, 1, 0, 18, 18, 1));
7083     QCOMPARE(grandChildClipper2->x, QTransform(1, 0, 0, 0, 1, 0, 20, 20, 1));
7084     QCOMPARE(greatGrandChild2->x, QTransform(1, 0, 0, 0, 1, 0, 22, 22, 1));
7085     QCOMPARE(grandChildClipper3->x, QTransform(1, 0, 0, 0, 1, 0, 24, 24, 1));
7086     QCOMPARE(greatGrandChild3->x, QTransform(1, 0, 0, 0, 1, 0, 26, 26, 1));
7087 }
7088
7089 void tst_QGraphicsItem::sceneTransformCache()
7090 {
7091     // Test that an item's scene transform is updated correctly when the
7092     // parent is transformed.
7093     QGraphicsScene scene;
7094     QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
7095     QGraphicsRectItem *rect2 = scene.addRect(0, 0, 100, 100);
7096     rect2->setParentItem(rect);
7097     rect2->rotate(90);
7098     rect->translate(0, 50);
7099     QGraphicsView view(&scene);
7100     view.show();
7101 #ifdef Q_WS_X11
7102     qt_x11_wait_for_window_manager(&view);
7103 #endif
7104
7105     rect->translate(0, 100);
7106     QTransform x;
7107     x.translate(0, 150);
7108     x.rotate(90);
7109     QCOMPARE(rect2->sceneTransform(), x);
7110
7111     scene.removeItem(rect);
7112
7113     //Crazy use case : rect4 child of rect3 so the transformation of rect4 will be cached.Good!
7114     //We remove rect4 from the scene, then the validTransform bit flag is set to 0 and the index of the cache
7115     //add to the freeTransformSlots. The problem was that sceneTransformIndex was not set to -1 so if a new item arrive
7116     //with a child (rect6) that will be cached then it will take the freeSlot (ex rect4) and put it his transform. But if rect4 is
7117     //added back to the scene then it will set the transform to his old sceneTransformIndex value that will erase the new
7118     //value of rect6 so rect6 transform will be wrong.
7119     QGraphicsRectItem *rect3 = scene.addRect(0, 0, 100, 100);
7120     QGraphicsRectItem *rect4 = scene.addRect(0, 0, 100, 100);
7121     rect3->setPos(QPointF(10,10));
7122
7123     rect4->setParentItem(rect3);
7124     rect4->setPos(QPointF(10,10));
7125
7126     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(20,20));
7127
7128     scene.removeItem(rect4);
7129     //rect4 transform is local only
7130     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7131
7132     QGraphicsRectItem *rect5 = scene.addRect(0, 0, 100, 100);
7133     QGraphicsRectItem *rect6 = scene.addRect(0, 0, 100, 100);
7134     rect5->setPos(QPointF(20,20));
7135
7136     rect6->setParentItem(rect5);
7137     rect6->setPos(QPointF(10,10));
7138     //test if rect6 transform is ok
7139     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7140
7141     scene.addItem(rect4);
7142
7143     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7144     //test if rect6 transform is still correct
7145     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7146 }
7147
7148 void tst_QGraphicsItem::tabChangesFocus_data()
7149 {
7150     QTest::addColumn<bool>("tabChangesFocus");
7151     QTest::newRow("tab changes focus") << true;
7152     QTest::newRow("tab doesn't change focus") << false;
7153 }
7154
7155 void tst_QGraphicsItem::tabChangesFocus()
7156 {
7157     QFETCH(bool, tabChangesFocus);
7158
7159     QGraphicsScene scene;
7160     QGraphicsTextItem *item = scene.addText("Hello");
7161     item->setTabChangesFocus(tabChangesFocus);
7162     item->setTextInteractionFlags(Qt::TextEditorInteraction);
7163     item->setFocus();
7164
7165     QDial *dial1 = new QDial;
7166     QGraphicsView *view = new QGraphicsView(&scene);
7167
7168     QDial *dial2 = new QDial;
7169     QVBoxLayout *layout = new QVBoxLayout;
7170     layout->addWidget(dial1);
7171     layout->addWidget(view);
7172     layout->addWidget(dial2);
7173
7174     QWidget widget;
7175     widget.setLayout(layout);
7176     widget.show();
7177     QTest::qWaitForWindowShown(&widget);
7178     QTest::qWait(2000);
7179
7180     QTRY_VERIFY(scene.isActive());
7181
7182     dial1->setFocus();
7183     QTest::qWait(15);
7184     QTRY_VERIFY(dial1->hasFocus());
7185
7186     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7187     QTest::qWait(15);
7188     QTRY_VERIFY(view->hasFocus());
7189     QTRY_VERIFY(item->hasFocus());
7190
7191     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7192     QTest::qWait(15);
7193
7194     if (tabChangesFocus) {
7195         QTRY_VERIFY(!view->hasFocus());
7196         QTRY_VERIFY(!item->hasFocus());
7197         QTRY_VERIFY(dial2->hasFocus());
7198     } else {
7199         QTRY_VERIFY(view->hasFocus());
7200         QTRY_VERIFY(item->hasFocus());
7201         QCOMPARE(item->toPlainText(), QString("\tHello"));
7202     }
7203 }
7204
7205 void tst_QGraphicsItem::cacheMode()
7206 {
7207     QGraphicsScene scene(0, 0, 100, 100);
7208     QGraphicsView view(&scene);
7209     view.resize(150, 150);
7210     view.show();
7211     QApplication::setActiveWindow(&view);
7212     QTest::qWaitForWindowShown(&view);
7213
7214     // Increase the probability of window activation
7215     // not causing another repaint of test items.
7216     QTest::qWait(50);
7217
7218     EventTester *tester = new EventTester;
7219     EventTester *testerChild = new EventTester;
7220     testerChild->setParentItem(tester);
7221     EventTester *testerChild2 = new EventTester;
7222     testerChild2->setParentItem(testerChild);
7223     testerChild2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
7224
7225     scene.addItem(tester);
7226     QTest::qWait(10);
7227
7228     for (int i = 0; i < 2; ++i) {
7229         // No visual change.
7230         QTRY_COMPARE(tester->repaints, 1);
7231         QCOMPARE(testerChild->repaints, 1);
7232         QCOMPARE(testerChild2->repaints, 1);
7233         tester->setCacheMode(QGraphicsItem::NoCache);
7234         testerChild->setCacheMode(QGraphicsItem::NoCache);
7235         testerChild2->setCacheMode(QGraphicsItem::NoCache);
7236         QTest::qWait(25);
7237         QTRY_COMPARE(tester->repaints, 1);
7238         QCOMPARE(testerChild->repaints, 1);
7239         QCOMPARE(testerChild2->repaints, 1);
7240         tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7241         testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7242         testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7243         QTest::qWait(25);
7244     }
7245
7246     // The first move causes a repaint as the item is painted into its pixmap.
7247     // (Only occurs if the item has previously been painted without cache).
7248     tester->setPos(10, 10);
7249     testerChild->setPos(10, 10);
7250     testerChild2->setPos(10, 10);
7251     QTest::qWait(25);
7252     QTRY_COMPARE(tester->repaints, 2);
7253     QCOMPARE(testerChild->repaints, 2);
7254     QCOMPARE(testerChild2->repaints, 2);
7255
7256     // Consecutive moves should not repaint.
7257     tester->setPos(20, 20);
7258     testerChild->setPos(20, 20);
7259     testerChild2->setPos(20, 20);
7260     QTest::qWait(250);
7261     QCOMPARE(tester->repaints, 2);
7262     QCOMPARE(testerChild->repaints, 2);
7263     QCOMPARE(testerChild2->repaints, 2);
7264
7265     // Translating does not result in a repaint.
7266     tester->translate(10, 10);
7267     QTest::qWait(25);
7268     QTRY_COMPARE(tester->repaints, 2);
7269     QCOMPARE(testerChild->repaints, 2);
7270     QCOMPARE(testerChild2->repaints, 2);
7271
7272     // Rotating results in a repaint.
7273     tester->rotate(45);
7274     QTest::qWait(25);
7275     QTRY_COMPARE(tester->repaints, 3);
7276     QCOMPARE(testerChild->repaints, 3);
7277     QCOMPARE(testerChild2->repaints, 2);
7278
7279     // Change to ItemCoordinateCache (triggers repaint).
7280     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7281     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7282     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7283     QTest::qWait(25);
7284     QTRY_COMPARE(tester->repaints, 4);
7285     QCOMPARE(testerChild->repaints, 4);
7286     QCOMPARE(testerChild2->repaints, 3);
7287
7288     // Rotating items with ItemCoordinateCache doesn't cause a repaint.
7289     tester->rotate(22);
7290     testerChild->rotate(22);
7291     testerChild2->rotate(22);
7292     QTest::qWait(25);
7293     QTRY_COMPARE(tester->repaints, 4);
7294     QTRY_COMPARE(testerChild->repaints, 4);
7295     QTRY_COMPARE(testerChild2->repaints, 3);
7296     tester->resetTransform();
7297     testerChild->resetTransform();
7298     testerChild2->resetTransform();
7299
7300     // Explicit update causes a repaint.
7301     tester->update(0, 0, 5, 5);
7302     QTest::qWait(25);
7303     QTRY_COMPARE(tester->repaints, 5);
7304     QCOMPARE(testerChild->repaints, 4);
7305     QCOMPARE(testerChild2->repaints, 3);
7306
7307     // Updating outside the item's bounds does not cause a repaint.
7308     tester->update(10, 10, 5, 5);
7309     QTest::qWait(25);
7310     QTRY_COMPARE(tester->repaints, 5);
7311     QCOMPARE(testerChild->repaints, 4);
7312     QCOMPARE(testerChild2->repaints, 3);
7313
7314     // Resizing an item should cause a repaint of that item. (because of
7315     // autosize).
7316     tester->setGeometry(QRectF(-15, -15, 30, 30));
7317     QTest::qWait(25);
7318     QTRY_COMPARE(tester->repaints, 6);
7319     QCOMPARE(testerChild->repaints, 4);
7320     QCOMPARE(testerChild2->repaints, 3);
7321
7322     // Set fixed size.
7323     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7324     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7325     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7326     QTest::qWait(20);
7327     QTRY_COMPARE(tester->repaints, 7);
7328     QCOMPARE(testerChild->repaints, 5);
7329     QCOMPARE(testerChild2->repaints, 4);
7330
7331     // Resizing the item should cause a repaint.
7332     testerChild->setGeometry(QRectF(-15, -15, 30, 30));
7333     QTest::qWait(25);
7334     QTRY_COMPARE(tester->repaints, 7);
7335     QCOMPARE(testerChild->repaints, 6);
7336     QCOMPARE(testerChild2->repaints, 4);
7337
7338     // Scaling the view does not cause a repaint.
7339     view.scale(0.7, 0.7);
7340     QTest::qWait(25);
7341     QTRY_COMPARE(tester->repaints, 7);
7342     QCOMPARE(testerChild->repaints, 6);
7343     QCOMPARE(testerChild2->repaints, 4);
7344
7345     // Switch to device coordinate cache.
7346     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7347     testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7348     testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7349     QTest::qWait(25);
7350     QTRY_COMPARE(tester->repaints, 8);
7351     QCOMPARE(testerChild->repaints, 7);
7352     QCOMPARE(testerChild2->repaints, 5);
7353
7354     // Scaling the view back should cause repaints for two of the items.
7355     view.setTransform(QTransform());
7356     QTest::qWait(25);
7357     QTRY_COMPARE(tester->repaints, 9);
7358     QCOMPARE(testerChild->repaints, 8);
7359     QCOMPARE(testerChild2->repaints, 5);
7360
7361     // Rotating the base item (perspective) should repaint two items.
7362     tester->setTransform(QTransform().rotate(10, Qt::XAxis));
7363     QTest::qWait(25);
7364     QTRY_COMPARE(tester->repaints, 10);
7365     QCOMPARE(testerChild->repaints, 9);
7366     QCOMPARE(testerChild2->repaints, 5);
7367
7368     // Moving the middle item should case a repaint even if it's a move,
7369     // because the parent is rotated with a perspective.
7370     testerChild->setPos(1, 1);
7371     QTest::qWait(25);
7372     QTRY_COMPARE(tester->repaints, 11);
7373     QTRY_COMPARE(testerChild->repaints, 10);
7374     QTRY_COMPARE(testerChild2->repaints, 5);
7375     tester->resetTransform();
7376
7377     // Make a huge item
7378     tester->setGeometry(QRectF(-4000, -4000, 8000, 8000));
7379     QTRY_COMPARE(tester->repaints, 12);
7380     QTRY_COMPARE(testerChild->repaints, 11);
7381     QTRY_COMPARE(testerChild2->repaints, 5);
7382
7383     // Move the large item - will cause a repaint as the
7384     // cache is clipped.
7385     tester->setPos(5, 0);
7386     QTRY_COMPARE(tester->repaints, 13);
7387     QTRY_COMPARE(testerChild->repaints, 11);
7388     QTRY_COMPARE(testerChild2->repaints, 5);
7389
7390     // Hiding and showing should invalidate the cache
7391     tester->hide();
7392     QTest::qWait(25);
7393     tester->show();
7394     QTRY_COMPARE(tester->repaints, 14);
7395     QTRY_COMPARE(testerChild->repaints, 12);
7396     QTRY_COMPARE(testerChild2->repaints, 6);
7397 }
7398
7399 void tst_QGraphicsItem::cacheMode2()
7400 {
7401     QGraphicsScene scene(0, 0, 100, 100);
7402     QGraphicsView view(&scene);
7403     view.resize(150, 150);
7404     view.show();
7405     QApplication::setActiveWindow(&view);
7406     QTest::qWaitForWindowShown(&view);
7407
7408     // Increase the probability of window activation
7409     // not causing another repaint of test items.
7410     QTest::qWait(50);
7411
7412     EventTester *tester = new EventTester;
7413     scene.addItem(tester);
7414     QTest::qWait(10);
7415     QTRY_COMPARE(tester->repaints, 1);
7416
7417     // Switching from NoCache to NoCache (no repaint)
7418     tester->setCacheMode(QGraphicsItem::NoCache);
7419     QTest::qWait(50);
7420     QTRY_COMPARE(tester->repaints, 1);
7421
7422     // Switching from NoCache to DeviceCoordinateCache (no repaint)
7423     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7424     QTest::qWait(50);
7425     QTRY_COMPARE(tester->repaints, 1);
7426
7427     // Switching from DeviceCoordinateCache to DeviceCoordinateCache (no repaint)
7428     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7429     QTest::qWait(50);
7430     QTRY_COMPARE(tester->repaints, 1);
7431
7432     // Switching from DeviceCoordinateCache to NoCache (no repaint)
7433     tester->setCacheMode(QGraphicsItem::NoCache);
7434     QTest::qWait(50);
7435     QTRY_COMPARE(tester->repaints, 1);
7436
7437     // Switching from NoCache to ItemCoordinateCache (repaint)
7438     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7439     QTest::qWait(50);
7440     QTRY_COMPARE(tester->repaints, 2);
7441
7442     // Switching from ItemCoordinateCache to ItemCoordinateCache (no repaint)
7443     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7444     QTest::qWait(50);
7445     QTRY_COMPARE(tester->repaints, 2);
7446
7447     // Switching from ItemCoordinateCache to ItemCoordinateCache with different size (repaint)
7448     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(100, 100));
7449     QTest::qWait(50);
7450     QTRY_COMPARE(tester->repaints, 3);
7451
7452     // Switching from ItemCoordinateCache to NoCache (repaint)
7453     tester->setCacheMode(QGraphicsItem::NoCache);
7454     QTest::qWait(50);
7455     QTRY_COMPARE(tester->repaints, 4);
7456
7457     // Switching from DeviceCoordinateCache to ItemCoordinateCache (repaint)
7458     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7459     QTest::qWait(50);
7460     QTRY_COMPARE(tester->repaints, 4);
7461     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7462     QTest::qWait(50);
7463     QTRY_COMPARE(tester->repaints, 5);
7464
7465     // Switching from ItemCoordinateCache to DeviceCoordinateCache (repaint)
7466     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7467     QTest::qWait(50);
7468     QTRY_COMPARE(tester->repaints, 6);
7469 }
7470
7471 void tst_QGraphicsItem::updateCachedItemAfterMove()
7472 {
7473     // A simple item that uses ItemCoordinateCache
7474     EventTester *tester = new EventTester;
7475     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7476
7477     // Add to a scene, show in a view, ensure it's painted and reset its
7478     // repaint counter.
7479     QGraphicsScene scene;
7480     scene.addItem(tester);
7481     QGraphicsView view(&scene);
7482     view.show();
7483     QTest::qWaitForWindowShown(&view);
7484
7485     QTest::qWait(12);
7486     QTRY_VERIFY(tester->repaints > 0);
7487     tester->repaints = 0;
7488
7489     // Move the item, should not cause repaints
7490     tester->setPos(10, 0);
7491     QTest::qWait(12);
7492     QCOMPARE(tester->repaints, 0);
7493
7494     // Move then update, should cause one repaint
7495     tester->setPos(20, 0);
7496     tester->update();
7497     QTest::qWait(12);
7498     QCOMPARE(tester->repaints, 1);
7499
7500     // Hiding the item doesn't cause a repaint
7501     tester->hide();
7502     QTest::qWait(12);
7503     QCOMPARE(tester->repaints, 1);
7504
7505     // Moving a hidden item doesn't cause a repaint
7506     tester->setPos(30, 0);
7507     tester->update();
7508     QTest::qWait(12);
7509     QCOMPARE(tester->repaints, 1);
7510 }
7511
7512 class Track : public QGraphicsRectItem
7513 {
7514 public:
7515     Track(const QRectF &rect)
7516         : QGraphicsRectItem(rect)
7517     {
7518         setAcceptHoverEvents(true);
7519     }
7520
7521     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7522     {
7523         QGraphicsRectItem::paint(painter, option, widget);
7524         painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1x%2\n%3x%4").arg(p.x()).arg(p.y()).arg(sp.x()).arg(sp.y()));
7525     }
7526
7527 protected:
7528     void hoverMoveEvent(QGraphicsSceneHoverEvent *event)
7529     {
7530         p = event->pos();
7531         sp = event->widget()->mapFromGlobal(event->screenPos());
7532         update();
7533     }
7534 private:
7535     QPointF p;
7536     QPoint sp;
7537 };
7538
7539 void tst_QGraphicsItem::deviceTransform_data()
7540 {
7541     QTest::addColumn<bool>("untransformable1");
7542     QTest::addColumn<bool>("untransformable2");
7543     QTest::addColumn<bool>("untransformable3");
7544     QTest::addColumn<qreal>("rotation1");
7545     QTest::addColumn<qreal>("rotation2");
7546     QTest::addColumn<qreal>("rotation3");
7547     QTest::addColumn<QTransform>("deviceX");
7548     QTest::addColumn<QPointF>("mapResult1");
7549     QTest::addColumn<QPointF>("mapResult2");
7550     QTest::addColumn<QPointF>("mapResult3");
7551
7552     QTest::newRow("nil") << false << false << false
7553                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7554                          << QTransform()
7555                          << QPointF(150, 150) << QPointF(250, 250) << QPointF(350, 350);
7556     QTest::newRow("deviceX rot 90") << false << false << false
7557                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7558                          << QTransform().rotate(90)
7559                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-350, 350);
7560     QTest::newRow("deviceX rot 90 100") << true << false << false
7561                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7562                          << QTransform().rotate(90)
7563                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7564     QTest::newRow("deviceX rot 90 010") << false << true << false
7565                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7566                          << QTransform().rotate(90)
7567                          << QPointF(-150, 150) << QPointF(-150, 250) << QPointF(-50, 350);
7568     QTest::newRow("deviceX rot 90 001") << false << false << true
7569                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7570                          << QTransform().rotate(90)
7571                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-250, 350);
7572     QTest::newRow("deviceX rot 90 111") << true << true << true
7573                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7574                          << QTransform().rotate(90)
7575                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7576     QTest::newRow("deviceX rot 90 101") << true << false << true
7577                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7578                          << QTransform().rotate(90)
7579                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7580 }
7581
7582 void tst_QGraphicsItem::deviceTransform()
7583 {
7584     QFETCH(bool, untransformable1);
7585     QFETCH(bool, untransformable2);
7586     QFETCH(bool, untransformable3);
7587     QFETCH(qreal, rotation1);
7588     QFETCH(qreal, rotation2);
7589     QFETCH(qreal, rotation3);
7590     QFETCH(QTransform, deviceX);
7591     QFETCH(QPointF, mapResult1);
7592     QFETCH(QPointF, mapResult2);
7593     QFETCH(QPointF, mapResult3);
7594
7595     QGraphicsScene scene;
7596     Track *rect1 = new Track(QRectF(0, 0, 100, 100));
7597     Track *rect2 = new Track(QRectF(0, 0, 100, 100));
7598     Track *rect3 = new Track(QRectF(0, 0, 100, 100));
7599     rect2->setParentItem(rect1);
7600     rect3->setParentItem(rect2);
7601     rect1->setPos(100, 100);
7602     rect2->setPos(100, 100);
7603     rect3->setPos(100, 100);
7604     rect1->rotate(rotation1);
7605     rect2->rotate(rotation2);
7606     rect3->rotate(rotation3);
7607     rect1->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable1);
7608     rect2->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable2);
7609     rect3->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable3);
7610     rect1->setBrush(Qt::red);
7611     rect2->setBrush(Qt::green);
7612     rect3->setBrush(Qt::blue);
7613     scene.addItem(rect1);
7614
7615     QCOMPARE(rect1->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult1);
7616     QCOMPARE(rect2->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult2);
7617     QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3);
7618 }
7619
7620 void tst_QGraphicsItem::update()
7621 {
7622     QGraphicsScene scene;
7623     scene.setSceneRect(-100, -100, 200, 200);
7624     QWidget topLevel;
7625     MyGraphicsView view(&scene,&topLevel);
7626
7627     topLevel.resize(300, 300);
7628     topLevel.show();
7629 #ifdef Q_WS_X11
7630     qt_x11_wait_for_window_manager(&view);
7631 #endif
7632     QTest::qWait(100);
7633
7634     EventTester *item = new EventTester;
7635     scene.addItem(item);
7636     QTest::qWait(100); // Make sure all pending updates are processed.
7637     item->repaints = 0;
7638
7639     item->update(); // Item marked as dirty
7640     scene.update(); // Entire scene marked as dirty
7641     qApp->processEvents();
7642     QCOMPARE(item->repaints, 1);
7643
7644     // Make sure the dirty state from the previous update is reset so that
7645     // the item don't think it is already dirty and discards this update.
7646     item->update();
7647     qApp->processEvents();
7648     QCOMPARE(item->repaints, 2);
7649
7650     // Make sure a partial update doesn't cause a full update to be discarded.
7651     view.reset();
7652     item->repaints = 0;
7653     item->update(QRectF(0, 0, 5, 5));
7654     item->update();
7655     qApp->processEvents();
7656     QCOMPARE(item->repaints, 1);
7657     QCOMPARE(view.repaints, 1);
7658     QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7659                                                          .mapRect(item->boundingRect()).toAlignedRect();
7660     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7661     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7662     QCOMPARE(view.paintedRegion, expectedRegion);
7663
7664     // Make sure update requests outside the bounding rect are discarded.
7665     view.reset();
7666     item->repaints = 0;
7667     item->update(-15, -15, 5, 5); // Item's brect: (-10, -10, 20, 20)
7668     qApp->processEvents();
7669     QCOMPARE(item->repaints, 0);
7670     QCOMPARE(view.repaints, 0);
7671
7672     // Make sure the area occupied by an item is repainted when hiding it.
7673     view.reset();
7674     item->repaints = 0;
7675     item->update(); // Full update; all sub-sequent update requests are discarded.
7676     item->hide(); // visible set to 0. ignoreVisible must be set to 1; the item won't be processed otherwise.
7677     qApp->processEvents();
7678     QCOMPARE(item->repaints, 0);
7679     QCOMPARE(view.repaints, 1);
7680     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7681     QCOMPARE(view.paintedRegion, expectedRegion);
7682
7683     // Make sure item is repainted when shown (after being hidden).
7684     view.reset();
7685     item->repaints = 0;
7686     item->show();
7687     qApp->processEvents();
7688     QCOMPARE(item->repaints, 1);
7689     QCOMPARE(view.repaints, 1);
7690     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7691     QCOMPARE(view.paintedRegion, expectedRegion);
7692
7693     item->repaints = 0;
7694     item->hide();
7695     qApp->processEvents();
7696     view.reset();
7697     const QPointF originalPos = item->pos();
7698     item->setPos(5000, 5000);
7699     qApp->processEvents();
7700     QCOMPARE(item->repaints, 0);
7701     QCOMPARE(view.repaints, 0);
7702     qApp->processEvents();
7703
7704     item->setPos(originalPos);
7705     qApp->processEvents();
7706     QCOMPARE(item->repaints, 0);
7707     QCOMPARE(view.repaints, 0);
7708     item->show();
7709     qApp->processEvents();
7710     QCOMPARE(item->repaints, 1);
7711     QCOMPARE(view.repaints, 1);
7712     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7713     QCOMPARE(view.paintedRegion, expectedRegion);
7714
7715     QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
7716     item->setPos(originalPos + QPoint(50, 50));
7717     viewPrivate->updateAll();
7718     QVERIFY(viewPrivate->fullUpdatePending);
7719     QTest::qWait(50);
7720     item->repaints = 0;
7721     view.reset();
7722     item->setPos(originalPos);
7723     QTest::qWait(50);
7724     qApp->processEvents();
7725     QCOMPARE(item->repaints, 1);
7726     QCOMPARE(view.repaints, 1);
7727     COMPARE_REGIONS(view.paintedRegion, expectedRegion + expectedRegion.translated(50, 50));
7728
7729     // Make sure moving a parent item triggers an update on the children
7730     // (even though the parent itself is outside the viewport).
7731     QGraphicsRectItem *parent = new QGraphicsRectItem(0, 0, 10, 10);
7732     parent->setPos(-400, 0);
7733     item->setParentItem(parent);
7734     item->setPos(400, 0);
7735     scene.addItem(parent);
7736     QTest::qWait(50);
7737     itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7738                                                    .mapRect(item->boundingRect()).toAlignedRect();
7739     expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7740     view.reset();
7741     item->repaints = 0;
7742     parent->translate(-400, 0);
7743     qApp->processEvents();
7744     QCOMPARE(item->repaints, 0);
7745     QCOMPARE(view.repaints, 1);
7746     QCOMPARE(view.paintedRegion, expectedRegion);
7747     view.reset();
7748     item->repaints = 0;
7749     parent->translate(400, 0);
7750     qApp->processEvents();
7751     QCOMPARE(item->repaints, 1);
7752     QCOMPARE(view.repaints, 1);
7753     QCOMPARE(view.paintedRegion, expectedRegion);
7754     QCOMPARE(view.paintedRegion, expectedRegion);
7755 }
7756
7757 void tst_QGraphicsItem::setTransformProperties_data()
7758 {
7759     QTest::addColumn<QPointF>("origin");
7760     QTest::addColumn<qreal>("rotation");
7761     QTest::addColumn<qreal>("scale");
7762
7763     QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(1.0);
7764
7765     QTest::newRow("rotation") << QPointF() << qreal(42.2) << qreal(1.0);
7766
7767     QTest::newRow("rotation dicentred") << QPointF(qreal(22.3), qreal(-56.2))
7768                                 << qreal(-2578.2)
7769                                 << qreal(1.0);
7770
7771     QTest::newRow("Scale")    << QPointF() << qreal(0.0)
7772                                           << qreal(6);
7773
7774     QTest::newRow("Everything dicentred")  << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196);
7775 }
7776
7777 /**
7778  * the normal QCOMPARE doesn't work because it doesn't use qFuzzyCompare
7779  */
7780 #define QCOMPARE_TRANSFORM(X1, X2)   QVERIFY(((X1)*(X2).inverted()).isIdentity())
7781
7782 void tst_QGraphicsItem::setTransformProperties()
7783 {
7784     QFETCH(QPointF,origin);
7785     QFETCH(qreal,rotation);
7786     QFETCH(qreal,scale);
7787
7788     QTransform result;
7789     result.translate(origin.x(), origin.y());
7790     result.rotate(rotation, Qt::ZAxis);
7791     result.scale(scale, scale);
7792     result.translate(-origin.x(), -origin.y());
7793
7794     QGraphicsScene scene;
7795     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
7796     scene.addItem(item);
7797
7798     item->setRotation(rotation);
7799     item->setScale(scale);
7800     item->setTransformOriginPoint(origin);
7801
7802     QCOMPARE(item->rotation(), rotation);
7803     QCOMPARE(item->scale(), scale);
7804     QCOMPARE(item->transformOriginPoint(), origin);
7805
7806     QCOMPARE(QTransform(), item->transform());
7807     QCOMPARE(result, item->sceneTransform());
7808
7809     //-----------------------------------------------------------------
7810     //Change the rotation Z
7811     item->setRotation(45);
7812     QTransform result2;
7813     result2.translate(origin.x(), origin.y());
7814     result2.rotate(45);
7815     result2.scale(scale, scale);
7816     result2.translate(-origin.x(), -origin.y());
7817
7818     QCOMPARE(item->rotation(), 45.);
7819     QCOMPARE(item->scale(), scale);
7820     QCOMPARE(item->transformOriginPoint(), origin);
7821
7822     QCOMPARE(QTransform(), item->transform());
7823     QCOMPARE(result2, item->sceneTransform());
7824
7825     //-----------------------------------------------------------------
7826     // calling setTransform() and setPos should change the sceneTransform
7827     item->setTransform(result);
7828     item->setPos(100, -150.5);
7829
7830     QCOMPARE(item->rotation(), 45.);
7831     QCOMPARE(item->scale(), scale);
7832     QCOMPARE(item->transformOriginPoint(), origin);
7833     QCOMPARE(result, item->transform());
7834
7835     QTransform result3(result);
7836
7837     result3.translate(origin.x(), origin.y());
7838     result3.rotate(45);
7839     result3.scale(scale, scale);
7840     result3.translate(-origin.x(), -origin.y());
7841
7842     result3 *= QTransform::fromTranslate(100, -150.5); //the pos;
7843
7844     QCOMPARE(result3, item->sceneTransform());
7845
7846     //-----------------------------------------------------
7847     // setting the propertiees should be the same as setting a transform
7848     {//with center origin on the matrix
7849         QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7850         scene.addItem(item1);
7851         QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7852         scene.addItem(item2);
7853
7854         item1->setPos(12.3, -5);
7855         item2->setPos(12.3, -5);
7856         item1->setRotation(rotation);
7857         item1->setScale(scale);
7858         item1->setTransformOriginPoint(origin);
7859
7860         item2->setTransform(result);
7861
7862         QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform());
7863
7864         QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform());
7865         QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform());
7866     }
7867 }
7868
7869 class MyStyleOptionTester : public QGraphicsRectItem
7870 {
7871 public:
7872     MyStyleOptionTester(const QRectF &rect)
7873         : QGraphicsRectItem(rect), startTrack(false)
7874     {}
7875
7876     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7877     {
7878         if (startTrack) {
7879             //Doesn't use the extended style option so the exposed rect is the boundingRect
7880             if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) {
7881                 QCOMPARE(option->exposedRect, boundingRect());
7882                 QCOMPARE(option->matrix, QMatrix());
7883             } else {
7884                 QVERIFY(option->exposedRect != QRect());
7885                 QVERIFY(option->exposedRect != boundingRect());
7886                 QCOMPARE(option->matrix, sceneTransform().toAffine());
7887             }
7888         }
7889         QGraphicsRectItem::paint(painter, option, widget);
7890     }
7891     bool startTrack;
7892 };
7893
7894 void tst_QGraphicsItem::itemUsesExtendedStyleOption()
7895 {
7896     QGraphicsScene scene(0, 0, 300, 300);
7897     QGraphicsPixmapItem item;
7898     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7899     QCOMPARE(item.flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
7900     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
7901     QCOMPARE(item.flags(), 0);
7902
7903     //We now test the content of the style option
7904     MyStyleOptionTester *rect = new MyStyleOptionTester(QRect(0, 0, 100, 100));
7905     scene.addItem(rect);
7906     rect->setPos(200, 200);
7907     QWidget topLevel;
7908     QGraphicsView view(&scene, &topLevel);
7909     topLevel.setWindowFlags(Qt::X11BypassWindowManagerHint);
7910     rect->startTrack = false;
7911     topLevel.show();
7912     QTest::qWaitForWindowShown(&view);
7913     QTest::qWait(60);
7914     rect->startTrack = true;
7915     rect->update(10, 10, 10, 10);
7916     QTest::qWait(60);
7917     rect->startTrack = false;
7918     rect->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7919     QVERIFY((rect->flags() & QGraphicsItem::ItemUsesExtendedStyleOption));
7920     QTest::qWait(60);
7921     rect->startTrack = true;
7922     rect->update(10, 10, 10, 10);
7923     QTest::qWait(60);
7924 }
7925
7926 void tst_QGraphicsItem::itemSendsGeometryChanges()
7927 {
7928     ItemChangeTester item;
7929     item.setFlags(0);
7930     item.clear();
7931
7932     QTransform x = QTransform().rotate(45);
7933     QPointF pos(10, 10);
7934     qreal o(0.5);
7935     qreal r(10.0);
7936     qreal s(1.5);
7937     QPointF origin(1.0, 1.0);
7938     item.setTransform(x);
7939     item.setPos(pos);
7940     item.setRotation(r);
7941     item.setScale(s);
7942     item.setTransformOriginPoint(origin);
7943     QCOMPARE(item.transform(), x);
7944     QCOMPARE(item.pos(), pos);
7945     QCOMPARE(item.rotation(), r);
7946     QCOMPARE(item.scale(), s);
7947     QCOMPARE(item.transformOriginPoint(), origin);
7948     QCOMPARE(item.changes.size(), 0);
7949
7950     item.setOpacity(o);
7951     QCOMPARE(item.changes.size(), 2); // opacity
7952
7953     item.setFlag(QGraphicsItem::ItemSendsGeometryChanges);
7954     QCOMPARE(item.changes.size(), 4); // flags
7955     item.setTransform(QTransform());
7956     item.setPos(QPointF());
7957     QCOMPARE(item.changes.size(), 8); // transform + pos
7958     QCOMPARE(item.transform(), QTransform());
7959     QCOMPARE(item.pos(), QPointF());
7960     QCOMPARE(item.opacity(), o);
7961     item.setRotation(0.0);
7962     item.setScale(1.0);
7963     item.setTransformOriginPoint(0.0, 0.0);
7964     QCOMPARE(item.changes.size(), 14); // rotation + scale + origin
7965     QCOMPARE(item.rotation(), qreal(0.0));
7966     QCOMPARE(item.scale(), qreal(1.0));
7967     QCOMPARE(item.transformOriginPoint(), QPointF(0.0, 0.0));
7968
7969     QCOMPARE(item.changes, QList<QGraphicsItem::GraphicsItemChange>()
7970              << QGraphicsItem::ItemOpacityChange
7971              << QGraphicsItem::ItemOpacityHasChanged
7972              << QGraphicsItem::ItemFlagsChange
7973              << QGraphicsItem::ItemFlagsHaveChanged
7974              << QGraphicsItem::ItemTransformChange
7975              << QGraphicsItem::ItemTransformHasChanged
7976              << QGraphicsItem::ItemPositionChange
7977              << QGraphicsItem::ItemPositionHasChanged
7978              << QGraphicsItem::ItemRotationChange
7979              << QGraphicsItem::ItemRotationHasChanged
7980              << QGraphicsItem::ItemScaleChange
7981              << QGraphicsItem::ItemScaleHasChanged
7982              << QGraphicsItem::ItemTransformOriginPointChange
7983              << QGraphicsItem::ItemTransformOriginPointHasChanged);
7984 }
7985
7986 // Make sure we update moved items correctly.
7987 void tst_QGraphicsItem::moveItem()
7988 {
7989     QGraphicsScene scene;
7990     scene.setSceneRect(-50, -50, 200, 200);
7991
7992     MyGraphicsView view(&scene);
7993     view.show();
7994 #ifdef Q_WS_X11
7995     qt_x11_wait_for_window_manager(&view);
7996 #endif
7997     QTest::qWait(100);
7998
7999     EventTester *parent = new EventTester;
8000     EventTester *child = new EventTester(parent);
8001     EventTester *grandChild = new EventTester(child);
8002
8003 #define RESET_COUNTERS \
8004     parent->repaints = 0; \
8005     child->repaints = 0; \
8006     grandChild->repaints = 0; \
8007     view.reset();
8008
8009     scene.addItem(parent);
8010     QTest::qWait(100);
8011
8012     RESET_COUNTERS
8013
8014     // Item's boundingRect:  (-10, -10, 20, 20).
8015     QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
8016                                      .mapRect(parent->boundingRect()).toAlignedRect()
8017                                      .adjusted(-2, -2, 2, 2); // Adjusted for antialiasing.
8018
8019     parent->setPos(20, 20);
8020     qApp->processEvents();
8021     QCOMPARE(parent->repaints, 1);
8022     QCOMPARE(view.repaints, 1);
8023     QRegion expectedParentRegion = parentDeviceBoundingRect; // old position
8024     parentDeviceBoundingRect.translate(20, 20);
8025     expectedParentRegion += parentDeviceBoundingRect; // new position
8026     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
8027
8028     RESET_COUNTERS
8029
8030     child->setPos(20, 20);
8031     qApp->processEvents();
8032     QCOMPARE(parent->repaints, 1);
8033     QCOMPARE(child->repaints, 1);
8034     QCOMPARE(view.repaints, 1);
8035     const QRegion expectedChildRegion = expectedParentRegion.translated(20, 20);
8036     COMPARE_REGIONS(view.paintedRegion, expectedChildRegion);
8037
8038     RESET_COUNTERS
8039
8040     grandChild->setPos(20, 20);
8041     qApp->processEvents();
8042     QCOMPARE(parent->repaints, 1);
8043     QCOMPARE(child->repaints, 1);
8044     QCOMPARE(grandChild->repaints, 1);
8045     QCOMPARE(view.repaints, 1);
8046     const QRegion expectedGrandChildRegion = expectedParentRegion.translated(40, 40);
8047     COMPARE_REGIONS(view.paintedRegion, expectedGrandChildRegion);
8048
8049     RESET_COUNTERS
8050
8051     parent->translate(20, 20);
8052     qApp->processEvents();
8053     QCOMPARE(parent->repaints, 1);
8054     QCOMPARE(child->repaints, 1);
8055     QCOMPARE(grandChild->repaints, 1);
8056     QCOMPARE(view.repaints, 1);
8057     expectedParentRegion.translate(20, 20);
8058     expectedParentRegion += expectedChildRegion.translated(20, 20);
8059     expectedParentRegion += expectedGrandChildRegion.translated(20, 20);
8060     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
8061 }
8062
8063 void tst_QGraphicsItem::moveLineItem()
8064 {
8065     QGraphicsScene scene;
8066     scene.setSceneRect(0, 0, 200, 200);
8067     QGraphicsLineItem *item = new QGraphicsLineItem(0, 0, 100, 0);
8068     item->setPos(50, 50);
8069     scene.addItem(item);
8070
8071     MyGraphicsView view(&scene);
8072     view.show();
8073 #ifdef Q_WS_X11
8074     qt_x11_wait_for_window_manager(&view);
8075 #endif
8076     QTest::qWait(200);
8077     view.reset();
8078
8079     QRectF brect = item->boundingRect();
8080     // Do same adjustments as in qgraphicsscene.cpp
8081     if (!brect.width())
8082         brect.adjust(qreal(-0.00001), 0, qreal(0.00001), 0);
8083     if (!brect.height())
8084         brect.adjust(0, qreal(-0.00001), 0, qreal(0.00001));
8085     const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
8086                                          .mapRect(brect).toAlignedRect();
8087     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // antialiasing
8088
8089     // Make sure the calculated region is correct.
8090     item->update();
8091     QTest::qWait(10);
8092     QTRY_COMPARE(view.paintedRegion, expectedRegion);
8093     view.reset();
8094
8095     // Old position: (50, 50)
8096     item->setPos(50, 100);
8097     expectedRegion += expectedRegion.translated(0, 50);
8098     QTest::qWait(10);
8099     QCOMPARE(view.paintedRegion, expectedRegion);
8100 }
8101
8102 void tst_QGraphicsItem::sorting_data()
8103 {
8104     QTest::addColumn<int>("index");
8105
8106     QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex);
8107     QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex);
8108 }
8109
8110 void tst_QGraphicsItem::sorting()
8111 {
8112     if (PlatformQuirks::isAutoMaximizing())
8113         QSKIP("Skipped because Platform is auto maximizing");
8114
8115     _paintedItems.clear();
8116
8117     QGraphicsScene scene;
8118     QGraphicsItem *grid[100][100];
8119     for (int x = 0; x < 100; ++x) {
8120         for (int y = 0; y < 100; ++y) {
8121             PainterItem *item = new PainterItem;
8122             item->setPos(x * 25, y * 25);
8123             item->setData(0, QString("%1x%2").arg(x).arg(y));
8124             grid[x][y] = item;
8125             scene.addItem(item);
8126         }
8127     }
8128
8129     PainterItem *item1 = new PainterItem;
8130     PainterItem *item2 = new PainterItem;
8131     item1->setData(0, "item1");
8132     item2->setData(0, "item2");
8133     scene.addItem(item1);
8134     scene.addItem(item2);
8135
8136     QGraphicsView view(&scene);
8137     view.setResizeAnchor(QGraphicsView::NoAnchor);
8138     view.setTransformationAnchor(QGraphicsView::NoAnchor);
8139     view.resize(120, 100);
8140     view.setFrameStyle(0);
8141     view.show();
8142 #ifdef Q_WS_X11
8143     qt_x11_wait_for_window_manager(&view);
8144 #endif
8145     QTest::qWait(100);
8146
8147     _paintedItems.clear();
8148
8149     view.viewport()->repaint();
8150 #if defined(Q_WS_MAC)
8151     // There's no difference between repaint and update on the Mac,
8152     // so we have to process events here to make sure we get the event.
8153     QTest::qWait(100);
8154 #endif
8155
8156     QCOMPARE(_paintedItems, QList<QGraphicsItem *>()
8157                  << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3]
8158                  << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3]
8159                  << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3]
8160                  << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3]
8161                  << grid[4][0] << grid[4][1] << grid[4][2] << grid[4][3]
8162                  << item1 << item2);
8163 }
8164
8165 void tst_QGraphicsItem::itemHasNoContents()
8166 {
8167     PainterItem *item1 = new PainterItem;
8168     PainterItem *item2 = new PainterItem;
8169     item2->setParentItem(item1);
8170     item2->setPos(50, 50);
8171     item1->setFlag(QGraphicsItem::ItemHasNoContents);
8172     item1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
8173
8174     QGraphicsScene scene;
8175     scene.addItem(item1);
8176
8177     QGraphicsView view(&scene);
8178     view.show();
8179     QTest::qWaitForWindowShown(&view);
8180     QTRY_VERIFY(!_paintedItems.isEmpty());
8181
8182     _paintedItems.clear();
8183
8184     view.viewport()->repaint();
8185 #ifdef Q_WS_MAC
8186     // There's no difference between update() and repaint() on the Mac,
8187     // so we have to process events here to make sure we get the event.
8188     QTest::qWait(10);
8189 #endif
8190
8191     QTRY_COMPARE(_paintedItems, QList<QGraphicsItem *>() << item2);
8192 }
8193
8194 void tst_QGraphicsItem::hitTestUntransformableItem()
8195 {
8196     QGraphicsScene scene;
8197     scene.setSceneRect(-100, -100, 200, 200);
8198
8199     QGraphicsView view(&scene);
8200     view.show();
8201 #ifdef Q_WS_X11
8202     qt_x11_wait_for_window_manager(&view);
8203 #endif
8204     QTest::qWait(100);
8205
8206     // Confuse the BSP with dummy items.
8207     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8208     dummy->setPos(-100, -100);
8209     scene.addItem(dummy);
8210     for (int i = 0; i < 100; ++i) {
8211         QGraphicsItem *parent = dummy;
8212         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8213         dummy->setPos(-100 + i, -100 + i);
8214         dummy->setParentItem(parent);
8215     }
8216
8217     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
8218     item1->setPos(-200, -200);
8219
8220     QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 20, 20);
8221     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8222     item2->setParentItem(item1);
8223     item2->setPos(200, 200);
8224
8225     QGraphicsRectItem *item3 = new QGraphicsRectItem(0, 0, 20, 20);
8226     item3->setParentItem(item2);
8227     item3->setPos(80, 80);
8228
8229     scene.addItem(item1);
8230     QTest::qWait(100);
8231
8232     QList<QGraphicsItem *> items = scene.items(QPointF(80, 80));
8233     QCOMPARE(items.size(), 1);
8234     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8235
8236     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8237     QTest::qWait(100);
8238
8239     items = scene.items(QPointF(80, 80));
8240     QCOMPARE(items.size(), 1);
8241     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8242 }
8243
8244 void tst_QGraphicsItem::hitTestGraphicsEffectItem()
8245 {
8246     QGraphicsScene scene;
8247     scene.setSceneRect(-100, -100, 200, 200);
8248
8249     QWidget toplevel;
8250
8251     QGraphicsView view(&scene, &toplevel);
8252     toplevel.resize(300, 300);
8253     toplevel.show();
8254 #ifdef Q_WS_X11
8255     qt_x11_wait_for_window_manager(&toplevel);
8256 #endif
8257     QTest::qWait(100);
8258
8259     // Confuse the BSP with dummy items.
8260     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8261     dummy->setPos(-100, -100);
8262     scene.addItem(dummy);
8263     for (int i = 0; i < 100; ++i) {
8264         QGraphicsItem *parent = dummy;
8265         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8266         dummy->setPos(-100 + i, -100 + i);
8267         dummy->setParentItem(parent);
8268     }
8269
8270     const QRectF itemBoundingRect(0, 0, 20, 20);
8271     EventTester *item1 = new EventTester;
8272     item1->br = itemBoundingRect;
8273     item1->setPos(-200, -200);
8274     item1->brush = Qt::red;
8275
8276     EventTester *item2 = new EventTester;
8277     item2->br = itemBoundingRect;
8278     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8279     item2->setParentItem(item1);
8280     item2->setPos(200, 200);
8281     item2->brush = Qt::green;
8282
8283     EventTester *item3 = new EventTester;
8284     item3->br = itemBoundingRect;
8285     item3->setParentItem(item2);
8286     item3->setPos(80, 80);
8287     item3->brush = Qt::blue;
8288
8289     scene.addItem(item1);
8290     QTest::qWait(100);
8291
8292     item1->repaints = 0;
8293     item2->repaints = 0;
8294     item3->repaints = 0;
8295
8296     // Apply shadow effect to the entire sub-tree.
8297     QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
8298     shadow->setOffset(-20, -20);
8299     item1->setGraphicsEffect(shadow);
8300     QTest::qWait(50);
8301
8302     // Make sure all visible items are repainted.
8303     QCOMPARE(item1->repaints, 1);
8304     QCOMPARE(item2->repaints, 1);
8305     QCOMPARE(item3->repaints, 1);
8306
8307     // Make sure an item doesn't respond to a click on its shadow.
8308     QList<QGraphicsItem *> items = scene.items(QPointF(75, 75));
8309     QVERIFY(items.isEmpty());
8310     items = scene.items(QPointF(80, 80));
8311     QCOMPARE(items.size(), 1);
8312     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8313
8314     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8315     QTest::qWait(100);
8316
8317     items = scene.items(QPointF(75, 75));
8318     QVERIFY(items.isEmpty());
8319     items = scene.items(QPointF(80, 80));
8320     QCOMPARE(items.size(), 1);
8321     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8322 }
8323
8324 void tst_QGraphicsItem::focusProxy()
8325 {
8326     QGraphicsScene scene;
8327     QEvent activate(QEvent::WindowActivate);
8328     QApplication::sendEvent(&scene, &activate);
8329
8330     QGraphicsItem *item = scene.addRect(0, 0, 10, 10);
8331     item->setFlag(QGraphicsItem::ItemIsFocusable);
8332     QVERIFY(!item->focusProxy());
8333
8334     QGraphicsItem *item2 = scene.addRect(0, 0, 10, 10);
8335     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8336     item->setFocusProxy(item2);
8337     QCOMPARE(item->focusProxy(), item2);
8338
8339     item->setFocus();
8340     QVERIFY(item->hasFocus());
8341     QVERIFY(item2->hasFocus());
8342
8343     // Try to make a focus chain loop
8344     QString err;
8345     QTextStream stream(&err);
8346     stream << "QGraphicsItem::setFocusProxy: "
8347            << (void*)item << " is already in the focus proxy chain" << flush;
8348     QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
8349     item2->setFocusProxy(item); // fails
8350     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8351     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8352
8353     // Try to assign self as focus proxy
8354     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
8355     item->setFocusProxy(item); // fails
8356     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8357     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8358
8359     // Reset the focus proxy
8360     item->setFocusProxy(0);
8361     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8362     QVERIFY(!item->hasFocus());
8363     QVERIFY(item2->hasFocus());
8364
8365     // Test deletion
8366     item->setFocusProxy(item2);
8367     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8368     delete item2;
8369     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8370
8371     // Test event delivery
8372     item2 = scene.addRect(0, 0, 10, 10);
8373     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8374     item->setFocusProxy(item2);
8375     item->clearFocus();
8376
8377     EventSpy focusInSpy(&scene, item, QEvent::FocusIn);
8378     EventSpy focusOutSpy(&scene, item, QEvent::FocusOut);
8379     EventSpy focusInSpy2(&scene, item2, QEvent::FocusIn);
8380     EventSpy focusOutSpy2(&scene, item2, QEvent::FocusOut);
8381     QCOMPARE(focusInSpy.count(), 0);
8382     QCOMPARE(focusOutSpy.count(), 0);
8383     QCOMPARE(focusInSpy2.count(), 0);
8384     QCOMPARE(focusOutSpy2.count(), 0);
8385
8386     item->setFocus();
8387     QCOMPARE(focusInSpy.count(), 0);
8388     QCOMPARE(focusInSpy2.count(), 1);
8389     item->clearFocus();
8390     QCOMPARE(focusOutSpy.count(), 0);
8391     QCOMPARE(focusOutSpy2.count(), 1);
8392
8393     // Test two items proxying one item.
8394     QGraphicsItem *item3 = scene.addRect(0, 0, 10, 10);
8395     item3->setFlag(QGraphicsItem::ItemIsFocusable);
8396     item3->setFocusProxy(item2); // item and item3 use item2 as proxy
8397
8398     QCOMPARE(item->focusProxy(), item2);
8399     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8400     QCOMPARE(item3->focusProxy(), item2);
8401     delete item2;
8402     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8403     QCOMPARE(item3->focusProxy(), (QGraphicsItem *)0);
8404 }
8405
8406 void tst_QGraphicsItem::subFocus()
8407 {
8408     // Construct a text item that's not part of a scene (yet)
8409     // and has no parent. Setting focus on it will not make
8410     // the item gain input focus; that requires a scene. But
8411     // it does set subfocus, indicating that the item wishes
8412     // to gain focus later.
8413     QGraphicsTextItem *text = new QGraphicsTextItem("Hello");
8414     text->setTextInteractionFlags(Qt::TextEditorInteraction);
8415     QVERIFY(!text->hasFocus());
8416     text->setFocus();
8417     QVERIFY(!text->hasFocus());
8418     QCOMPARE(text->focusItem(), (QGraphicsItem *)text);
8419
8420     // Add a sibling.
8421     QGraphicsTextItem *text2 = new QGraphicsTextItem("Hi");
8422     text2->setTextInteractionFlags(Qt::TextEditorInteraction);
8423     text2->setPos(30, 30);
8424
8425     // Add both items to a scene and check that it's text that
8426     // got input focus.
8427     QGraphicsScene scene;
8428     QEvent activate(QEvent::WindowActivate);
8429     QApplication::sendEvent(&scene, &activate);
8430
8431     scene.addItem(text);
8432     scene.addItem(text2);
8433     QVERIFY(text->hasFocus());
8434
8435     text->setData(0, "text");
8436     text2->setData(0, "text2");
8437
8438     // Remove text2 and set subfocus on it. Then readd. Reparent it onto the
8439     // other item and see that it gains input focus.
8440     scene.removeItem(text2);
8441     text2->setFocus();
8442     scene.addItem(text2);
8443     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8444     text2->setParentItem(text);
8445     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8446     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8447     QVERIFY(!text->hasFocus());
8448     QVERIFY(text2->hasFocus());
8449
8450     // Remove both items from the scene, restore subfocus and
8451     // readd them. Now the subfocus should kick in and give
8452     // text2 focus.
8453     scene.removeItem(text);
8454     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8455     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8456     text2->setFocus();
8457     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8458     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8459     scene.addItem(text);
8460
8461     // Hiding and showing text should pass focus to text2.
8462     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8463     QVERIFY(text2->hasFocus());
8464
8465     // Subfocus should repropagate to root when reparenting.
8466     QGraphicsRectItem *rect = new QGraphicsRectItem;
8467     QGraphicsRectItem *rect2 = new QGraphicsRectItem(rect);
8468     QGraphicsRectItem *rect3 = new QGraphicsRectItem(rect2);
8469     rect3->setFlag(QGraphicsItem::ItemIsFocusable);
8470
8471     text->setData(0, "text");
8472     text2->setData(0, "text2");
8473     rect->setData(0, "rect");
8474     rect2->setData(0, "rect2");
8475     rect3->setData(0, "rect3");
8476
8477     rect3->setFocus();
8478     QVERIFY(!rect3->hasFocus());
8479     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8480     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8481     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8482     rect->setParentItem(text2);
8483     QCOMPARE(text->focusItem(), (QGraphicsItem *)rect3);
8484     QCOMPARE(text2->focusItem(), (QGraphicsItem *)rect3);
8485     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8486     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8487     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8488     QVERIFY(!rect->hasFocus());
8489     QVERIFY(!rect2->hasFocus());
8490     QVERIFY(rect3->hasFocus());
8491
8492     delete rect2;
8493     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8494     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8495     QCOMPARE(rect->focusItem(), (QGraphicsItem *)0);
8496 }
8497
8498 void tst_QGraphicsItem::focusProxyDeletion()
8499 {
8500     QGraphicsRectItem *rect = new QGraphicsRectItem;
8501     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8502     rect->setFocusProxy(rect2);
8503     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8504
8505     delete rect2;
8506     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8507
8508     rect2 = new QGraphicsRectItem;
8509     rect->setFocusProxy(rect2);
8510     delete rect; // don't crash
8511
8512     rect = new QGraphicsRectItem;
8513     rect->setFocusProxy(rect2);
8514     QGraphicsScene *scene = new QGraphicsScene;
8515     scene->addItem(rect);
8516     scene->addItem(rect2);
8517     delete rect2;
8518     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8519
8520     rect2 = new QGraphicsRectItem;
8521     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
8522     rect->setFocusProxy(rect2);
8523     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8524     scene->addItem(rect2);
8525     rect->setFocusProxy(rect2);
8526     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8527     delete rect; // don't crash
8528
8529     rect = new QGraphicsRectItem;
8530     rect2 = new QGraphicsRectItem;
8531     rect->setFocusProxy(rect2);
8532     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8533     scene->addItem(rect);
8534     scene->addItem(rect2);
8535     rect->setFocusProxy(rect2);
8536     delete scene; // don't crash
8537 }
8538
8539 void tst_QGraphicsItem::negativeZStacksBehindParent()
8540 {
8541     QGraphicsRectItem rect;
8542     QCOMPARE(rect.zValue(), qreal(0.0));
8543     QVERIFY(!(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent));
8544     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8545     rect.setZValue(-1);
8546     QCOMPARE(rect.zValue(), qreal(-1.0));
8547     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8548     rect.setZValue(0);
8549     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
8550     QVERIFY(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent);
8551     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8552     rect.setZValue(-1);
8553     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8554     rect.setZValue(0);
8555     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8556     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8557     rect.setZValue(-1);
8558     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, true);
8559     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8560     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8561     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8562 }
8563
8564 void tst_QGraphicsItem::setGraphicsEffect()
8565 {
8566     // Check that we don't have any effect by default.
8567     QGraphicsItem *item = new QGraphicsRectItem(0, 0, 10, 10);
8568     QVERIFY(!item->graphicsEffect());
8569
8570     // SetGet check.
8571     QPointer<QGraphicsEffect> blurEffect = new QGraphicsBlurEffect;
8572     item->setGraphicsEffect(blurEffect);
8573     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(blurEffect));
8574
8575     // Ensure the existing effect is deleted when setting a new one.
8576     QPointer<QGraphicsEffect> shadowEffect = new QGraphicsDropShadowEffect;
8577     item->setGraphicsEffect(shadowEffect);
8578     QVERIFY(!blurEffect);
8579     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(shadowEffect));
8580     blurEffect = new QGraphicsBlurEffect;
8581
8582     // Ensure the effect is uninstalled when setting it on a new target.
8583     QGraphicsItem *anotherItem = new QGraphicsRectItem(0, 0, 10, 10);
8584     anotherItem->setGraphicsEffect(blurEffect);
8585     item->setGraphicsEffect(blurEffect);
8586     QVERIFY(!anotherItem->graphicsEffect());
8587     QVERIFY(!shadowEffect);
8588
8589     // Ensure the existing effect is deleted when deleting the item.
8590     delete item;
8591     QVERIFY(!blurEffect);
8592     delete anotherItem;
8593
8594     // Ensure the effect is uninstalled when deleting it
8595     item = new QGraphicsRectItem(0, 0, 10, 10);
8596     blurEffect = new QGraphicsBlurEffect;
8597     item->setGraphicsEffect(blurEffect);
8598     delete blurEffect;
8599     QVERIFY(!item->graphicsEffect());
8600
8601     // Ensure the existing effect is uninstalled and deleted when setting a null effect
8602     blurEffect = new QGraphicsBlurEffect;
8603     item->setGraphicsEffect(blurEffect);
8604     item->setGraphicsEffect(0);
8605     QVERIFY(!item->graphicsEffect());
8606     QVERIFY(!blurEffect);
8607
8608     delete item;
8609 }
8610
8611 void tst_QGraphicsItem::panel()
8612 {
8613     QGraphicsScene scene;
8614
8615     QGraphicsRectItem *panel1 = new QGraphicsRectItem;
8616     QGraphicsRectItem *panel2 = new QGraphicsRectItem;
8617     QGraphicsRectItem *panel3 = new QGraphicsRectItem;
8618     QGraphicsRectItem *panel4 = new QGraphicsRectItem;
8619     QGraphicsRectItem *notPanel1 = new QGraphicsRectItem;
8620     QGraphicsRectItem *notPanel2 = new QGraphicsRectItem;
8621     panel1->setFlag(QGraphicsItem::ItemIsPanel);
8622     panel2->setFlag(QGraphicsItem::ItemIsPanel);
8623     panel3->setFlag(QGraphicsItem::ItemIsPanel);
8624     panel4->setFlag(QGraphicsItem::ItemIsPanel);
8625     scene.addItem(panel1);
8626     scene.addItem(panel2);
8627     scene.addItem(panel3);
8628     scene.addItem(panel4);
8629     scene.addItem(notPanel1);
8630     scene.addItem(notPanel2);
8631
8632     EventSpy spy_activate_panel1(&scene, panel1, QEvent::WindowActivate);
8633     EventSpy spy_deactivate_panel1(&scene, panel1, QEvent::WindowDeactivate);
8634     EventSpy spy_activate_panel2(&scene, panel2, QEvent::WindowActivate);
8635     EventSpy spy_deactivate_panel2(&scene, panel2, QEvent::WindowDeactivate);
8636     EventSpy spy_activate_panel3(&scene, panel3, QEvent::WindowActivate);
8637     EventSpy spy_deactivate_panel3(&scene, panel3, QEvent::WindowDeactivate);
8638     EventSpy spy_activate_panel4(&scene, panel4, QEvent::WindowActivate);
8639     EventSpy spy_deactivate_panel4(&scene, panel4, QEvent::WindowDeactivate);
8640     EventSpy spy_activate_notPanel1(&scene, notPanel1, QEvent::WindowActivate);
8641     EventSpy spy_deactivate_notPanel1(&scene, notPanel1, QEvent::WindowDeactivate);
8642     EventSpy spy_activate_notPanel2(&scene, notPanel1, QEvent::WindowActivate);
8643     EventSpy spy_deactivate_notPanel2(&scene, notPanel1, QEvent::WindowDeactivate);
8644
8645     QCOMPARE(spy_activate_panel1.count(), 0);
8646     QCOMPARE(spy_deactivate_panel1.count(), 0);
8647     QCOMPARE(spy_activate_panel2.count(), 0);
8648     QCOMPARE(spy_deactivate_panel2.count(), 0);
8649     QCOMPARE(spy_activate_panel3.count(), 0);
8650     QCOMPARE(spy_deactivate_panel3.count(), 0);
8651     QCOMPARE(spy_activate_panel4.count(), 0);
8652     QCOMPARE(spy_deactivate_panel4.count(), 0);
8653     QCOMPARE(spy_activate_notPanel1.count(), 0);
8654     QCOMPARE(spy_deactivate_notPanel1.count(), 0);
8655     QCOMPARE(spy_activate_notPanel2.count(), 0);
8656     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8657
8658     QVERIFY(!scene.activePanel());
8659     QVERIFY(!scene.isActive());
8660
8661     QEvent activate(QEvent::WindowActivate);
8662     QEvent deactivate(QEvent::WindowDeactivate);
8663
8664     QApplication::sendEvent(&scene, &activate);
8665
8666     // No previous activation, so the scene is active.
8667     QVERIFY(scene.isActive());
8668     QCOMPARE(scene.activePanel(), (QGraphicsItem *)panel1);
8669     QVERIFY(panel1->isActive());
8670     QVERIFY(!panel2->isActive());
8671     QVERIFY(!panel3->isActive());
8672     QVERIFY(!panel4->isActive());
8673     QVERIFY(!notPanel1->isActive());
8674     QVERIFY(!notPanel2->isActive());
8675     QCOMPARE(spy_deactivate_notPanel1.count(), 0);
8676     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8677     QCOMPARE(spy_activate_panel1.count(), 1);
8678     QCOMPARE(spy_activate_panel2.count(), 0);
8679     QCOMPARE(spy_activate_panel3.count(), 0);
8680     QCOMPARE(spy_activate_panel4.count(), 0);
8681
8682     // Switch back to scene.
8683     scene.setActivePanel(0);
8684     QVERIFY(!scene.activePanel());
8685     QVERIFY(!panel1->isActive());
8686     QVERIFY(!panel2->isActive());
8687     QVERIFY(!panel3->isActive());
8688     QVERIFY(!panel4->isActive());
8689     QVERIFY(notPanel1->isActive());
8690     QVERIFY(notPanel2->isActive());
8691     QCOMPARE(spy_activate_notPanel1.count(), 1);
8692     QCOMPARE(spy_activate_notPanel2.count(), 1);
8693
8694     // Deactivate the scene
8695     QApplication::sendEvent(&scene, &deactivate);
8696     QVERIFY(!scene.activePanel());
8697     QVERIFY(!panel1->isActive());
8698     QVERIFY(!panel2->isActive());
8699     QVERIFY(!panel3->isActive());
8700     QVERIFY(!panel4->isActive());
8701     QVERIFY(!notPanel1->isActive());
8702     QVERIFY(!notPanel2->isActive());
8703     QCOMPARE(spy_deactivate_notPanel1.count(), 1);
8704     QCOMPARE(spy_deactivate_notPanel2.count(), 1);
8705
8706     // Reactivate the scene
8707     QApplication::sendEvent(&scene, &activate);
8708     QVERIFY(!scene.activePanel());
8709     QVERIFY(!panel1->isActive());
8710     QVERIFY(!panel2->isActive());
8711     QVERIFY(!panel3->isActive());
8712     QVERIFY(!panel4->isActive());
8713     QVERIFY(notPanel1->isActive());
8714     QVERIFY(notPanel2->isActive());
8715     QCOMPARE(spy_activate_notPanel1.count(), 2);
8716     QCOMPARE(spy_activate_notPanel2.count(), 2);
8717
8718     // Switch to panel1
8719     scene.setActivePanel(panel1);
8720     QVERIFY(panel1->isActive());
8721     QCOMPARE(spy_deactivate_notPanel1.count(), 2);
8722     QCOMPARE(spy_deactivate_notPanel2.count(), 2);
8723     QCOMPARE(spy_activate_panel1.count(), 2);
8724
8725     // Deactivate the scene
8726     QApplication::sendEvent(&scene, &deactivate);
8727     QVERIFY(!panel1->isActive());
8728     QCOMPARE(spy_deactivate_panel1.count(), 2);
8729
8730     // Reactivate the scene
8731     QApplication::sendEvent(&scene, &activate);
8732     QVERIFY(panel1->isActive());
8733     QCOMPARE(spy_activate_panel1.count(), 3);
8734
8735     // Deactivate the scene
8736     QApplication::sendEvent(&scene, &deactivate);
8737     QVERIFY(!panel1->isActive());
8738     QVERIFY(!scene.activePanel());
8739     scene.setActivePanel(0);
8740
8741     // Reactivate the scene
8742     QApplication::sendEvent(&scene, &activate);
8743     QVERIFY(!panel1->isActive());
8744 }
8745
8746 void tst_QGraphicsItem::panelWithFocusItem()
8747 {
8748     QGraphicsScene scene;
8749     QEvent activate(QEvent::WindowActivate);
8750     QApplication::sendEvent(&scene, &activate);
8751
8752     QGraphicsRectItem *parentPanel = new QGraphicsRectItem;
8753     QGraphicsRectItem *parentPanelFocusItem = new QGraphicsRectItem(parentPanel);
8754     parentPanel->setFlag(QGraphicsItem::ItemIsPanel);
8755     parentPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8756     parentPanelFocusItem->setFocus();
8757     scene.addItem(parentPanel);
8758
8759     QVERIFY(parentPanel->isActive());
8760     QVERIFY(parentPanelFocusItem->hasFocus());
8761     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8762     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8763
8764     QGraphicsRectItem *childPanel = new QGraphicsRectItem;
8765     QGraphicsRectItem *childPanelFocusItem = new QGraphicsRectItem(childPanel);
8766     childPanel->setFlag(QGraphicsItem::ItemIsPanel);
8767     childPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8768     childPanelFocusItem->setFocus();
8769
8770     QVERIFY(!childPanelFocusItem->hasFocus());
8771     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8772     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8773
8774     childPanel->setParentItem(parentPanel);
8775
8776     QVERIFY(!parentPanel->isActive());
8777     QVERIFY(!parentPanelFocusItem->hasFocus());
8778     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8779     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8780
8781     QVERIFY(childPanel->isActive());
8782     QVERIFY(childPanelFocusItem->hasFocus());
8783     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8784     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8785
8786     childPanel->hide();
8787
8788     QVERIFY(parentPanel->isActive());
8789     QVERIFY(parentPanelFocusItem->hasFocus());
8790     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8791     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8792 }
8793
8794 void tst_QGraphicsItem::addPanelToActiveScene()
8795 {
8796     QGraphicsScene scene;
8797     QVERIFY(!scene.isActive());
8798
8799     QGraphicsRectItem *rect = new QGraphicsRectItem;
8800     scene.addItem(rect);
8801     QVERIFY(!rect->isActive());
8802     scene.removeItem(rect);
8803
8804     QEvent activate(QEvent::WindowActivate);
8805     QEvent deactivate(QEvent::WindowDeactivate);
8806
8807     QApplication::sendEvent(&scene, &activate);
8808     QVERIFY(scene.isActive());
8809     scene.addItem(rect);
8810     QVERIFY(rect->isActive());
8811     scene.removeItem(rect);
8812
8813     rect->setFlag(QGraphicsItem::ItemIsPanel);
8814     scene.addItem(rect);
8815     QVERIFY(rect->isActive());
8816     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8817
8818     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8819     scene.addItem(rect2);
8820     QVERIFY(rect->isActive());
8821     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8822 }
8823
8824 void tst_QGraphicsItem::activate()
8825 {
8826     QGraphicsScene scene;
8827     QGraphicsRectItem *rect = scene.addRect(-10, -10, 20, 20);
8828     QVERIFY(!rect->isActive());
8829
8830     QEvent activate(QEvent::WindowActivate);
8831     QEvent deactivate(QEvent::WindowDeactivate);
8832
8833     QApplication::sendEvent(&scene, &activate);
8834
8835     // Non-panel item (active when scene is active).
8836     QVERIFY(rect->isActive());
8837
8838     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8839     rect2->setFlag(QGraphicsItem::ItemIsPanel);
8840     QGraphicsRectItem *rect3 = new QGraphicsRectItem;
8841     rect3->setFlag(QGraphicsItem::ItemIsPanel);
8842
8843     // Test normal activation.
8844     QVERIFY(!rect2->isActive());
8845     scene.addItem(rect2);
8846     QVERIFY(rect2->isActive()); // first panel item is activated
8847     scene.addItem(rect3);
8848     QVERIFY(!rect3->isActive()); // second panel item is _not_ activated
8849     rect3->setActive(true);
8850     QVERIFY(rect3->isActive());
8851     scene.removeItem(rect3);
8852     QVERIFY(!rect3->isActive()); // no panel is active anymore
8853     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8854     scene.addItem(rect3);
8855     QVERIFY(rect3->isActive()); // second panel item is activated
8856
8857     // Test pending activation.
8858     scene.removeItem(rect3);
8859     rect2->setActive(true);
8860     QVERIFY(rect2->isActive()); // first panel item is activated
8861     rect3->setActive(true);
8862     QVERIFY(!rect3->isActive()); // not active (yet)
8863     scene.addItem(rect3);
8864     QVERIFY(rect3->isActive()); // now becomes active
8865
8866     // Test pending deactivation.
8867     scene.removeItem(rect3);
8868     rect3->setActive(false);
8869     scene.addItem(rect3);
8870     QVERIFY(!rect3->isActive()); // doesn't become active
8871
8872     // Child of panel activation.
8873     rect3->setActive(true);
8874     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
8875     rect4->setFlag(QGraphicsItem::ItemIsPanel);
8876     QGraphicsRectItem *rect5 = new QGraphicsRectItem(rect4);
8877     QGraphicsRectItem *rect6 = new QGraphicsRectItem(rect5);
8878     scene.addItem(rect4);
8879     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect3);
8880     scene.removeItem(rect4);
8881     rect6->setActive(true);
8882     scene.addItem(rect4);
8883     QVERIFY(rect4->isActive());
8884     QVERIFY(rect5->isActive());
8885     QVERIFY(rect6->isActive());
8886     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect4);
8887     scene.removeItem(rect4); // no active panel
8888     rect6->setActive(false);
8889     scene.addItem(rect4);
8890     QVERIFY(!rect4->isActive());
8891     QVERIFY(!rect5->isActive());
8892     QVERIFY(!rect6->isActive());
8893     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8894
8895     // Controlling auto-activation when the scene changes activation.
8896     rect4->setActive(true);
8897     QApplication::sendEvent(&scene, &deactivate);
8898     QVERIFY(!scene.isActive());
8899     QVERIFY(!rect4->isActive());
8900     rect4->setActive(false);
8901     QApplication::sendEvent(&scene, &activate);
8902     QVERIFY(scene.isActive());
8903     QVERIFY(!scene.activePanel());
8904     QVERIFY(!rect4->isActive());
8905 }
8906
8907 void tst_QGraphicsItem::setActivePanelOnInactiveScene()
8908 {
8909     QGraphicsScene scene;
8910     QGraphicsRectItem *item = scene.addRect(QRectF());
8911     QGraphicsRectItem *panel = scene.addRect(QRectF());
8912     panel->setFlag(QGraphicsItem::ItemIsPanel);
8913
8914     EventSpy itemActivateSpy(&scene, item, QEvent::WindowActivate);
8915     EventSpy itemDeactivateSpy(&scene, item, QEvent::WindowDeactivate);
8916     EventSpy panelActivateSpy(&scene, panel, QEvent::WindowActivate);
8917     EventSpy panelDeactivateSpy(&scene, panel, QEvent::WindowDeactivate);
8918     EventSpy sceneActivationChangeSpy(&scene, QEvent::ActivationChange);
8919
8920     scene.setActivePanel(panel);
8921     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8922     QCOMPARE(itemActivateSpy.count(), 0);
8923     QCOMPARE(itemDeactivateSpy.count(), 0);
8924     QCOMPARE(panelActivateSpy.count(), 0);
8925     QCOMPARE(panelDeactivateSpy.count(), 0);
8926     QCOMPARE(sceneActivationChangeSpy.count(), 0);
8927 }
8928
8929 void tst_QGraphicsItem::activationOnShowHide()
8930 {
8931     QGraphicsScene scene;
8932     QEvent activate(QEvent::WindowActivate);
8933     QApplication::sendEvent(&scene, &activate);
8934
8935     QGraphicsRectItem *rootPanel = scene.addRect(QRectF());
8936     rootPanel->setFlag(QGraphicsItem::ItemIsPanel);
8937     rootPanel->setActive(true);
8938
8939     QGraphicsRectItem *subPanel = new QGraphicsRectItem;
8940     subPanel->setFlag(QGraphicsItem::ItemIsPanel);
8941
8942     // Reparenting onto an active panel auto-activates the child panel.
8943     subPanel->setParentItem(rootPanel);
8944     QVERIFY(subPanel->isActive());
8945     QVERIFY(!rootPanel->isActive());
8946
8947     // Hiding an active child panel will reactivate the parent panel.
8948     subPanel->hide();
8949     QVERIFY(rootPanel->isActive());
8950
8951     // Showing a child panel will auto-activate it.
8952     subPanel->show();
8953     QVERIFY(subPanel->isActive());
8954     QVERIFY(!rootPanel->isActive());
8955
8956     // Adding an unrelated panel doesn't affect activation.
8957     QGraphicsRectItem *otherPanel = new QGraphicsRectItem;
8958     otherPanel->setFlag(QGraphicsItem::ItemIsPanel);
8959     scene.addItem(otherPanel);
8960     QVERIFY(subPanel->isActive());
8961
8962     // Showing an unrelated panel doesn't affect activation.
8963     otherPanel->hide();
8964     otherPanel->show();
8965     QVERIFY(subPanel->isActive());
8966
8967     // Add a non-panel item.
8968     QGraphicsRectItem *otherItem = new QGraphicsRectItem;
8969     scene.addItem(otherItem);
8970     otherItem->setActive(true);
8971     QVERIFY(otherItem->isActive());
8972
8973     // Reparent a panel onto an active non-panel item.
8974     subPanel->setParentItem(otherItem);
8975     QVERIFY(subPanel->isActive());
8976
8977     // Showing a child panel of a non-panel item will activate it.
8978     subPanel->hide();
8979     QVERIFY(!subPanel->isActive());
8980     QVERIFY(otherItem->isActive());
8981     subPanel->show();
8982     QVERIFY(subPanel->isActive());
8983
8984     // Hiding a toplevel active panel will pass activation back
8985     // to the non-panel items.
8986     rootPanel->setActive(true);
8987     rootPanel->hide();
8988     QVERIFY(!rootPanel->isActive());
8989     QVERIFY(otherItem->isActive());
8990 }
8991
8992 class MoveWhileDying : public QGraphicsRectItem
8993 {
8994 public:
8995     MoveWhileDying(QGraphicsItem *parent = 0)
8996         : QGraphicsRectItem(parent)
8997     { }
8998     ~MoveWhileDying()
8999     {
9000         foreach (QGraphicsItem *c, childItems()) {
9001             foreach (QGraphicsItem *cc, c->childItems()) {
9002                 cc->moveBy(10, 10);
9003             }
9004             c->moveBy(10, 10);
9005         }
9006         if (QGraphicsItem *p = parentItem()) { p->moveBy(10, 10); }
9007     }
9008 };
9009
9010 void tst_QGraphicsItem::moveWhileDeleting()
9011 {
9012     QGraphicsScene scene;
9013     QGraphicsRectItem *rect = new QGraphicsRectItem;
9014     MoveWhileDying *silly = new MoveWhileDying(rect);
9015     QGraphicsRectItem *child = new QGraphicsRectItem(silly);
9016     scene.addItem(rect);
9017     delete rect; // don't crash!
9018
9019     rect = new QGraphicsRectItem;
9020     silly = new MoveWhileDying(rect);
9021     child = new QGraphicsRectItem(silly);
9022
9023     QGraphicsView view(&scene);
9024     view.show();
9025 #ifdef Q_WS_X11
9026     qt_x11_wait_for_window_manager(&view);
9027 #endif
9028     QTest::qWait(125);
9029
9030     delete rect;
9031
9032     rect = new QGraphicsRectItem;
9033     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
9034     silly = new MoveWhileDying(rect);
9035     child = new QGraphicsRectItem(silly);
9036
9037     QTest::qWait(125);
9038
9039     delete rect;
9040
9041     rect = new MoveWhileDying;
9042     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
9043     child = new QGraphicsRectItem(rect);
9044     silly = new MoveWhileDying(child);
9045
9046     QTest::qWait(125);
9047
9048     delete rect;
9049 }
9050
9051 class MyRectItem : public QGraphicsWidget
9052 {
9053     Q_OBJECT
9054 public:
9055     MyRectItem(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
9056     {
9057
9058     }
9059
9060     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
9061     {
9062         painter->setBrush(brush);
9063         painter->drawRect(boundingRect());
9064     }
9065     void move()
9066     {
9067         setPos(-100,-100);
9068         topLevel->collidingItems(Qt::IntersectsItemBoundingRect);
9069     }
9070 public:
9071     QGraphicsItem *topLevel;
9072     QBrush brush;
9073 };
9074
9075
9076 void tst_QGraphicsItem::ensureDirtySceneTransform()
9077 {
9078     QGraphicsScene scene;
9079
9080     MyRectItem *topLevel = new MyRectItem;
9081     topLevel->setGeometry(0, 0, 100, 100);
9082     topLevel->setPos(-50, -50);
9083     topLevel->brush = QBrush(QColor(Qt::black));
9084     scene.addItem(topLevel);
9085
9086     MyRectItem *parent = new MyRectItem;
9087     parent->topLevel = topLevel;
9088     parent->setGeometry(0, 0, 100, 100);
9089     parent->setPos(0, 0);
9090     parent->brush = QBrush(QColor(Qt::magenta));
9091     parent->setObjectName("parent");
9092     scene.addItem(parent);
9093
9094     MyRectItem *child = new MyRectItem(parent);
9095     child->setGeometry(0, 0, 80, 80);
9096     child->setPos(10, 10);
9097     child->setObjectName("child");
9098     child->brush = QBrush(QColor(Qt::blue));
9099
9100     MyRectItem *child2 = new MyRectItem(parent);
9101     child2->setGeometry(0, 0, 80, 80);
9102     child2->setPos(15, 15);
9103     child2->setObjectName("child2");
9104     child2->brush = QBrush(QColor(Qt::green));
9105
9106     MyRectItem *child3 = new MyRectItem(parent);
9107     child3->setGeometry(0, 0, 80, 80);
9108     child3->setPos(20, 20);
9109     child3->setObjectName("child3");
9110     child3->brush = QBrush(QColor(Qt::gray));
9111
9112     QGraphicsView view(&scene);
9113     view.show();
9114     QTest::qWaitForWindowShown(&view);
9115     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
9116
9117     //We move the parent
9118     parent->move();
9119     QApplication::processEvents();
9120
9121     //We check if all items moved
9122     QCOMPARE(child->pos(), QPointF(10, 10));
9123     QCOMPARE(child2->pos(), QPointF(15, 15));
9124     QCOMPARE(child3->pos(), QPointF(20, 20));
9125
9126     QCOMPARE(child->sceneBoundingRect(), QRectF(-90, -90, 80, 80));
9127     QCOMPARE(child2->sceneBoundingRect(), QRectF(-85, -85, 80, 80));
9128     QCOMPARE(child3->sceneBoundingRect(), QRectF(-80, -80, 80, 80));
9129
9130     QCOMPARE(child->sceneTransform(), QTransform::fromTranslate(-90, -90));
9131     QCOMPARE(child2->sceneTransform(), QTransform::fromTranslate(-85, -85));
9132     QCOMPARE(child3->sceneTransform(), QTransform::fromTranslate(-80, -80));
9133 }
9134
9135 void tst_QGraphicsItem::focusScope()
9136 {
9137     // ItemIsFocusScope is an internal feature (for now).
9138     QGraphicsScene scene;
9139
9140     QGraphicsRectItem *scope3 = new QGraphicsRectItem;
9141     scope3->setData(0, "scope3");
9142     scope3->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9143     scope3->setFocus();
9144     QVERIFY(!scope3->focusScopeItem());
9145     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9146
9147     QGraphicsRectItem *scope2 = new QGraphicsRectItem;
9148     scope2->setData(0, "scope2");
9149     scope2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9150     scope2->setFocus();
9151     QVERIFY(!scope2->focusScopeItem());
9152     scope3->setParentItem(scope2);
9153     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9154     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9155
9156     QGraphicsRectItem *scope1 = new QGraphicsRectItem;
9157     scope1->setData(0, "scope1");
9158     scope1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9159     scope1->setFocus();
9160     QVERIFY(!scope1->focusScopeItem());
9161     scope2->setParentItem(scope1);
9162
9163     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9164     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9165     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9166     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9167     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9168     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9169
9170     scene.addItem(scope1);
9171
9172     QEvent windowActivate(QEvent::WindowActivate);
9173     qApp->sendEvent(&scene, &windowActivate);
9174     scene.setFocus();
9175
9176     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9177     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9178     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9179     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9180     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9181     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9182
9183     QVERIFY(scope3->hasFocus());
9184
9185     scope3->hide();
9186     QVERIFY(scope2->hasFocus());
9187     scope2->hide();
9188     QVERIFY(scope1->hasFocus());
9189     scope2->show();
9190     QVERIFY(scope2->hasFocus());
9191     scope3->show();
9192     QVERIFY(scope3->hasFocus());
9193     scope1->hide();
9194     QVERIFY(!scope3->hasFocus());
9195     scope1->show();
9196     QVERIFY(scope3->hasFocus());
9197     scope3->clearFocus();
9198     QVERIFY(scope2->hasFocus());
9199     scope2->clearFocus();
9200     QVERIFY(scope1->hasFocus());
9201     scope2->hide();
9202     scope2->show();
9203     QVERIFY(!scope2->hasFocus());
9204     QVERIFY(scope1->hasFocus());
9205     scope2->setFocus();
9206     QVERIFY(scope2->hasFocus());
9207     scope3->setFocus();
9208     QVERIFY(scope3->hasFocus());
9209
9210     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
9211     rect4->setData(0, "rect4");
9212     rect4->setParentItem(scope3);
9213
9214     QGraphicsRectItem *rect5 = new QGraphicsRectItem;
9215     rect5->setData(0, "rect5");
9216     rect5->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9217     rect5->setFocus();
9218     rect5->setParentItem(rect4);
9219     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)rect5);
9220     QVERIFY(rect5->hasFocus());
9221
9222     rect4->setParentItem(0);
9223     QVERIFY(rect5->hasFocus());
9224     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9225     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)0);
9226     QVERIFY(!scope3->hasFocus());
9227
9228     QGraphicsRectItem *rectA = new QGraphicsRectItem;
9229     QGraphicsRectItem *scopeA = new QGraphicsRectItem(rectA);
9230     scopeA->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9231     scopeA->setFocus();
9232     QGraphicsRectItem *scopeB = new QGraphicsRectItem(scopeA);
9233     scopeB->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9234     scopeB->setFocus();
9235
9236     scene.addItem(rectA);
9237     QVERIFY(rect5->hasFocus());
9238     QVERIFY(!scopeB->hasFocus());
9239
9240     scopeA->setFocus();
9241     QVERIFY(scopeB->hasFocus());
9242     QCOMPARE(scopeB->focusItem(), (QGraphicsItem *)scopeB);
9243 }
9244
9245 void tst_QGraphicsItem::focusScope2()
9246 {
9247     QGraphicsRectItem *child1 = new QGraphicsRectItem;
9248     child1->setFlags(QGraphicsItem::ItemIsFocusable);
9249     child1->setFocus();
9250     QCOMPARE(child1->focusItem(), (QGraphicsItem *)child1);
9251
9252     QGraphicsRectItem *child2 = new QGraphicsRectItem;
9253     child2->setFlags(QGraphicsItem::ItemIsFocusable);
9254
9255     QGraphicsRectItem *rootFocusScope = new QGraphicsRectItem;
9256     rootFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9257     rootFocusScope->setFocus();
9258     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)rootFocusScope);
9259
9260     child1->setParentItem(rootFocusScope);
9261     child2->setParentItem(rootFocusScope);
9262
9263     QCOMPARE(rootFocusScope->focusScopeItem(), (QGraphicsItem *)child1);
9264     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)child1);
9265
9266     QGraphicsRectItem *siblingChild1 = new QGraphicsRectItem;
9267     siblingChild1->setFlags(QGraphicsItem::ItemIsFocusable);
9268     siblingChild1->setFocus();
9269
9270     QGraphicsRectItem *siblingChild2 = new QGraphicsRectItem;
9271     siblingChild2->setFlags(QGraphicsItem::ItemIsFocusable);
9272
9273     QGraphicsRectItem *siblingFocusScope = new QGraphicsRectItem;
9274     siblingFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9275
9276     siblingChild1->setParentItem(siblingFocusScope);
9277     siblingChild2->setParentItem(siblingFocusScope);
9278
9279     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild1);
9280     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9281
9282     QGraphicsItem *root = new QGraphicsRectItem;
9283     rootFocusScope->setParentItem(root);
9284     siblingFocusScope->setParentItem(root);
9285
9286     QCOMPARE(root->focusItem(), (QGraphicsItem *)child1);
9287
9288     QGraphicsScene scene;
9289     scene.addItem(root);
9290
9291     QEvent activate(QEvent::WindowActivate);
9292     qApp->sendEvent(&scene, &activate);
9293     scene.setFocus();
9294
9295     QCOMPARE(scene.focusItem(), (QGraphicsItem *)child1);
9296
9297     // You cannot set focus on a descendant of a focus scope directly;
9298     // this will only change the scope's focus scope item pointer. If
9299     // you want to give true input focus, you must set it directly on
9300     // the scope itself
9301     siblingChild2->setFocus();
9302     QVERIFY(!siblingChild2->hasFocus());
9303     QVERIFY(!siblingChild2->focusItem());
9304     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9305     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9306
9307     // Set focus on the scope; focus is forwarded to the focus scope item.
9308     siblingFocusScope->setFocus();
9309     QVERIFY(siblingChild2->hasFocus());
9310     QVERIFY(siblingChild2->focusItem());
9311     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9312     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)siblingChild2);
9313 }
9314
9315 void tst_QGraphicsItem::stackBefore()
9316 {
9317     QGraphicsRectItem parent;
9318     QGraphicsRectItem *child1 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9319     QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9320     QGraphicsRectItem *child3 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9321     QGraphicsRectItem *child4 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9322     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9323     child1->setData(0, "child1");
9324     child2->setData(0, "child2");
9325     child3->setData(0, "child3");
9326     child4->setData(0, "child4");
9327
9328     // Remove and append
9329     child2->setParentItem(0);
9330     child2->setParentItem(&parent);
9331     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9332
9333     // Move child2 before child1
9334     child2->stackBefore(child1); // 2134
9335     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9336     child2->stackBefore(child2); // 2134
9337     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9338     child1->setZValue(1); // 2341
9339     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9340     child1->stackBefore(child2); // 2341
9341     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9342     child1->setZValue(0); // 1234
9343     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9344     child4->stackBefore(child1); // 4123
9345     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9346     child4->setZValue(1); // 1234 (4123)
9347     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9348     child3->stackBefore(child1); // 3124 (4312)
9349     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9350     child4->setZValue(0); // 4312
9351     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9352
9353     // Make them all toplevels
9354     child1->setParentItem(0);
9355     child2->setParentItem(0);
9356     child3->setParentItem(0);
9357     child4->setParentItem(0);
9358
9359     QGraphicsScene scene;
9360     scene.addItem(child1);
9361     scene.addItem(child2);
9362     scene.addItem(child3);
9363     scene.addItem(child4);
9364     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder),
9365              (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9366
9367     // Remove and append
9368     scene.removeItem(child2);
9369     scene.addItem(child2);
9370     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9371
9372     // Move child2 before child1
9373     child2->stackBefore(child1); // 2134
9374     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9375     child2->stackBefore(child2); // 2134
9376     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9377     child1->setZValue(1); // 2341
9378     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9379     child1->stackBefore(child2); // 2341
9380     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9381     child1->setZValue(0); // 1234
9382     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9383     child4->stackBefore(child1); // 4123
9384     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9385     child4->setZValue(1); // 1234 (4123)
9386     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9387     child3->stackBefore(child1); // 3124 (4312)
9388     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9389     child4->setZValue(0); // 4312
9390     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9391 }
9392
9393 void tst_QGraphicsItem::QTBUG_4233_updateCachedWithSceneRect()
9394 {
9395     EventTester *tester = new EventTester;
9396     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
9397
9398     QGraphicsScene scene;
9399     scene.addItem(tester);
9400     scene.setSceneRect(-100, -100, 200, 200); // contains the tester item
9401
9402     QGraphicsView view(&scene);
9403     view.show();
9404     QTest::qWaitForWindowShown(&view);
9405     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
9406
9407     QTRY_COMPARE(tester->repaints, 1);
9408
9409     scene.update(); // triggers "updateAll" optimization
9410     qApp->processEvents();
9411     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9412
9413     QCOMPARE(tester->repaints, 1);
9414
9415     scene.update(); // triggers "updateAll" optimization
9416     tester->update();
9417     qApp->processEvents();
9418     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9419
9420     QCOMPARE(tester->repaints, 2);
9421 }
9422
9423 void tst_QGraphicsItem::sceneModality()
9424 {
9425     // 1) Test mouse events (delivery/propagation/redirection)
9426     // 2) Test hover events (incl. leave on block, enter on unblock)
9427     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9428     // 4) Test clickfocus
9429     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9430     // 6) ### modality for non-panels is unsupported for now
9431     QGraphicsScene scene;
9432
9433     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9434     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9435     bottomItem->setBrush(Qt::yellow);
9436
9437     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9438     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9439     leftParent->setBrush(Qt::blue);
9440
9441     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9442     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9443     leftChild->setBrush(Qt::green);
9444     leftChild->setParentItem(leftParent);
9445
9446     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9447     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9448     rightParent->setBrush(Qt::red);
9449     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9450     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9451     rightChild->setBrush(Qt::gray);
9452     rightChild->setParentItem(rightParent);
9453
9454     leftParent->setPos(-75, 0);
9455     rightParent->setPos(75, 0);
9456
9457     bottomItem->setData(0, "bottomItem");
9458     leftParent->setData(0, "leftParent");
9459     leftChild->setData(0, "leftChild");
9460     rightParent->setData(0, "rightParent");
9461     rightChild->setData(0, "rightChild");
9462
9463     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9464
9465     EventSpy2 leftParentSpy(&scene, leftParent);
9466     EventSpy2 leftChildSpy(&scene, leftChild);
9467     EventSpy2 rightParentSpy(&scene, rightParent);
9468     EventSpy2 rightChildSpy(&scene, rightChild);
9469     EventSpy2 bottomItemSpy(&scene, bottomItem);
9470
9471     // Scene modality, also test multiple scene modal items
9472     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9473     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9474     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9475     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9476     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9477     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // not a panel
9478
9479     // Click inside left child
9480     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9481     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9482     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9483     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9484     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9485     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9486     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9487
9488     // Click on left parent, event goes to modal child
9489     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9490     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9491     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9492     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9493     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9494     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9495     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9496
9497     // Click on all other items and outside the items
9498     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9499     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9500     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9501     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9502     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9503     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9504     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9505     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9506     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9507     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9508     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9509     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9510     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9511
9512     leftChildSpy.counts.clear();
9513     rightChildSpy.counts.clear();
9514     leftParentSpy.counts.clear();
9515     rightParentSpy.counts.clear();
9516     bottomItemSpy.counts.clear();
9517
9518     leftChild->setPanelModality(QGraphicsItem::NonModal);
9519     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9520     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9521     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9522     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 1);
9523     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9524
9525     // Left parent enters scene modality.
9526     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9527     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9528     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9529     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9530     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9531     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9532
9533     // Click inside left child.
9534     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9535     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9536     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9537     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // panel stops propagation
9538     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9539     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9540     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9541
9542    // Click on left parent.
9543     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9544     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9545     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9546     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9547     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9548     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9549     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9550
9551     // Click on all other items and outside the items
9552     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9553     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9554     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9555     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9556     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9557     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9558     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9559     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9560     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9561     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9562     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9563     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9564     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9565
9566     leftChildSpy.counts.clear();
9567     rightChildSpy.counts.clear();
9568     leftParentSpy.counts.clear();
9569     rightParentSpy.counts.clear();
9570     bottomItemSpy.counts.clear();
9571
9572     // Now both left parent and child are scene modal. Left parent is blocked.
9573     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9574     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9575     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9576     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9577     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9578     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9579
9580     // Click inside left child
9581     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9582     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9583     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9584     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9585     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9586     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9587     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9588
9589     // Click on left parent, event goes to modal child
9590     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9591     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9592     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9593     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9594     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9595     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9596     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9597
9598     // Click on all other items and outside the items
9599     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9600     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9601     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9602     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9603     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9604     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9605     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9606     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9607     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9608     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9609     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9610     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9611     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9612
9613     leftChildSpy.counts.clear();
9614     rightChildSpy.counts.clear();
9615     leftParentSpy.counts.clear();
9616     rightParentSpy.counts.clear();
9617     bottomItemSpy.counts.clear();
9618
9619     // Right child enters scene modality, only left child is blocked.
9620     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9621     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9622     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9623     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9624     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9625     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9626 }
9627
9628 void tst_QGraphicsItem::panelModality()
9629 {
9630     // 1) Test mouse events (delivery/propagation/redirection)
9631     // 2) Test hover events (incl. leave on block, enter on unblock)
9632     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9633     // 4) Test clickfocus
9634     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9635     // 6) ### modality for non-panels is unsupported for now
9636     QGraphicsScene scene;
9637
9638     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9639     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9640     bottomItem->setBrush(Qt::yellow);
9641
9642     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9643     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9644     leftParent->setBrush(Qt::blue);
9645
9646     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9647     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9648     leftChild->setBrush(Qt::green);
9649     leftChild->setParentItem(leftParent);
9650
9651     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9652     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9653     rightParent->setBrush(Qt::red);
9654     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9655     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9656     rightChild->setBrush(Qt::gray);
9657     rightChild->setParentItem(rightParent);
9658
9659     leftParent->setPos(-75, 0);
9660     rightParent->setPos(75, 0);
9661
9662     bottomItem->setData(0, "bottomItem");
9663     leftParent->setData(0, "leftParent");
9664     leftChild->setData(0, "leftChild");
9665     rightParent->setData(0, "rightParent");
9666     rightChild->setData(0, "rightChild");
9667
9668     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9669
9670     EventSpy2 leftParentSpy(&scene, leftParent);
9671     EventSpy2 leftChildSpy(&scene, leftChild);
9672     EventSpy2 rightParentSpy(&scene, rightParent);
9673     EventSpy2 rightChildSpy(&scene, rightChild);
9674     EventSpy2 bottomItemSpy(&scene, bottomItem);
9675
9676     // Left Child enters panel modality, only left parent is blocked.
9677     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9678     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9679     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9680     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9681     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9682     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9683
9684     leftChild->setPanelModality(QGraphicsItem::NonModal);
9685     leftChildSpy.counts.clear();
9686     rightChildSpy.counts.clear();
9687     leftParentSpy.counts.clear();
9688     rightParentSpy.counts.clear();
9689     bottomItemSpy.counts.clear();
9690
9691     // Left parent enter panel modality, nothing is blocked.
9692     leftParent->setPanelModality(QGraphicsItem::PanelModal);
9693     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9694     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9695     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9696     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9697     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9698
9699     // Left child enters panel modality, left parent is blocked again.
9700     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9701     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9702     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9703     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9704     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9705     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9706
9707     leftChildSpy.counts.clear();
9708     rightChildSpy.counts.clear();
9709     leftParentSpy.counts.clear();
9710     rightParentSpy.counts.clear();
9711     bottomItemSpy.counts.clear();
9712
9713     leftChild->setPanelModality(QGraphicsItem::NonModal);
9714     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9715     leftParent->setPanelModality(QGraphicsItem::NonModal);
9716     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9717     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9718     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9719     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9720     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9721
9722     leftChildSpy.counts.clear();
9723     rightChildSpy.counts.clear();
9724     leftParentSpy.counts.clear();
9725     rightParentSpy.counts.clear();
9726     bottomItemSpy.counts.clear();
9727
9728     // Left and right child enter panel modality, both parents are blocked.
9729     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9730     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9731     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9732     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9733     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9734     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9735 }
9736
9737 void tst_QGraphicsItem::mixedModality()
9738 {
9739     // 1) Test mouse events (delivery/propagation/redirection)
9740     // 2) Test hover events (incl. leave on block, enter on unblock)
9741     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9742     // 4) Test clickfocus
9743     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9744     // 6) ### modality for non-panels is unsupported for now
9745     QGraphicsScene scene;
9746
9747     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9748     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9749     bottomItem->setBrush(Qt::yellow);
9750
9751     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9752     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9753     leftParent->setBrush(Qt::blue);
9754
9755     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9756     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9757     leftChild->setBrush(Qt::green);
9758     leftChild->setParentItem(leftParent);
9759
9760     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9761     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9762     rightParent->setBrush(Qt::red);
9763     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9764     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9765     rightChild->setBrush(Qt::gray);
9766     rightChild->setParentItem(rightParent);
9767
9768     leftParent->setPos(-75, 0);
9769     rightParent->setPos(75, 0);
9770
9771     bottomItem->setData(0, "bottomItem");
9772     leftParent->setData(0, "leftParent");
9773     leftChild->setData(0, "leftChild");
9774     rightParent->setData(0, "rightParent");
9775     rightChild->setData(0, "rightChild");
9776
9777     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9778
9779     EventSpy2 leftParentSpy(&scene, leftParent);
9780     EventSpy2 leftChildSpy(&scene, leftChild);
9781     EventSpy2 rightParentSpy(&scene, rightParent);
9782     EventSpy2 rightChildSpy(&scene, rightChild);
9783     EventSpy2 bottomItemSpy(&scene, bottomItem);
9784
9785     // Left Child enters panel modality, only left parent is blocked.
9786     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9787     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9788     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9789     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9790     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9791
9792     // Left parent enters scene modality, which blocks everything except the child.
9793     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9794     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9795     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9796     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9797     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9798     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9799     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9800     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9801     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9802
9803     // Right child enters panel modality (changes nothing).
9804     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9805     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9806     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9807     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9808     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9809     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9810     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9811     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9812     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9813
9814     // Left parent leaves modality. Right child is unblocked.
9815     leftParent->setPanelModality(QGraphicsItem::NonModal);
9816     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9817     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9818     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9819     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9820     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9821     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9822     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9823     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9824
9825     // Right child "upgrades" its modality to scene modal. Left child is blocked.
9826     // Right parent is unaffected.
9827     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9828     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9829     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9830     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9831     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9832     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9833     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9834     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9835     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9836
9837     // "downgrade" right child back to panel modal, left child is unblocked
9838     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9839     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9840     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 1);
9841     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9842     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9843     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9844     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9845     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9846     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9847 }
9848
9849 void tst_QGraphicsItem::modality_hover()
9850 {
9851     QGraphicsScene scene;
9852     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9853     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9854     rect1->setAcceptHoverEvents(true);
9855     rect1->setData(0, "rect1");
9856
9857     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9858     rect2->setParentItem(rect1);
9859     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9860     rect2->setAcceptHoverEvents(true);
9861     rect2->setPos(50, 50);
9862     rect2->setPanelModality(QGraphicsItem::SceneModal);
9863     rect2->setData(0, "rect2");
9864
9865     EventSpy2 rect1Spy(&scene, rect1);
9866     EventSpy2 rect2Spy(&scene, rect2);
9867
9868     sendMouseMove(&scene, QPointF(-25, -25));
9869
9870     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9871     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9872     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9873
9874     sendMouseMove(&scene, QPointF(75, 75));
9875
9876     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9877     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9878     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9879     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9880     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9881     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9882
9883     sendMouseMove(&scene, QPointF(-25, -25));
9884
9885     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9886     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9887     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9888     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9889
9890     rect2->setPanelModality(QGraphicsItem::NonModal);
9891
9892     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9893     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9894
9895     sendMouseMove(&scene, QPointF(75, 75));
9896
9897     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9898     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9899
9900     rect2->setPanelModality(QGraphicsItem::SceneModal);
9901
9902     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9903     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9904     // changing modality causes a spurious GraphicsSceneHoveMove, even though the mouse didn't
9905     // actually move
9906     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9907
9908     sendMouseMove(&scene, QPointF(-25, -25));
9909
9910     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9911     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9912     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9913     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9914
9915     rect2->setPanelModality(QGraphicsItem::PanelModal);
9916
9917     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9918     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9919     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9920     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9921     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9922     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9923
9924     rect2->setPanelModality(QGraphicsItem::NonModal);
9925
9926     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9927     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9928     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9929     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9930     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9931 }
9932
9933 void tst_QGraphicsItem::modality_mouseGrabber()
9934 {
9935     QGraphicsScene scene;
9936     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9937     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9938     rect1->setFlag(QGraphicsItem::ItemIsMovable);
9939     rect1->setData(0, "rect1");
9940
9941     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9942     rect2->setParentItem(rect1);
9943     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9944     rect2->setFlag(QGraphicsItem::ItemIsMovable);
9945     rect2->setPos(50, 50);
9946     rect2->setData(0, "rect2");
9947
9948     EventSpy2 rect1Spy(&scene, rect1);
9949     EventSpy2 rect2Spy(&scene, rect2);
9950
9951     {
9952         // pressing mouse on rect1 starts implicit grab
9953         sendMousePress(&scene, QPoint(-25, -25));
9954         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9955         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9956         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
9957         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9958         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9959         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9960
9961         // grab lost when rect1 is modally shadowed
9962         rect2->setPanelModality(QGraphicsItem::SceneModal);
9963         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9964         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9965         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9966         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9967         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9968
9969         // releasing goes nowhere
9970         sendMouseRelease(&scene, QPoint(-25, -25));
9971         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9972         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9973         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9974         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9975         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9976         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9977         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9978
9979         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
9980         sendMouseClick(&scene, QPoint(-25, -25));
9981         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9982         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9983         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9984         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9985         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9986         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9987         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
9988         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9989
9990         rect2->setPanelModality(QGraphicsItem::NonModal);
9991
9992         // pressing mouse on rect1 starts implicit grab
9993         sendMousePress(&scene, QPoint(-25, -25));
9994         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9995         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
9996         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9997         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9998         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9999         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10000
10001         // grab lost to rect2 when rect1 is modally shadowed
10002         rect2->setPanelModality(QGraphicsItem::SceneModal);
10003         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10004         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10005         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10006         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10007         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10008
10009         // rect1 does *not* re-grab when rect2 is no longer modal
10010         rect2->setPanelModality(QGraphicsItem::NonModal);
10011         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10012         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10013         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10014         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10015         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10016
10017         // release goes nowhere
10018         sendMouseRelease(&scene, QPoint(-25, -25));
10019         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10020         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10021         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10022         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10023         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10024         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10025     }
10026     {
10027         // repeat the test using PanelModal
10028         rect2->setPanelModality(QGraphicsItem::NonModal);
10029         rect1Spy.counts.clear();
10030         rect2Spy.counts.clear();
10031
10032         // pressing mouse on rect1 starts implicit grab
10033         sendMousePress(&scene, QPoint(-25, -25));
10034         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10035         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10036         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10037         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10038         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10039         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10040
10041         // grab lost when rect1 is modally shadowed
10042         rect2->setPanelModality(QGraphicsItem::PanelModal);
10043         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10044         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10045         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10046         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10047         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10048
10049         // releasing goes nowhere
10050         sendMouseRelease(&scene, QPoint(-25, -25));
10051         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10052         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10053         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10054         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10055         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10056         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10057         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10058
10059         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
10060         sendMouseClick(&scene, QPoint(-25, -25));
10061         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10062         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10063         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10064         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10065         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10066         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10067         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10068         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10069
10070         rect2->setPanelModality(QGraphicsItem::NonModal);
10071
10072         // pressing mouse on rect1 starts implicit grab
10073         sendMousePress(&scene, QPoint(-25, -25));
10074         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10075         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
10076         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10077         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10078         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10079         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10080
10081         // grab lost to rect2 when rect1 is modally shadowed
10082         rect2->setPanelModality(QGraphicsItem::PanelModal);
10083         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10084         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10085         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10086         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10087         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10088
10089         // rect1 does *not* re-grab when rect2 is no longer modal
10090         rect2->setPanelModality(QGraphicsItem::NonModal);
10091         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10092         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10093         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10094         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10095         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10096
10097         // release goes nowhere
10098         sendMouseRelease(&scene, QPoint(-25, -25));
10099         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10100         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10101         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10102         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10103         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10104         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10105     }
10106
10107     {
10108         // repeat the PanelModal tests, but this time the mouse events will be on a non-modal item,
10109         // meaning normal grabbing should work
10110         rect2->setPanelModality(QGraphicsItem::NonModal);
10111         rect1Spy.counts.clear();
10112         rect2Spy.counts.clear();
10113
10114         QGraphicsRectItem *rect3 = scene.addRect(-50, -50, 100, 100);
10115         rect3->setFlag(QGraphicsItem::ItemIsPanel);
10116         rect3->setFlag(QGraphicsItem::ItemIsMovable);
10117         rect3->setPos(150, 50);
10118         rect3->setData(0, "rect3");
10119
10120         EventSpy2 rect3Spy(&scene, rect3);
10121
10122         // pressing mouse on rect3 starts implicit grab
10123         sendMousePress(&scene, QPoint(150, 50));
10124         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10125         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10126         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10127         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10128         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10129         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10130         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10131         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10132
10133         // grab is *not* lost when rect1 is modally shadowed by rect2
10134         rect2->setPanelModality(QGraphicsItem::PanelModal);
10135         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10136         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10137         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10138         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10139         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10140         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10141         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10142
10143         // releasing goes to rect3
10144         sendMouseRelease(&scene, QPoint(150, 50));
10145         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10146         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10147         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10148         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10149         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10150         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10151         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10152         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10153
10154         rect2->setPanelModality(QGraphicsItem::NonModal);
10155
10156         // pressing mouse on rect3 starts implicit grab
10157         sendMousePress(&scene, QPoint(150, 50));
10158         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10159         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10160         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10161         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10162         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10163         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10164         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10165
10166         // grab is not lost
10167         rect2->setPanelModality(QGraphicsItem::PanelModal);
10168         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10169         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10170         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10171         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10172         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10173         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10174         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10175
10176         // grab stays on rect3
10177         rect2->setPanelModality(QGraphicsItem::NonModal);
10178         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10179         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10180         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10181         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10182         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10183         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10184         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10185
10186         // release goes to rect3
10187         sendMouseRelease(&scene, QPoint(150, 50));
10188         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10189         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10190         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10191         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10192         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10193         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 2);
10194         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10195     }
10196 }
10197
10198 void tst_QGraphicsItem::modality_clickFocus()
10199 {
10200     QGraphicsScene scene;
10201     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10202     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10203     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10204     rect1->setData(0, "rect1");
10205
10206     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10207     rect2->setParentItem(rect1);
10208     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10209     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10210     rect2->setPos(50, 50);
10211     rect2->setData(0, "rect2");
10212
10213     QEvent windowActivateEvent(QEvent::WindowActivate);
10214     QApplication::sendEvent(&scene, &windowActivateEvent);
10215
10216     EventSpy2 rect1Spy(&scene, rect1);
10217     EventSpy2 rect2Spy(&scene, rect2);
10218
10219     // activate rect1, it should not get focus
10220     rect1->setActive(true);
10221     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10222
10223     // focus stays unset when rect2 becomes modal
10224     rect2->setPanelModality(QGraphicsItem::SceneModal);
10225     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10226     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10227     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10228     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10229     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10230
10231     // clicking on rect1 should not set it's focus item
10232     sendMouseClick(&scene, QPointF(-25, -25));
10233     QCOMPARE(rect1->focusItem(), (QGraphicsItem *) 0);
10234     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10235     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10236     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10237     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10238
10239     // clicking on rect2 gives it focus
10240     rect2->setActive(true);
10241     sendMouseClick(&scene, QPointF(75, 75));
10242     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect2);
10243     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10244     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10245     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10246     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10247
10248     // clicking on rect1 does *not* give it focus
10249     rect1->setActive(true);
10250     sendMouseClick(&scene, QPointF(-25, -25));
10251     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10252     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10253     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10254     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10255     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10256
10257     // focus doesn't change when leaving modality either
10258     rect2->setPanelModality(QGraphicsItem::NonModal);
10259     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10260     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10261     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10262     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10263     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10264
10265     // click on rect1, it should get focus now
10266     sendMouseClick(&scene, QPointF(-25, -25));
10267     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1);
10268     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 1);
10269     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10270     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10271     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10272 }
10273
10274 void tst_QGraphicsItem::modality_keyEvents()
10275 {
10276     QGraphicsScene scene;
10277     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10278     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10279     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10280     rect1->setData(0, "rect1");
10281
10282     QGraphicsRectItem *rect1child = scene.addRect(-10, -10, 20, 20);
10283     rect1child->setParentItem(rect1);
10284     rect1child->setFlag(QGraphicsItem::ItemIsFocusable);
10285     rect1child->setData(0, "rect1child1");
10286
10287     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10288     rect2->setParentItem(rect1);
10289     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10290     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10291     rect2->setPos(50, 50);
10292     rect2->setData(0, "rect2");
10293
10294     QGraphicsRectItem *rect2child = scene.addRect(-10, -10, 20, 20);
10295     rect2child->setParentItem(rect2);
10296     rect2child->setFlag(QGraphicsItem::ItemIsFocusable);
10297     rect2child->setData(0, "rect2child1");
10298
10299     QEvent windowActivateEvent(QEvent::WindowActivate);
10300     QApplication::sendEvent(&scene, &windowActivateEvent);
10301
10302     EventSpy2 rect1Spy(&scene, rect1);
10303     EventSpy2 rect1childSpy(&scene, rect1child);
10304     EventSpy2 rect2Spy(&scene, rect2);
10305     EventSpy2 rect2childSpy(&scene, rect2child);
10306
10307     // activate rect1 and give it rect1child focus
10308     rect1->setActive(true);
10309     rect1child->setFocus();
10310     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10311
10312     // focus stays on rect1child when rect2 becomes modal
10313     rect2->setPanelModality(QGraphicsItem::SceneModal);
10314     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10315
10316     // but key events to rect1child should be neither delivered nor propagated
10317     sendKeyClick(&scene, Qt::Key_A);
10318     sendKeyClick(&scene, Qt::Key_S);
10319     sendKeyClick(&scene, Qt::Key_D);
10320     sendKeyClick(&scene, Qt::Key_F);
10321     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10322     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10323     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10324     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10325
10326     // change to panel modality, rect1child1 keeps focus
10327     rect2->setPanelModality(QGraphicsItem::PanelModal);
10328     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10329
10330     // still no key events
10331     sendKeyClick(&scene, Qt::Key_J);
10332     sendKeyClick(&scene, Qt::Key_K);
10333     sendKeyClick(&scene, Qt::Key_L);
10334     sendKeyClick(&scene, Qt::Key_Semicolon);
10335     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10336     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10337     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10338     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10339 }
10340
10341 void tst_QGraphicsItem::itemIsInFront()
10342 {
10343     QGraphicsScene scene;
10344     QGraphicsRectItem *rect1 = new QGraphicsRectItem;
10345     rect1->setData(0, "rect1");
10346     scene.addItem(rect1);
10347
10348     QGraphicsRectItem *rect1child1 = new QGraphicsRectItem(rect1);
10349     rect1child1->setZValue(1);
10350     rect1child1->setData(0, "rect1child1");
10351
10352     QGraphicsRectItem *rect1child2 = new QGraphicsRectItem(rect1);
10353     rect1child2->setParentItem(rect1);
10354     rect1child2->setData(0, "rect1child2");
10355
10356     QGraphicsRectItem *rect1child1_1 = new QGraphicsRectItem(rect1child1);
10357     rect1child1_1->setData(0, "rect1child1_1");
10358
10359     QGraphicsRectItem *rect1child1_2 = new QGraphicsRectItem(rect1child1);
10360     rect1child1_2->setFlag(QGraphicsItem::ItemStacksBehindParent);
10361     rect1child1_2->setData(0, "rect1child1_2");
10362
10363     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
10364     rect2->setData(0, "rect2");
10365     scene.addItem(rect2);
10366
10367     QGraphicsRectItem *rect2child1 = new QGraphicsRectItem(rect2);
10368     rect2child1->setData(0, "rect2child1");
10369
10370     QCOMPARE(qt_closestItemFirst(rect1, rect1), false);
10371     QCOMPARE(qt_closestItemFirst(rect1, rect2), false);
10372     QCOMPARE(qt_closestItemFirst(rect1child1, rect2child1), false);
10373     QCOMPARE(qt_closestItemFirst(rect1child1, rect1child2), true);
10374     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child2), true);
10375     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child1), true);
10376     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child2), true);
10377     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child1), false);
10378     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1), true);
10379     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2), false);
10380     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2child1), false);
10381 }
10382
10383 class ScenePosChangeTester : public ItemChangeTester
10384 {
10385 public:
10386     ScenePosChangeTester()
10387     { }
10388     ScenePosChangeTester(QGraphicsItem *parent) : ItemChangeTester(parent)
10389     { }
10390 };
10391
10392 void tst_QGraphicsItem::scenePosChange()
10393 {
10394     ScenePosChangeTester* root = new ScenePosChangeTester;
10395     ScenePosChangeTester* child1 = new ScenePosChangeTester(root);
10396     ScenePosChangeTester* grandChild1 = new ScenePosChangeTester(child1);
10397     ScenePosChangeTester* child2 = new ScenePosChangeTester(root);
10398     ScenePosChangeTester* grandChild2 = new ScenePosChangeTester(child2);
10399
10400     child1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10401     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10402
10403     QVERIFY(child1->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10404     QVERIFY(grandChild2->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10405
10406     QGraphicsScene scene;
10407     scene.addItem(root);
10408
10409     // ignore uninteresting changes
10410     child1->clear();
10411     child2->clear();
10412     grandChild1->clear();
10413     grandChild2->clear();
10414
10415     // move whole tree
10416     root->moveBy(1.0, 1.0);
10417     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10418     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10419     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10420     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10421
10422     // move subtree
10423     child2->moveBy(1.0, 1.0);
10424     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10425     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10426     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10427     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10428
10429     // reparent
10430     grandChild2->setParentItem(child1);
10431     child1->moveBy(1.0, 1.0);
10432     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10433     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10434     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10435     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10436
10437     // change flags
10438     grandChild1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10439     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false);
10440     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10441     child1->moveBy(1.0, 1.0);
10442     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10443     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10444     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10445     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10446
10447     // remove
10448     scene.removeItem(grandChild1);
10449     delete grandChild2; grandChild2 = 0;
10450     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10451     root->moveBy(1.0, 1.0);
10452     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 4);
10453     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10454     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10455
10456     root->setX(1);
10457     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 5);
10458     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10459     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10460
10461     root->setY(1);
10462     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 6);
10463     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10464     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10465 }
10466
10467 class MyInputContext : public QInputContext
10468 {
10469 public:
10470     MyInputContext() : nbUpdates(0) {}
10471     ~MyInputContext() {}
10472
10473     QString identifierName() { return QString(); }
10474     QString language() { return QString(); }
10475
10476     void reset() {}
10477
10478     bool isComposing() const { return false; }
10479
10480     void update() { nbUpdates++; }
10481
10482     bool nbUpdates;
10483 };
10484
10485 class MyInputWidget : public QGraphicsWidget
10486 {
10487 public:
10488     MyInputWidget()
10489     {
10490         setFlag(QGraphicsItem::ItemIsFocusable, true);
10491         setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
10492     }
10493     void mousePressEvent(QGraphicsSceneMouseEvent *event)
10494     {
10495         event->accept();
10496     }
10497
10498     void doUpdateMicroFocus()
10499     {
10500         if (QWidget *fw = QApplication::focusWidget()) {
10501             if (scene()) {
10502                 for (int i = 0 ; i < scene()->views().count() ; ++i) {
10503                     if (scene()->views().at(i) == fw) {
10504                         if (QInputContext *inputContext = fw->inputContext()) {
10505                             inputContext->update();
10506                         }
10507                     }
10508                 }
10509             }
10510         }
10511     }
10512 };
10513
10514 void tst_QGraphicsItem::updateMicroFocus()
10515 {
10516 #if defined Q_OS_WIN || defined Q_OS_MAC
10517     QSKIP("QTBUG-9578");
10518 #endif
10519     QGraphicsScene scene;
10520     QWidget parent;
10521     QGridLayout layout;
10522     parent.setLayout(&layout);
10523     QGraphicsView view(&scene);
10524     QGraphicsView view2(&scene);
10525     layout.addWidget(&view, 0, 0);
10526     layout.addWidget(&view2, 0, 1);
10527     MyInputContext *ic = new MyInputContext;
10528     qApp->setInputContext(ic);
10529     MyInputWidget input;
10530     input.setPos(0, 0);
10531     input.resize(150, 150);
10532     scene.addItem(&input);
10533     input.setFocus();
10534     parent.show();
10535     view.setFocus();
10536     qApp->setAutoSipEnabled(true);
10537     QApplication::setActiveWindow(&parent);
10538     QTest::qWaitForWindowShown(&parent);
10539     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&parent));
10540     //We reset the number of updates that happened previously (initialisation)
10541     ic->nbUpdates = 0;
10542     input.doUpdateMicroFocus();
10543     QApplication::processEvents();
10544     QTRY_COMPARE(ic->nbUpdates, 1);
10545 }
10546
10547 void tst_QGraphicsItem::textItem_shortcuts()
10548 {
10549     QWidget w;
10550     QVBoxLayout l;
10551     w.setLayout(&l);
10552     QGraphicsScene scene;
10553     QGraphicsView view(&scene);
10554     l.addWidget(&view);
10555     QPushButton b("Push Me");
10556     l.addWidget(&b);
10557
10558     QGraphicsTextItem *item = scene.addText("Troll Text");
10559     item->setFlag(QGraphicsItem::ItemIsFocusable);
10560     item->setTextInteractionFlags(Qt::TextEditorInteraction);
10561     w.show();
10562     QTest::qWaitForWindowShown(&w);
10563
10564     item->setFocus();
10565     QTRY_VERIFY(item->hasFocus());
10566     QVERIFY(item->textCursor().selectedText().isEmpty());
10567
10568     // Shortcut should work (select all)
10569     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10570     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10571     QTextCursor tc = item->textCursor();
10572     tc.clearSelection();
10573     item->setTextCursor(tc);
10574     QVERIFY(item->textCursor().selectedText().isEmpty());
10575
10576     // Shortcut should also work if the text item has the focus and another widget
10577     // has the same shortcut.
10578     b.setShortcut(QKeySequence("CTRL+A"));
10579     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10580     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10581 }
10582
10583 void tst_QGraphicsItem::scroll()
10584 {
10585     // Create two overlapping rectangles in the scene:
10586     // +-------+
10587     // |       | <- item1
10588     // |   +-------+
10589     // |   |       |
10590     // +---|       | <- item2
10591     //     |       |
10592     //     +-------+
10593
10594     EventTester *item1 = new EventTester;
10595     item1->br = QRectF(0, 0, 200, 200);
10596     item1->brush = Qt::red;
10597     item1->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10598
10599     EventTester *item2 = new EventTester;
10600     item2->br = QRectF(0, 0, 200, 200);
10601     item2->brush = Qt::blue;
10602     item2->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10603     item2->setPos(100, 100);
10604
10605     QGraphicsScene scene(0, 0, 300, 300);
10606     scene.addItem(item1);
10607     scene.addItem(item2);
10608
10609     MyGraphicsView view(&scene);
10610     view.setFrameStyle(0);
10611     view.show();
10612     QTest::qWaitForWindowShown(&view);
10613     QTRY_VERIFY(view.repaints > 0);
10614
10615     view.reset();
10616     item1->reset();
10617     item2->reset();
10618
10619     const QRectF item1BoundingRect = item1->boundingRect();
10620     const QRectF item2BoundingRect = item2->boundingRect();
10621
10622     // Scroll item1:
10623     // Item1 should get full exposure
10624     // Item2 should get exposure for the part that overlaps item1.
10625     item1->scroll(0, -10);
10626     QTRY_VERIFY(view.repaints > 0);
10627     QCOMPARE(item1->lastExposedRect, item1BoundingRect);
10628
10629     QRectF expectedItem2Expose = item2BoundingRect;
10630     // NB! Adjusted by 2 pixels for antialiasing
10631     expectedItem2Expose &= item1->mapRectToItem(item2, item1BoundingRect.adjusted(-2, -2, 2, 2));
10632     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10633
10634     // Enable ItemCoordinateCache on item1.
10635     view.reset();
10636     item1->setCacheMode(QGraphicsItem::ItemCoordinateCache);
10637     QTRY_VERIFY(view.repaints > 0);
10638     view.reset();
10639     item1->reset();
10640     item2->reset();
10641
10642     // Scroll item1:
10643     // Item1 should only get expose for the newly exposed area (accelerated scroll).
10644     // Item2 should get exposure for the part that overlaps item1.
10645     item1->scroll(0, -10, QRectF(50, 50, 100, 100));
10646     QTRY_VERIFY(view.repaints > 0);
10647     QCOMPARE(item1->lastExposedRect, QRectF(50, 140, 100, 10));
10648
10649     expectedItem2Expose = item2BoundingRect;
10650     // NB! Adjusted by 2 pixels for antialiasing
10651     expectedItem2Expose &= item1->mapRectToItem(item2, QRectF(50, 50, 100, 100).adjusted(-2, -2, 2, 2));
10652     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10653 }
10654
10655 Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlag);
10656
10657 void tst_QGraphicsItem::focusHandling_data()
10658 {
10659     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("focusFlag");
10660     QTest::addColumn<bool>("useStickyFocus");
10661     QTest::addColumn<int>("expectedFocusItem"); // 0: none, 1: focusableUnder, 2: itemWithFocus
10662
10663     QTest::newRow("Focus goes through.")
10664         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << false << 1;
10665
10666     QTest::newRow("Focus goes through, even with sticky scene.")
10667         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << true  << 1;
10668
10669     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (but can still focus-out).")
10670         << QGraphicsItem::ItemStopsClickFocusPropagation << false << 0;
10671
10672     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (and cannot focus-out if scene is sticky).")
10673         << QGraphicsItem::ItemStopsClickFocusPropagation << true << 2;
10674
10675     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses.")
10676         << QGraphicsItem::ItemStopsFocusHandling << false << 2;
10677
10678     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses (even if scene is sticky).")
10679         << QGraphicsItem::ItemStopsFocusHandling << true << 2;
10680 }
10681
10682 void tst_QGraphicsItem::focusHandling()
10683 {
10684     QFETCH(QGraphicsItem::GraphicsItemFlag, focusFlag);
10685     QFETCH(bool, useStickyFocus);
10686     QFETCH(int, expectedFocusItem);
10687
10688     class MyItem : public QGraphicsRectItem
10689     {
10690     public:
10691         MyItem() : QGraphicsRectItem(0, 0, 100, 100) {}
10692         void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
10693         {
10694             painter->fillRect(boundingRect(), hasFocus() ? QBrush(Qt::red) : brush());
10695         }
10696     };
10697
10698     QGraphicsRectItem *noFocusOnTop = new MyItem;
10699     noFocusOnTop->setFlag(QGraphicsItem::ItemIsFocusable, false);
10700     noFocusOnTop->setBrush(Qt::yellow);
10701
10702     QGraphicsRectItem *focusableUnder = new MyItem;
10703     focusableUnder->setBrush(Qt::blue);
10704     focusableUnder->setFlag(QGraphicsItem::ItemIsFocusable);
10705     focusableUnder->setPos(50, 50);
10706
10707     QGraphicsRectItem *itemWithFocus = new MyItem;
10708     itemWithFocus->setBrush(Qt::black);
10709     itemWithFocus->setFlag(QGraphicsItem::ItemIsFocusable);
10710     itemWithFocus->setPos(250, 10);
10711
10712     QGraphicsScene scene(-50, -50, 400, 400);
10713     scene.addItem(noFocusOnTop);
10714     scene.addItem(focusableUnder);
10715     scene.addItem(itemWithFocus);
10716     scene.setStickyFocus(useStickyFocus);
10717
10718     noFocusOnTop->setFlag(focusFlag);
10719     focusableUnder->stackBefore(noFocusOnTop);
10720     itemWithFocus->setFocus();
10721
10722     QGraphicsView view(&scene);
10723     view.show();
10724     QTest::qWaitForWindowShown(&view);
10725
10726     QApplication::setActiveWindow(&view);
10727     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
10728     QVERIFY(itemWithFocus->hasFocus());
10729
10730     const QPointF mousePressPoint = noFocusOnTop->mapToScene(noFocusOnTop->boundingRect().center());
10731     const QList<QGraphicsItem *> itemsAtMousePressPosition = scene.items(mousePressPoint);
10732     QVERIFY(itemsAtMousePressPosition.contains(noFocusOnTop));
10733
10734     sendMousePress(&scene, mousePressPoint);
10735
10736     switch (expectedFocusItem) {
10737     case 0:
10738         QCOMPARE(scene.focusItem(), static_cast<QGraphicsRectItem *>(0));
10739         break;
10740     case 1:
10741         QCOMPARE(scene.focusItem(), focusableUnder);
10742         break;
10743     case 2:
10744         QCOMPARE(scene.focusItem(), itemWithFocus);
10745         break;
10746     }
10747
10748     // Sanity check - manually setting the focus must work regardless of our
10749     // focus handling flags:
10750     focusableUnder->setFocus();
10751     QCOMPARE(scene.focusItem(), focusableUnder);
10752 }
10753
10754 void tst_QGraphicsItem::touchEventPropagation_data()
10755 {
10756     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("flag");
10757     QTest::addColumn<int>("expectedCount");
10758
10759     QTest::newRow("ItemIsPanel")
10760         << QGraphicsItem::ItemIsPanel << 0;
10761     QTest::newRow("ItemStopsClickFocusPropagation")
10762         << QGraphicsItem::ItemStopsClickFocusPropagation << 1;
10763     QTest::newRow("ItemStopsFocusHandling")
10764         << QGraphicsItem::ItemStopsFocusHandling << 1;
10765 }
10766
10767 void tst_QGraphicsItem::touchEventPropagation()
10768 {
10769     QFETCH(QGraphicsItem::GraphicsItemFlag, flag);
10770     QFETCH(int, expectedCount);
10771
10772     class Testee : public QGraphicsRectItem
10773     {
10774     public:
10775         int touchBeginEventCount;
10776
10777         Testee()
10778             : QGraphicsRectItem(0, 0, 100, 100)
10779             , touchBeginEventCount(0)
10780         {
10781             setAcceptTouchEvents(true);
10782             setFlag(QGraphicsItem::ItemIsFocusable, false);
10783         }
10784
10785         bool sceneEvent(QEvent *ev)
10786         {
10787             if (ev->type() == QEvent::TouchBegin)
10788                 ++touchBeginEventCount;
10789
10790             return QGraphicsRectItem::sceneEvent(ev);
10791         }
10792     };
10793
10794     Testee *touchEventReceiver = new Testee;
10795     QGraphicsItem *topMost = new QGraphicsRectItem(touchEventReceiver->boundingRect());
10796
10797     QGraphicsScene scene;
10798     scene.addItem(topMost);
10799     scene.addItem(touchEventReceiver);
10800
10801     topMost->setAcceptTouchEvents(true);
10802     topMost->setZValue(FLT_MAX);
10803     topMost->setFlag(QGraphicsItem::ItemIsFocusable, false);
10804     topMost->setFlag(flag, true);
10805
10806     QGraphicsView view(&scene);
10807     view.setSceneRect(touchEventReceiver->boundingRect());
10808     view.show();
10809     QTest::qWaitForWindowShown(&view);
10810
10811     QCOMPARE(touchEventReceiver->touchBeginEventCount, 0);
10812
10813     QTouchEvent::TouchPoint tp(0);
10814     tp.setState(Qt::TouchPointPressed);
10815     tp.setScenePos(view.sceneRect().center());
10816     tp.setLastScenePos(view.sceneRect().center());
10817
10818     QList<QTouchEvent::TouchPoint> touchPoints;
10819     touchPoints << tp;
10820
10821     sendMousePress(&scene, tp.scenePos());
10822     QTouchEvent touchBegin(QEvent::TouchBegin, QTouchEvent::TouchScreen, Qt::NoModifier, Qt::TouchPointPressed, touchPoints);
10823
10824     qApp->sendEvent(&scene, &touchBegin);
10825     QCOMPARE(touchEventReceiver->touchBeginEventCount, expectedCount);
10826 }
10827
10828 void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations()
10829 {
10830     // Make sure we don't invalidate the cache when applying simple
10831     // (90, 180, 270, 360) rotation transforms to the item.
10832     QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 300, 200);
10833     item->setBrush(Qt::red);
10834     item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
10835
10836     QGraphicsScene scene;
10837     scene.setSceneRect(0, 0, 300, 200);
10838     scene.addItem(item);
10839
10840     MyGraphicsView view(&scene);
10841     view.show();
10842     QTest::qWaitForWindowShown(&view);
10843     QTRY_VERIFY(view.repaints > 0);
10844
10845     QGraphicsItemCache *itemCache = QGraphicsItemPrivate::get(item)->extraItemCache();
10846     QVERIFY(itemCache);
10847     QPixmapCache::Key currentKey = itemCache->deviceData.value(view.viewport()).key;
10848
10849     // Trigger an update and verify that the cache is unchanged.
10850     QPixmapCache::Key oldKey = currentKey;
10851     view.reset();
10852     view.viewport()->update();
10853     QTRY_VERIFY(view.repaints > 0);
10854     currentKey = itemCache->deviceData.value(view.viewport()).key;
10855     QCOMPARE(currentKey, oldKey);
10856
10857     // Check 90, 180, 270 and 360 degree rotations.
10858     for (int angle = 90; angle <= 360; angle += 90) {
10859         // Rotate item and verify that the cache was invalidated.
10860         oldKey = currentKey;
10861         view.reset();
10862         QTransform transform;
10863         transform.translate(150, 100);
10864         transform.rotate(angle);
10865         transform.translate(-150, -100);
10866         item->setTransform(transform);
10867         QTRY_VERIFY(view.repaints > 0);
10868         currentKey = itemCache->deviceData.value(view.viewport()).key;
10869         QVERIFY(currentKey != oldKey);
10870
10871         // IMPORTANT PART:
10872         // Trigger an update and verify that the cache is unchanged.
10873         oldKey = currentKey;
10874         view.reset();
10875         view.viewport()->update();
10876         QTRY_VERIFY(view.repaints > 0);
10877         currentKey = itemCache->deviceData.value(view.viewport()).key;
10878         QCOMPARE(currentKey, oldKey);
10879     }
10880
10881     // 45 degree rotation.
10882     oldKey = currentKey;
10883     view.reset();
10884     QTransform transform;
10885     transform.translate(150, 100);
10886     transform.rotate(45);
10887     transform.translate(-150, -100);
10888     item->setTransform(transform);
10889     QTRY_VERIFY(view.repaints > 0);
10890     currentKey = itemCache->deviceData.value(view.viewport()).key;
10891     QVERIFY(currentKey != oldKey);
10892
10893     // Trigger an update and verify that the cache was invalidated.
10894     // We should always invalidate the cache for non-trivial transforms.
10895     oldKey = currentKey;
10896     view.reset();
10897     view.viewport()->update();
10898     QTRY_VERIFY(view.repaints > 0);
10899     currentKey = itemCache->deviceData.value(view.viewport()).key;
10900     QVERIFY(currentKey != oldKey);
10901 }
10902
10903 void tst_QGraphicsItem::QTBUG_5418_textItemSetDefaultColor()
10904 {
10905     struct Item : public QGraphicsTextItem
10906     {
10907         int painted;
10908         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
10909         {
10910             painted++;
10911             QGraphicsTextItem::paint(painter, opt, wid);
10912         }
10913     };
10914
10915     Item *i = new Item;
10916     i->painted = 0;
10917     i->setPlainText("I AM A TROLL");
10918
10919     QGraphicsScene scene;
10920     QGraphicsView view(&scene);
10921     view.show();
10922     QTest::qWaitForWindowShown(&view);
10923     scene.addItem(i);
10924     QApplication::processEvents();
10925     QTRY_VERIFY(i->painted);
10926     QApplication::processEvents();
10927
10928     i->painted = 0;
10929     QColor col(Qt::red);
10930     i->setDefaultTextColor(col);
10931     QApplication::processEvents();
10932     QTRY_COMPARE(i->painted, 1); //check that changing the color force an update
10933
10934     i->painted = false;
10935     QImage image(400, 200, QImage::Format_RGB32);
10936     image.fill(0);
10937     QPainter painter(&image);
10938     scene.render(&painter);
10939     painter.end();
10940     QCOMPARE(i->painted, 1);
10941
10942     int numRedPixel = 0;
10943     QRgb rgb = col.rgb();
10944     for (int y = 0; y < image.height(); ++y) {
10945         for (int x = 0; x < image.width(); ++x) {
10946             // Because of antialiasing we allow a certain range of errors here.
10947             QRgb pixel = image.pixel(x, y);
10948             if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) +
10949                 qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) +
10950                 qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) {
10951                 if (++numRedPixel >= 10) {
10952                     return;
10953                 }
10954             }
10955         }
10956     }
10957     QCOMPARE(numRedPixel, -1); //color not found, FAIL!
10958
10959     i->painted = 0;
10960     i->setDefaultTextColor(col);
10961     QApplication::processEvents();
10962     QCOMPARE(i->painted, 0); //same color as before should not trigger an update (QTBUG-6242)
10963 }
10964
10965 void tst_QGraphicsItem::QTBUG_6738_missingUpdateWithSetParent()
10966 {
10967     // In all 3 test cases below the reparented item should disappear
10968     EventTester *parent = new EventTester;
10969     EventTester *child = new EventTester(parent);
10970     EventTester *child2 = new EventTester(parent);
10971     EventTester *child3 = new EventTester(parent);
10972     EventTester *child4 = new EventTester(parent);
10973
10974     child->setPos(10, 10);
10975     child2->setPos(20, 20);
10976     child3->setPos(30, 30);
10977     child4->setPos(40, 40);
10978
10979     QGraphicsScene scene;
10980     scene.addItem(parent);
10981
10982     MyGraphicsView view(&scene);
10983     if(PlatformQuirks::isAutoMaximizing())
10984         view.showFullScreen();
10985     else
10986         view.show();
10987     QTest::qWaitForWindowShown(&view);
10988     QTRY_VERIFY(view.repaints > 0);
10989
10990     // test case #1
10991     view.reset();
10992     child2->setVisible(false);
10993     child2->setParentItem(child);
10994
10995     QTRY_VERIFY(view.repaints == 1);
10996
10997     // test case #2
10998     view.reset();
10999     child3->setOpacity(0.0);
11000     child3->setParentItem(child);
11001
11002     QTRY_VERIFY(view.repaints == 1);
11003
11004     // test case #3
11005     view.reset();
11006     child4->setParentItem(child);
11007     child4->setVisible(false);
11008
11009     QTRY_VERIFY(view.repaints == 1);
11010 }
11011
11012 void tst_QGraphicsItem::QT_2653_fullUpdateDiscardingOpacityUpdate()
11013 {
11014     QGraphicsScene scene(0, 0, 200, 200);
11015     MyGraphicsView view(&scene);
11016
11017     EventTester *parentGreen = new EventTester();
11018     parentGreen->setGeometry(QRectF(20, 20, 100, 100));
11019     parentGreen->brush = Qt::green;
11020
11021     EventTester *childYellow = new EventTester(parentGreen);
11022     childYellow->setGeometry(QRectF(10, 10, 50, 50));
11023     childYellow->brush = Qt::yellow;
11024
11025     scene.addItem(parentGreen);
11026
11027     childYellow->setOpacity(0.0);
11028     parentGreen->setOpacity(0.0);
11029
11030     // set any of the flags below to trigger a fullUpdate to reproduce the bug:
11031     // ItemIgnoresTransformations, ItemClipsChildrenToShape, ItemIsSelectable
11032     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
11033
11034     if (PlatformQuirks::isAutoMaximizing())
11035         view.showFullScreen();
11036     else
11037         view.show();
11038     QTest::qWaitForWindowShown(&view);
11039     view.reset();
11040
11041     parentGreen->setOpacity(1.0);
11042
11043     QTRY_COMPARE(view.repaints, 1);
11044
11045     view.reset();
11046     childYellow->repaints = 0;
11047
11048     childYellow->setOpacity(1.0);
11049
11050     QTRY_COMPARE(view.repaints, 1);
11051     QTRY_COMPARE(childYellow->repaints, 1);
11052 }
11053
11054 void tst_QGraphicsItem::QTBUG_7714_fullUpdateDiscardingOpacityUpdate2()
11055 {
11056     QGraphicsScene scene(0, 0, 200, 200);
11057     MyGraphicsView view(&scene);
11058     MyGraphicsView origView(&scene);
11059
11060     EventTester *parentGreen = new EventTester();
11061     parentGreen->setGeometry(QRectF(20, 20, 100, 100));
11062     parentGreen->brush = Qt::green;
11063
11064     EventTester *childYellow = new EventTester(parentGreen);
11065     childYellow->setGeometry(QRectF(10, 10, 50, 50));
11066     childYellow->brush = Qt::yellow;
11067
11068     scene.addItem(parentGreen);
11069
11070     origView.show();
11071     QTest::qWaitForWindowShown(&origView);
11072     origView.setGeometry(origView.width() + 20, 20,
11073                          origView.width(), origView.height());
11074
11075     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
11076
11077     origView.reset();
11078     childYellow->setOpacity(0.0);
11079
11080     QTRY_COMPARE(origView.repaints, 1);
11081
11082     view.show();
11083
11084     QTest::qWaitForWindowShown(&view);
11085     view.reset();
11086     origView.reset();
11087
11088     childYellow->setOpacity(1.0);
11089
11090     QTRY_COMPARE(origView.repaints, 1);
11091     QTRY_COMPARE(view.repaints, 1);
11092 }
11093
11094 void tst_QGraphicsItem::QT_2649_focusScope()
11095 {
11096     QGraphicsScene *scene = new QGraphicsScene;
11097
11098     QGraphicsRectItem *subFocusItem = new QGraphicsRectItem;
11099     subFocusItem->setFlags(QGraphicsItem::ItemIsFocusable);
11100     subFocusItem->setFocus();
11101     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11102
11103     QGraphicsRectItem *scope = new QGraphicsRectItem;
11104     scope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
11105     scope->setFocus();
11106     subFocusItem->setParentItem(scope);
11107     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11108     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11109     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11110     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11111
11112     QGraphicsRectItem *rootItem = new QGraphicsRectItem;
11113     rootItem->setFlags(QGraphicsItem::ItemIsFocusable);
11114     scope->setParentItem(rootItem);
11115     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11116     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11117     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11118     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11119     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11120     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11121
11122     scene->addItem(rootItem);
11123
11124     QEvent windowActivate(QEvent::WindowActivate);
11125     qApp->sendEvent(scene, &windowActivate);
11126     scene->setFocus();
11127
11128     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11129     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11130     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11131     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11132     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11133     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11134     QVERIFY(subFocusItem->hasFocus());
11135
11136     scope->hide();
11137
11138     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)0);
11139     QCOMPARE(scope->focusItem(), (QGraphicsItem *)0);
11140     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)0);
11141     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11142     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11143     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11144     QVERIFY(!subFocusItem->hasFocus());
11145
11146     scope->show();
11147
11148     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11149     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11150     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11151     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11152     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11153     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11154     QVERIFY(subFocusItem->hasFocus());
11155
11156     // This should not crash
11157     scope->hide();
11158     delete scene;
11159 }
11160
11161 class MyGraphicsItemWithItemChange : public QGraphicsWidget
11162 {
11163 public:
11164     MyGraphicsItemWithItemChange(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
11165     {}
11166
11167     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
11168     {
11169         if (change == QGraphicsItem::ItemSceneHasChanged) {
11170             foreach (QGraphicsView *view, scene()->views()) {
11171                 //We trigger a sort of unindexed items in the BSP
11172                 view->sceneRect();
11173             }
11174         }
11175         return QGraphicsWidget::itemChange(change, value);
11176     }
11177 };
11178
11179 void tst_QGraphicsItem::sortItemsWhileAdding()
11180 {
11181     QGraphicsScene scene;
11182     QGraphicsView view(&scene);
11183     QGraphicsWidget grandGrandParent;
11184     grandGrandParent.resize(200, 200);
11185     scene.addItem(&grandGrandParent);
11186     QGraphicsWidget grandParent;
11187     grandParent.resize(200, 200);
11188     QGraphicsWidget parent(&grandParent);
11189     parent.resize(200, 200);
11190     MyGraphicsItemWithItemChange item(&parent);
11191     grandParent.setParentItem(&grandGrandParent);
11192 }
11193
11194 void tst_QGraphicsItem::doNotMarkFullUpdateIfNotInScene()
11195 {
11196     struct Item : public QGraphicsTextItem
11197     {
11198         int painted;
11199         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
11200         {
11201             painted++;
11202             QGraphicsTextItem::paint(painter, opt, wid);
11203         }
11204     };
11205     QGraphicsScene scene;
11206     MyGraphicsView view(&scene);
11207     Item *item = new Item;
11208     item->painted = 0;
11209     item->setPlainText("Grandparent");
11210     Item *item2 = new Item;
11211     item2->setPlainText("parent");
11212     item2->painted = 0;
11213     Item *item3 = new Item;
11214     item3->setPlainText("child");
11215     item3->painted = 0;
11216     QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect;
11217     effect->setOpacity(0.5);
11218     item2->setGraphicsEffect(effect);
11219     item3->setParentItem(item2);
11220     item2->setParentItem(item);
11221     scene.addItem(item);
11222     if(PlatformQuirks::isAutoMaximizing())
11223         view.showFullScreen();
11224     else
11225         view.show();
11226     QTest::qWaitForWindowShown(&view);
11227     QTRY_COMPARE(view.repaints, 1);
11228     QTRY_COMPARE(item->painted, 1);
11229     QTRY_COMPARE(item2->painted, 1);
11230     QTRY_COMPARE(item3->painted, 1);
11231     item2->update();
11232     QApplication::processEvents();
11233     QTRY_COMPARE(item->painted, 2);
11234     QTRY_COMPARE(item2->painted, 2);
11235     QTRY_COMPARE(item3->painted, 2);
11236     item2->update();
11237     QApplication::processEvents();
11238     QTRY_COMPARE(item->painted, 3);
11239     QTRY_COMPARE(item2->painted, 3);
11240     QTRY_COMPARE(item3->painted, 3);
11241 }
11242
11243 void tst_QGraphicsItem::itemDiesDuringDraggingOperation()
11244 {
11245     QGraphicsScene scene;
11246     QGraphicsView view(&scene);
11247     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
11248     item->setFlag(QGraphicsItem::ItemIsMovable);
11249     item->setAcceptDrops(true);
11250     scene.addItem(item);
11251     view.show();
11252     QApplication::setActiveWindow(&view);
11253     QTest::qWaitForWindowShown(&view);
11254     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
11255     QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
11256     dragEnter.setScenePos(item->boundingRect().center());
11257     QApplication::sendEvent(&scene, &dragEnter);
11258     QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragMove);
11259     event.setScenePos(item->boundingRect().center());
11260     QApplication::sendEvent(&scene, &event);
11261     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == item);
11262     delete item;
11263     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == 0);
11264 }
11265
11266 void tst_QGraphicsItem::QTBUG_12112_focusItem()
11267 {
11268     QGraphicsScene scene;
11269     QGraphicsView view(&scene);
11270     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
11271     item1->setFlag(QGraphicsItem::ItemIsFocusable);
11272     QGraphicsRectItem *item2 = new QGraphicsRectItem(20, 20, 20, 20);
11273     item2->setFlag(QGraphicsItem::ItemIsFocusable);
11274     item1->setFocus();
11275     scene.addItem(item2);
11276     scene.addItem(item1);
11277
11278     view.show();
11279     QApplication::setActiveWindow(&view);
11280     QTest::qWaitForWindowShown(&view);
11281     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
11282
11283     QVERIFY(item1->focusItem());
11284     QVERIFY(!item2->focusItem());
11285
11286     item2->setFocus();
11287     QVERIFY(!item1->focusItem());
11288     QVERIFY(item2->focusItem());
11289 }
11290
11291 void tst_QGraphicsItem::QTBUG_13473_sceneposchange()
11292 {
11293     ScenePosChangeTester* parent = new ScenePosChangeTester;
11294     ScenePosChangeTester* child = new ScenePosChangeTester(parent);
11295
11296     // parent's disabled ItemSendsGeometryChanges flag must not affect
11297     // child's scene pos change notifications
11298     parent->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
11299     child->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
11300
11301     QGraphicsScene scene;
11302     scene.addItem(parent);
11303
11304     // ignore uninteresting changes
11305     parent->clear();
11306     child->clear();
11307
11308     // move
11309     parent->moveBy(1.0, 1.0);
11310     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
11311
11312     // transform
11313     parent->setTransform(QTransform::fromScale(0.5, 0.5));
11314     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
11315 }
11316
11317 class MyGraphicsWidget : public QGraphicsWidget {
11318 Q_OBJECT
11319 public:
11320     MyGraphicsWidget()
11321         : QGraphicsWidget(0)
11322     {
11323         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11324         QLatin1String wiseWords("AZ BUKI VEDI");
11325         QString sentence(wiseWords);
11326         QStringList words = sentence.split(QLatin1Char(' '), QString::SkipEmptyParts);
11327         for (int i = 0; i < words.count(); ++i) {
11328             QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(this);
11329             QLabel *label = new QLabel(words.at(i));
11330             proxy->setWidget(label);
11331             proxy->setFocusPolicy(Qt::StrongFocus);
11332             proxy->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
11333             if (i%2 == 0)
11334                 proxy->setVisible(false);
11335             proxy->setFocus();
11336             lay->addItem(proxy);
11337         }
11338         setLayout(lay);
11339     }
11340
11341 };
11342
11343 class MyWidgetWindow : public QGraphicsWidget
11344 {
11345 public:
11346     MyWidgetWindow()
11347         : QGraphicsWidget(0, Qt::Window)
11348     {
11349         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11350         MyGraphicsWidget *widget = new MyGraphicsWidget();
11351         lay->addItem(widget);
11352         setLayout(lay);
11353     }
11354 };
11355
11356 void tst_QGraphicsItem::QTBUG_16374_crashInDestructor()
11357 {
11358     QGraphicsScene scene;
11359     QGraphicsView view(&scene);
11360
11361     MyWidgetWindow win;
11362     scene.addItem(&win);
11363
11364     view.show();
11365     QTest::qWaitForWindowShown(&view);
11366 }
11367
11368 void tst_QGraphicsItem::QTBUG_20699_focusScopeCrash()
11369 {
11370     QGraphicsScene scene;
11371     QGraphicsView view(&scene);
11372     QGraphicsPixmapItem fs;
11373     fs.setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11374     scene.addItem(&fs);
11375     QGraphicsPixmapItem* fs2 = new QGraphicsPixmapItem(&fs);
11376     fs2->setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11377     QGraphicsPixmapItem* fi2 = new QGraphicsPixmapItem(&fs);
11378     fi2->setFlags(QGraphicsItem::ItemIsFocusable);
11379     QGraphicsPixmapItem* fi = new QGraphicsPixmapItem(fs2);
11380     fi->setFlags(QGraphicsItem::ItemIsFocusable);
11381     fs.setFocus();
11382     fi->setFocus();
11383
11384     view.show();
11385     QTest::qWaitForWindowShown(&view);
11386
11387     fi->setParentItem(fi2);
11388     fi->setFocus();
11389     fs.setFocus();
11390     fi->setParentItem(fs2);
11391     fi->setFocus();
11392     fs2->setFocus();
11393     fs.setFocus();
11394     fi->setParentItem(fi2);
11395     fi->setFocus();
11396     fs.setFocus();
11397 }
11398
11399 QTEST_MAIN(tst_QGraphicsItem)
11400 #include "tst_qgraphicsitem.moc"