Remove obsolete test data from qgraphicsitem test
[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     QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform()
6522                                                                        << QRegion(QRect(0, 0, 10, 1));
6523     QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform()
6524                                                                       << QRegion(QRect(0, 0, 10, 1));
6525     QTest::newRow("(0, 0, 10, 0) | 1.0 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(1.0) << QTransform()
6526                                                                       << QRegion(QRect(0, 0, 10, 1));
6527     QTest::newRow("(0, 0, 0, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.0) << QTransform()
6528                                                                        << QRegion(QRect(0, 0, 1, 10));
6529     QTest::newRow("(0, 0, 0, 10) | 0.5 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.5) << QTransform()
6530                                                                       << QRegion(QRect(0, 0, 1, 10));
6531     QTest::newRow("(0, 0, 0, 10) | 1.0 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(1.0) << QTransform()
6532                                                                       << QRegion(QRect(0, 0, 1, 10));
6533 }
6534
6535 void tst_QGraphicsItem::boundingRegion()
6536 {
6537     QFETCH(QLineF, line);
6538     QFETCH(qreal, granularity);
6539     QFETCH(QTransform, transform);
6540     QFETCH(QRegion, expectedRegion);
6541
6542     QGraphicsLineItem item(line);
6543     QCOMPARE(item.boundingRegionGranularity(), qreal(0.0));
6544     item.setBoundingRegionGranularity(granularity);
6545     QCOMPARE(item.boundingRegionGranularity(), granularity);
6546     QCOMPARE(item.boundingRegion(transform), expectedRegion);
6547 }
6548
6549 void tst_QGraphicsItem::itemTransform_parentChild()
6550 {
6551     QGraphicsScene scene;
6552     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6553     QGraphicsItem *child = scene.addRect(0, 0, 100, 100);
6554     child->setParentItem(parent);
6555     child->setPos(10, 10);
6556     child->scale(2, 2);
6557     child->rotate(90);
6558
6559     QCOMPARE(child->itemTransform(parent).map(QPointF(10, 10)), QPointF(-10, 30));
6560     QCOMPARE(parent->itemTransform(child).map(QPointF(-10, 30)), QPointF(10, 10));
6561 }
6562
6563 void tst_QGraphicsItem::itemTransform_siblings()
6564 {
6565     QGraphicsScene scene;
6566     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6567     QGraphicsItem *brother = scene.addRect(0, 0, 100, 100);
6568     QGraphicsItem *sister = scene.addRect(0, 0, 100, 100);
6569     parent->scale(10, 5);
6570     parent->rotate(-180);
6571     parent->shear(2, 3);
6572
6573     brother->setParentItem(parent);
6574     sister->setParentItem(parent);
6575
6576     brother->setPos(10, 10);
6577     brother->scale(2, 2);
6578     brother->rotate(90);
6579     sister->setPos(10, 10);
6580     sister->scale(2, 2);
6581     sister->rotate(90);
6582
6583     QCOMPARE(brother->itemTransform(sister).map(QPointF(10, 10)), QPointF(10, 10));
6584     QCOMPARE(sister->itemTransform(brother).map(QPointF(10, 10)), QPointF(10, 10));
6585 }
6586
6587 void tst_QGraphicsItem::itemTransform_unrelated()
6588 {
6589     QGraphicsScene scene;
6590     QGraphicsItem *stranger1 = scene.addRect(0, 0, 100, 100);
6591     QGraphicsItem *stranger2 = scene.addRect(0, 0, 100, 100);
6592     stranger1->setPos(10, 10);
6593     stranger1->scale(2, 2);
6594     stranger1->rotate(90);
6595     stranger2->setPos(10, 10);
6596     stranger2->scale(2, 2);
6597     stranger2->rotate(90);
6598
6599     QCOMPARE(stranger1->itemTransform(stranger2).map(QPointF(10, 10)), QPointF(10, 10));
6600     QCOMPARE(stranger2->itemTransform(stranger1).map(QPointF(10, 10)), QPointF(10, 10));
6601 }
6602
6603 void tst_QGraphicsItem::opacity_data()
6604 {
6605     QTest::addColumn<qreal>("p_opacity");
6606     QTest::addColumn<int>("p_opacityFlags");
6607     QTest::addColumn<qreal>("c1_opacity");
6608     QTest::addColumn<int>("c1_opacityFlags");
6609     QTest::addColumn<qreal>("c2_opacity");
6610     QTest::addColumn<int>("c2_opacityFlags");
6611     QTest::addColumn<qreal>("p_effectiveOpacity");
6612     QTest::addColumn<qreal>("c1_effectiveOpacity");
6613     QTest::addColumn<qreal>("c2_effectiveOpacity");
6614     QTest::addColumn<qreal>("c3_effectiveOpacity");
6615
6616     // Modify the opacity and see how it propagates
6617     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
6618                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6619     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
6620                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6621     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
6622                                                         << qreal(0.5) << qreal(0.05) << qreal(0.05) << qreal(0.05);
6623     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
6624                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6625
6626     // Parent doesn't propagate to children - now modify the opacity and see how it propagates
6627     int flags = QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6628     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
6629                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6630     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
6631                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6632     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
6633                                                         << qreal(0.5) << qreal(0.1) << qreal(0.1) << qreal(0.1);
6634     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
6635                                                         << qreal(0.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6636
6637     // Child ignores parent - now modify the opacity and see how it propagates
6638     flags = QGraphicsItem::ItemIgnoresParentOpacity;
6639     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
6640                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6641     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
6642                                                         << qreal(0.5) << qreal(0.5) << qreal(0.25) << qreal(0.25);
6643     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
6644                                                         << qreal(0.2) << qreal(0.2) << qreal(0.04) << qreal(0.04);
6645     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
6646                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6647
6648     // Child ignores parent and doesn't propagate - now modify the opacity and see how it propagates
6649     flags = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6650     QTest::newRow("M: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6651                                                         << qreal(1.0) << flags // c1 (no prop)
6652                                                         << qreal(1.0) << 0 // c2
6653                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6654     QTest::newRow("M: 0.5 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6655                                                         << qreal(1.0) << flags // c1 (no prop)
6656                                                         << qreal(1.0) << 0 // c2
6657                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6658     QTest::newRow("M: 0.5 0 0.5 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6659                                                         << qreal(0.5) << flags // c1 (no prop)
6660                                                         << qreal(1.0) << 0 // c2
6661                                                         << qreal(0.5) << qreal(0.5) << qreal(1.0) << qreal(1.0);
6662     QTest::newRow("M: 0.5 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6663                                                         << qreal(0.5) << flags // c1 (no prop)
6664                                                         << qreal(0.5) << 0 // c2
6665                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6666     QTest::newRow("M: 1.0 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6667                                                         << qreal(0.5) << flags // c1 (no prop)
6668                                                         << qreal(0.5) << 0 // c2
6669                                                         << qreal(1.0) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6670 }
6671
6672 void tst_QGraphicsItem::opacity()
6673 {
6674     QFETCH(qreal, p_opacity);
6675     QFETCH(int, p_opacityFlags);
6676     QFETCH(qreal, p_effectiveOpacity);
6677     QFETCH(qreal, c1_opacity);
6678     QFETCH(int, c1_opacityFlags);
6679     QFETCH(qreal, c1_effectiveOpacity);
6680     QFETCH(qreal, c2_opacity);
6681     QFETCH(int, c2_opacityFlags);
6682     QFETCH(qreal, c2_effectiveOpacity);
6683     QFETCH(qreal, c3_effectiveOpacity);
6684
6685     QGraphicsRectItem *p = new QGraphicsRectItem;
6686     QGraphicsRectItem *c1 = new QGraphicsRectItem(p);
6687     QGraphicsRectItem *c2 = new QGraphicsRectItem(c1);
6688     QGraphicsRectItem *c3 = new QGraphicsRectItem(c2);
6689
6690     QCOMPARE(p->opacity(), qreal(1.0));
6691     QCOMPARE(p->effectiveOpacity(), qreal(1.0));
6692     int opacityMask = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6693     QVERIFY(!(p->flags() & opacityMask));
6694
6695     p->setOpacity(p_opacity);
6696     c1->setOpacity(c1_opacity);
6697     c2->setOpacity(c2_opacity);
6698     p->setFlags(QGraphicsItem::GraphicsItemFlags(p->flags() | p_opacityFlags));
6699     c1->setFlags(QGraphicsItem::GraphicsItemFlags(c1->flags() | c1_opacityFlags));
6700     c2->setFlags(QGraphicsItem::GraphicsItemFlags(c2->flags() | c2_opacityFlags));
6701
6702     QCOMPARE(int(p->flags() & opacityMask), p_opacityFlags);
6703     QCOMPARE(int(c1->flags() & opacityMask), c1_opacityFlags);
6704     QCOMPARE(int(c2->flags() & opacityMask), c2_opacityFlags);
6705     QCOMPARE(p->opacity(), p_opacity);
6706     QCOMPARE(p->effectiveOpacity(), p_effectiveOpacity);
6707     QCOMPARE(c1->effectiveOpacity(), c1_effectiveOpacity);
6708     QCOMPARE(c2->effectiveOpacity(), c2_effectiveOpacity);
6709     QCOMPARE(c3->effectiveOpacity(), c3_effectiveOpacity);
6710 }
6711
6712 void tst_QGraphicsItem::opacity2()
6713 {
6714     EventTester *parent = new EventTester;
6715     EventTester *child = new EventTester(parent);
6716     EventTester *grandChild = new EventTester(child);
6717
6718     QGraphicsScene scene;
6719     scene.addItem(parent);
6720
6721     MyGraphicsView view(&scene);
6722     if(PlatformQuirks::isAutoMaximizing())
6723         view.showFullScreen();
6724     else
6725         view.show();
6726     QTest::qWaitForWindowShown(&view);
6727     QTRY_VERIFY(view.repaints >= 1);
6728
6729 #define RESET_REPAINT_COUNTERS \
6730     parent->repaints = 0; \
6731     child->repaints = 0; \
6732     grandChild->repaints = 0; \
6733     view.repaints = 0;
6734
6735     RESET_REPAINT_COUNTERS
6736
6737     child->setOpacity(0.0);
6738     QTest::qWait(10);
6739     QTRY_COMPARE(view.repaints, 1);
6740     QCOMPARE(parent->repaints, 1);
6741     QCOMPARE(child->repaints, 0);
6742     QCOMPARE(grandChild->repaints, 0);
6743
6744     RESET_REPAINT_COUNTERS
6745
6746     child->setOpacity(1.0);
6747     QTest::qWait(10);
6748     QTRY_COMPARE(view.repaints, 1);
6749     QCOMPARE(parent->repaints, 1);
6750     QCOMPARE(child->repaints, 1);
6751     QCOMPARE(grandChild->repaints, 1);
6752
6753     RESET_REPAINT_COUNTERS
6754
6755     parent->setOpacity(0.0);
6756     QTest::qWait(10);
6757     QTRY_COMPARE(view.repaints, 1);
6758     QCOMPARE(parent->repaints, 0);
6759     QCOMPARE(child->repaints, 0);
6760     QCOMPARE(grandChild->repaints, 0);
6761
6762     RESET_REPAINT_COUNTERS
6763
6764     parent->setOpacity(1.0);
6765     QTest::qWait(10);
6766     QTRY_COMPARE(view.repaints, 1);
6767     QCOMPARE(parent->repaints, 1);
6768     QCOMPARE(child->repaints, 1);
6769     QCOMPARE(grandChild->repaints, 1);
6770
6771     grandChild->setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
6772     RESET_REPAINT_COUNTERS
6773
6774     child->setOpacity(0.0);
6775     QTest::qWait(10);
6776     QTRY_COMPARE(view.repaints, 1);
6777     QCOMPARE(parent->repaints, 1);
6778     QCOMPARE(child->repaints, 0);
6779     QCOMPARE(grandChild->repaints, 1);
6780
6781     RESET_REPAINT_COUNTERS
6782
6783     child->setOpacity(0.0); // Already 0.0; no change.
6784     QTest::qWait(10);
6785     QTRY_COMPARE(view.repaints, 0);
6786     QCOMPARE(parent->repaints, 0);
6787     QCOMPARE(child->repaints, 0);
6788     QCOMPARE(grandChild->repaints, 0);
6789 }
6790
6791 void tst_QGraphicsItem::opacityZeroUpdates()
6792 {
6793     EventTester *parent = new EventTester;
6794     EventTester *child = new EventTester(parent);
6795
6796     child->setPos(10, 10);
6797
6798     QGraphicsScene scene;
6799     scene.addItem(parent);
6800
6801     MyGraphicsView view(&scene);
6802     view.show();
6803     QTest::qWaitForWindowShown(&view);
6804     QTRY_VERIFY(view.repaints > 0);
6805
6806     view.reset();
6807     parent->setOpacity(0.0);
6808
6809     QTest::qWait(20);
6810
6811     // transforming items bounding rect to view coordinates
6812     const QRect childDeviceBoundingRect = child->deviceTransform(view.viewportTransform())
6813                                            .mapRect(child->boundingRect()).toRect();
6814     const QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
6815                                            .mapRect(parent->boundingRect()).toRect();
6816
6817     QRegion expectedRegion = parentDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6818     expectedRegion += childDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6819
6820     COMPARE_REGIONS(view.paintedRegion, expectedRegion);
6821 }
6822
6823 class StacksBehindParentHelper : public QGraphicsRectItem
6824 {
6825 public:
6826     StacksBehindParentHelper(QList<QGraphicsItem *> *paintedItems, const QRectF &rect, QGraphicsItem *parent = 0)
6827         : QGraphicsRectItem(rect, parent), paintedItems(paintedItems)
6828     { }
6829
6830     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
6831     {
6832         QGraphicsRectItem::paint(painter, option, widget);
6833         paintedItems->append(this);
6834     }
6835
6836 private:
6837     QList<QGraphicsItem *> *paintedItems;
6838 };
6839
6840 void tst_QGraphicsItem::itemStacksBehindParent()
6841 {
6842     StacksBehindParentHelper *parent1 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6843     StacksBehindParentHelper *child11 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent1);
6844     StacksBehindParentHelper *grandChild111 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child11);
6845     StacksBehindParentHelper *child12 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent1);
6846     StacksBehindParentHelper *grandChild121 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child12);
6847
6848     StacksBehindParentHelper *parent2 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6849     StacksBehindParentHelper *child21 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent2);
6850     StacksBehindParentHelper *grandChild211 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child21);
6851     StacksBehindParentHelper *child22 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent2);
6852     StacksBehindParentHelper *grandChild221 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child22);
6853
6854     parent1->setData(0, "parent1");
6855     child11->setData(0, "child11");
6856     grandChild111->setData(0, "grandChild111");
6857     child12->setData(0, "child12");
6858     grandChild121->setData(0, "grandChild121");
6859     parent2->setData(0, "parent2");
6860     child21->setData(0, "child21");
6861     grandChild211->setData(0, "grandChild211");
6862     child22->setData(0, "child22");
6863     grandChild221->setData(0, "grandChild221");
6864
6865     // Disambiguate siblings
6866     parent1->setZValue(1);
6867     child11->setZValue(1);
6868     child21->setZValue(1);
6869
6870     QGraphicsScene scene;
6871     scene.addItem(parent1);
6872     scene.addItem(parent2);
6873
6874     QGraphicsView view(&scene);
6875     view.show();
6876     QTest::qWaitForWindowShown(&view);
6877     QTRY_VERIFY(!paintedItems.isEmpty());
6878     QTest::qWait(100);
6879     paintedItems.clear();
6880     view.viewport()->update();
6881     QApplication::processEvents();
6882     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6883                                            << grandChild111 << child11
6884                                            << grandChild121 << child12 << parent1
6885                                            << grandChild211 << child21
6886                                            << grandChild221 << child22 << parent2));
6887     QTRY_COMPARE(paintedItems, QList<QGraphicsItem *>()
6888              << parent2 << child22 << grandChild221
6889              << child21 << grandChild211
6890              << parent1 << child12 << grandChild121
6891              << child11 << grandChild111);
6892
6893     child11->setFlag(QGraphicsItem::ItemStacksBehindParent);
6894     scene.update();
6895     paintedItems.clear();
6896     QApplication::processEvents();
6897
6898     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6899                                            << grandChild121 << child12 << parent1
6900                                            << grandChild111 << child11
6901                                            << grandChild211 << child21
6902                                            << grandChild221 << child22 << parent2));
6903     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6904              << parent2 << child22 << grandChild221
6905              << child21 << grandChild211
6906              << child11 << grandChild111
6907              << parent1 << child12 << grandChild121);
6908
6909     child12->setFlag(QGraphicsItem::ItemStacksBehindParent);
6910     paintedItems.clear();
6911     scene.update();
6912     QApplication::processEvents();
6913
6914     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6915                                            << parent1 << grandChild111 << child11
6916                                            << grandChild121 << child12
6917                                            << grandChild211 << child21
6918                                            << grandChild221 << child22 << parent2));
6919     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6920              << parent2 << child22 << grandChild221
6921              << child21 << grandChild211
6922              << child12 << grandChild121
6923              << child11 << grandChild111 << parent1);
6924 }
6925
6926 class ClippingAndTransformsScene : public QGraphicsScene
6927 {
6928 public:
6929     QList<QGraphicsItem *> drawnItems;
6930 protected:
6931     void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[],
6932                    const QStyleOptionGraphicsItem options[], QWidget *widget = 0)
6933     {
6934         drawnItems.clear();
6935         for (int i = 0; i < numItems; ++i)
6936             drawnItems << items[i];
6937         QGraphicsScene::drawItems(painter, numItems, items, options, widget);
6938     }
6939 };
6940
6941 void tst_QGraphicsItem::nestedClipping()
6942 {
6943     ClippingAndTransformsScene scene;
6944     scene.setSceneRect(-50, -50, 200, 200);
6945
6946     QGraphicsRectItem *root = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6947     root->setBrush(QColor(0, 0, 255));
6948     root->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6949     QGraphicsRectItem *l1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6950     l1->setParentItem(root);
6951     l1->setPos(-50, 0);
6952     l1->setBrush(QColor(255, 0, 0));
6953     l1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6954     QGraphicsEllipseItem *l2 = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100));
6955     l2->setParentItem(l1);
6956     l2->setPos(50, 50);
6957     l2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6958     l2->setBrush(QColor(255, 255, 0));
6959     QGraphicsRectItem *l3 = new QGraphicsRectItem(QRectF(0, 0, 25, 25));
6960     l3->setParentItem(l2);
6961     l3->setBrush(QColor(0, 255, 0));
6962     l3->setPos(50 - 12, -12);
6963
6964     scene.addItem(root);
6965
6966     root->setData(0, "root");
6967     l1->setData(0, "l1");
6968     l2->setData(0, "l2");
6969     l3->setData(0, "l3");
6970
6971     QGraphicsView view(&scene);
6972     view.setOptimizationFlag(QGraphicsView::IndirectPainting);
6973     view.show();
6974     QTest::qWaitForWindowShown(&view);
6975     QTest::qWait(25);
6976
6977     QList<QGraphicsItem *> expected;
6978     expected << root << l1 << l2 << l3;
6979     QTRY_COMPARE(scene.drawnItems, expected);
6980
6981     QImage image(200, 200, QImage::Format_ARGB32_Premultiplied);
6982     image.fill(0);
6983
6984     QPainter painter(&image);
6985     scene.render(&painter);
6986     painter.end();
6987
6988     // Check transparent areas
6989     QCOMPARE(image.pixel(100, 25), qRgba(0, 0, 0, 0));
6990     QCOMPARE(image.pixel(100, 175), qRgba(0, 0, 0, 0));
6991     QCOMPARE(image.pixel(25, 100), qRgba(0, 0, 0, 0));
6992     QCOMPARE(image.pixel(175, 100), qRgba(0, 0, 0, 0));
6993     QCOMPARE(image.pixel(70, 80), qRgba(255, 0, 0, 255));
6994     QCOMPARE(image.pixel(80, 130), qRgba(255, 255, 0, 255));
6995     QCOMPARE(image.pixel(92, 105), qRgba(0, 255, 0, 255));
6996     QCOMPARE(image.pixel(105, 105), qRgba(0, 0, 255, 255));
6997 #if 0
6998     // Enable this to compare if the test starts failing.
6999     image.save("nestedClipping_reference.png");
7000 #endif
7001 }
7002
7003 class TransformDebugItem : public QGraphicsRectItem
7004 {
7005 public:
7006     TransformDebugItem()
7007         : QGraphicsRectItem(QRectF(-10, -10, 20, 20))
7008     {
7009         setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
7010     }
7011
7012     QTransform x;
7013
7014     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
7015                QWidget *widget = 0)
7016     {
7017         x = painter->worldTransform();
7018         QGraphicsRectItem::paint(painter, option, widget);
7019     }
7020 };
7021
7022 void tst_QGraphicsItem::nestedClippingTransforms()
7023 {
7024     TransformDebugItem *rootClipper = new TransformDebugItem;
7025     rootClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7026     TransformDebugItem *child = new TransformDebugItem;
7027     child->setParentItem(rootClipper);
7028     child->setPos(2, 2);
7029     TransformDebugItem *grandChildClipper = new TransformDebugItem;
7030     grandChildClipper->setParentItem(child);
7031     grandChildClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7032     grandChildClipper->setPos(4, 4);
7033     TransformDebugItem *greatGrandChild = new TransformDebugItem;
7034     greatGrandChild->setPos(2, 2);
7035     greatGrandChild->setParentItem(grandChildClipper);
7036     TransformDebugItem *grandChildClipper2 = new TransformDebugItem;
7037     grandChildClipper2->setParentItem(child);
7038     grandChildClipper2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7039     grandChildClipper2->setPos(8, 8);
7040     TransformDebugItem *greatGrandChild2 = new TransformDebugItem;
7041     greatGrandChild2->setPos(2, 2);
7042     greatGrandChild2->setParentItem(grandChildClipper2);
7043     TransformDebugItem *grandChildClipper3 = new TransformDebugItem;
7044     grandChildClipper3->setParentItem(child);
7045     grandChildClipper3->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7046     grandChildClipper3->setPos(12, 12);
7047     TransformDebugItem *greatGrandChild3 = new TransformDebugItem;
7048     greatGrandChild3->setPos(2, 2);
7049     greatGrandChild3->setParentItem(grandChildClipper3);
7050
7051     QGraphicsScene scene;
7052     scene.addItem(rootClipper);
7053
7054     QImage image(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
7055     image.fill(0);
7056     QPainter p(&image);
7057     scene.render(&p);
7058     p.end();
7059
7060     QCOMPARE(rootClipper->x, QTransform(1, 0, 0, 0, 1, 0, 10, 10, 1));
7061     QCOMPARE(child->x, QTransform(1, 0, 0, 0, 1, 0, 12, 12, 1));
7062     QCOMPARE(grandChildClipper->x, QTransform(1, 0, 0, 0, 1, 0, 16, 16, 1));
7063     QCOMPARE(greatGrandChild->x, QTransform(1, 0, 0, 0, 1, 0, 18, 18, 1));
7064     QCOMPARE(grandChildClipper2->x, QTransform(1, 0, 0, 0, 1, 0, 20, 20, 1));
7065     QCOMPARE(greatGrandChild2->x, QTransform(1, 0, 0, 0, 1, 0, 22, 22, 1));
7066     QCOMPARE(grandChildClipper3->x, QTransform(1, 0, 0, 0, 1, 0, 24, 24, 1));
7067     QCOMPARE(greatGrandChild3->x, QTransform(1, 0, 0, 0, 1, 0, 26, 26, 1));
7068 }
7069
7070 void tst_QGraphicsItem::sceneTransformCache()
7071 {
7072     // Test that an item's scene transform is updated correctly when the
7073     // parent is transformed.
7074     QGraphicsScene scene;
7075     QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
7076     QGraphicsRectItem *rect2 = scene.addRect(0, 0, 100, 100);
7077     rect2->setParentItem(rect);
7078     rect2->rotate(90);
7079     rect->translate(0, 50);
7080     QGraphicsView view(&scene);
7081     view.show();
7082 #ifdef Q_WS_X11
7083     qt_x11_wait_for_window_manager(&view);
7084 #endif
7085
7086     rect->translate(0, 100);
7087     QTransform x;
7088     x.translate(0, 150);
7089     x.rotate(90);
7090     QCOMPARE(rect2->sceneTransform(), x);
7091
7092     scene.removeItem(rect);
7093
7094     //Crazy use case : rect4 child of rect3 so the transformation of rect4 will be cached.Good!
7095     //We remove rect4 from the scene, then the validTransform bit flag is set to 0 and the index of the cache
7096     //add to the freeTransformSlots. The problem was that sceneTransformIndex was not set to -1 so if a new item arrive
7097     //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
7098     //added back to the scene then it will set the transform to his old sceneTransformIndex value that will erase the new
7099     //value of rect6 so rect6 transform will be wrong.
7100     QGraphicsRectItem *rect3 = scene.addRect(0, 0, 100, 100);
7101     QGraphicsRectItem *rect4 = scene.addRect(0, 0, 100, 100);
7102     rect3->setPos(QPointF(10,10));
7103
7104     rect4->setParentItem(rect3);
7105     rect4->setPos(QPointF(10,10));
7106
7107     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(20,20));
7108
7109     scene.removeItem(rect4);
7110     //rect4 transform is local only
7111     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7112
7113     QGraphicsRectItem *rect5 = scene.addRect(0, 0, 100, 100);
7114     QGraphicsRectItem *rect6 = scene.addRect(0, 0, 100, 100);
7115     rect5->setPos(QPointF(20,20));
7116
7117     rect6->setParentItem(rect5);
7118     rect6->setPos(QPointF(10,10));
7119     //test if rect6 transform is ok
7120     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7121
7122     scene.addItem(rect4);
7123
7124     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7125     //test if rect6 transform is still correct
7126     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7127 }
7128
7129 void tst_QGraphicsItem::tabChangesFocus_data()
7130 {
7131     QTest::addColumn<bool>("tabChangesFocus");
7132     QTest::newRow("tab changes focus") << true;
7133     QTest::newRow("tab doesn't change focus") << false;
7134 }
7135
7136 void tst_QGraphicsItem::tabChangesFocus()
7137 {
7138     QFETCH(bool, tabChangesFocus);
7139
7140     QGraphicsScene scene;
7141     QGraphicsTextItem *item = scene.addText("Hello");
7142     item->setTabChangesFocus(tabChangesFocus);
7143     item->setTextInteractionFlags(Qt::TextEditorInteraction);
7144     item->setFocus();
7145
7146     QDial *dial1 = new QDial;
7147     QGraphicsView *view = new QGraphicsView(&scene);
7148
7149     QDial *dial2 = new QDial;
7150     QVBoxLayout *layout = new QVBoxLayout;
7151     layout->addWidget(dial1);
7152     layout->addWidget(view);
7153     layout->addWidget(dial2);
7154
7155     QWidget widget;
7156     widget.setLayout(layout);
7157     widget.show();
7158     QTest::qWaitForWindowShown(&widget);
7159     QTest::qWait(2000);
7160
7161     QTRY_VERIFY(scene.isActive());
7162
7163     dial1->setFocus();
7164     QTest::qWait(15);
7165     QTRY_VERIFY(dial1->hasFocus());
7166
7167     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7168     QTest::qWait(15);
7169     QTRY_VERIFY(view->hasFocus());
7170     QTRY_VERIFY(item->hasFocus());
7171
7172     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7173     QTest::qWait(15);
7174
7175     if (tabChangesFocus) {
7176         QTRY_VERIFY(!view->hasFocus());
7177         QTRY_VERIFY(!item->hasFocus());
7178         QTRY_VERIFY(dial2->hasFocus());
7179     } else {
7180         QTRY_VERIFY(view->hasFocus());
7181         QTRY_VERIFY(item->hasFocus());
7182         QCOMPARE(item->toPlainText(), QString("\tHello"));
7183     }
7184 }
7185
7186 void tst_QGraphicsItem::cacheMode()
7187 {
7188     QGraphicsScene scene(0, 0, 100, 100);
7189     QGraphicsView view(&scene);
7190     view.resize(150, 150);
7191     view.show();
7192     QApplication::setActiveWindow(&view);
7193     QTest::qWaitForWindowShown(&view);
7194
7195     // Increase the probability of window activation
7196     // not causing another repaint of test items.
7197     QTest::qWait(50);
7198
7199     EventTester *tester = new EventTester;
7200     EventTester *testerChild = new EventTester;
7201     testerChild->setParentItem(tester);
7202     EventTester *testerChild2 = new EventTester;
7203     testerChild2->setParentItem(testerChild);
7204     testerChild2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
7205
7206     scene.addItem(tester);
7207     QTest::qWait(10);
7208
7209     for (int i = 0; i < 2; ++i) {
7210         // No visual change.
7211         QTRY_COMPARE(tester->repaints, 1);
7212         QCOMPARE(testerChild->repaints, 1);
7213         QCOMPARE(testerChild2->repaints, 1);
7214         tester->setCacheMode(QGraphicsItem::NoCache);
7215         testerChild->setCacheMode(QGraphicsItem::NoCache);
7216         testerChild2->setCacheMode(QGraphicsItem::NoCache);
7217         QTest::qWait(25);
7218         QTRY_COMPARE(tester->repaints, 1);
7219         QCOMPARE(testerChild->repaints, 1);
7220         QCOMPARE(testerChild2->repaints, 1);
7221         tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7222         testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7223         testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7224         QTest::qWait(25);
7225     }
7226
7227     // The first move causes a repaint as the item is painted into its pixmap.
7228     // (Only occurs if the item has previously been painted without cache).
7229     tester->setPos(10, 10);
7230     testerChild->setPos(10, 10);
7231     testerChild2->setPos(10, 10);
7232     QTest::qWait(25);
7233     QTRY_COMPARE(tester->repaints, 2);
7234     QCOMPARE(testerChild->repaints, 2);
7235     QCOMPARE(testerChild2->repaints, 2);
7236
7237     // Consecutive moves should not repaint.
7238     tester->setPos(20, 20);
7239     testerChild->setPos(20, 20);
7240     testerChild2->setPos(20, 20);
7241     QTest::qWait(250);
7242     QCOMPARE(tester->repaints, 2);
7243     QCOMPARE(testerChild->repaints, 2);
7244     QCOMPARE(testerChild2->repaints, 2);
7245
7246     // Translating does not result in a repaint.
7247     tester->translate(10, 10);
7248     QTest::qWait(25);
7249     QTRY_COMPARE(tester->repaints, 2);
7250     QCOMPARE(testerChild->repaints, 2);
7251     QCOMPARE(testerChild2->repaints, 2);
7252
7253     // Rotating results in a repaint.
7254     tester->rotate(45);
7255     QTest::qWait(25);
7256     QTRY_COMPARE(tester->repaints, 3);
7257     QCOMPARE(testerChild->repaints, 3);
7258     QCOMPARE(testerChild2->repaints, 2);
7259
7260     // Change to ItemCoordinateCache (triggers repaint).
7261     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7262     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7263     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7264     QTest::qWait(25);
7265     QTRY_COMPARE(tester->repaints, 4);
7266     QCOMPARE(testerChild->repaints, 4);
7267     QCOMPARE(testerChild2->repaints, 3);
7268
7269     // Rotating items with ItemCoordinateCache doesn't cause a repaint.
7270     tester->rotate(22);
7271     testerChild->rotate(22);
7272     testerChild2->rotate(22);
7273     QTest::qWait(25);
7274     QTRY_COMPARE(tester->repaints, 4);
7275     QTRY_COMPARE(testerChild->repaints, 4);
7276     QTRY_COMPARE(testerChild2->repaints, 3);
7277     tester->resetTransform();
7278     testerChild->resetTransform();
7279     testerChild2->resetTransform();
7280
7281     // Explicit update causes a repaint.
7282     tester->update(0, 0, 5, 5);
7283     QTest::qWait(25);
7284     QTRY_COMPARE(tester->repaints, 5);
7285     QCOMPARE(testerChild->repaints, 4);
7286     QCOMPARE(testerChild2->repaints, 3);
7287
7288     // Updating outside the item's bounds does not cause a repaint.
7289     tester->update(10, 10, 5, 5);
7290     QTest::qWait(25);
7291     QTRY_COMPARE(tester->repaints, 5);
7292     QCOMPARE(testerChild->repaints, 4);
7293     QCOMPARE(testerChild2->repaints, 3);
7294
7295     // Resizing an item should cause a repaint of that item. (because of
7296     // autosize).
7297     tester->setGeometry(QRectF(-15, -15, 30, 30));
7298     QTest::qWait(25);
7299     QTRY_COMPARE(tester->repaints, 6);
7300     QCOMPARE(testerChild->repaints, 4);
7301     QCOMPARE(testerChild2->repaints, 3);
7302
7303     // Set fixed size.
7304     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7305     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7306     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7307     QTest::qWait(20);
7308     QTRY_COMPARE(tester->repaints, 7);
7309     QCOMPARE(testerChild->repaints, 5);
7310     QCOMPARE(testerChild2->repaints, 4);
7311
7312     // Resizing the item should cause a repaint.
7313     testerChild->setGeometry(QRectF(-15, -15, 30, 30));
7314     QTest::qWait(25);
7315     QTRY_COMPARE(tester->repaints, 7);
7316     QCOMPARE(testerChild->repaints, 6);
7317     QCOMPARE(testerChild2->repaints, 4);
7318
7319     // Scaling the view does not cause a repaint.
7320     view.scale(0.7, 0.7);
7321     QTest::qWait(25);
7322     QTRY_COMPARE(tester->repaints, 7);
7323     QCOMPARE(testerChild->repaints, 6);
7324     QCOMPARE(testerChild2->repaints, 4);
7325
7326     // Switch to device coordinate cache.
7327     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7328     testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7329     testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7330     QTest::qWait(25);
7331     QTRY_COMPARE(tester->repaints, 8);
7332     QCOMPARE(testerChild->repaints, 7);
7333     QCOMPARE(testerChild2->repaints, 5);
7334
7335     // Scaling the view back should cause repaints for two of the items.
7336     view.setTransform(QTransform());
7337     QTest::qWait(25);
7338     QTRY_COMPARE(tester->repaints, 9);
7339     QCOMPARE(testerChild->repaints, 8);
7340     QCOMPARE(testerChild2->repaints, 5);
7341
7342     // Rotating the base item (perspective) should repaint two items.
7343     tester->setTransform(QTransform().rotate(10, Qt::XAxis));
7344     QTest::qWait(25);
7345     QTRY_COMPARE(tester->repaints, 10);
7346     QCOMPARE(testerChild->repaints, 9);
7347     QCOMPARE(testerChild2->repaints, 5);
7348
7349     // Moving the middle item should case a repaint even if it's a move,
7350     // because the parent is rotated with a perspective.
7351     testerChild->setPos(1, 1);
7352     QTest::qWait(25);
7353     QTRY_COMPARE(tester->repaints, 11);
7354     QTRY_COMPARE(testerChild->repaints, 10);
7355     QTRY_COMPARE(testerChild2->repaints, 5);
7356     tester->resetTransform();
7357
7358     // Make a huge item
7359     tester->setGeometry(QRectF(-4000, -4000, 8000, 8000));
7360     QTRY_COMPARE(tester->repaints, 12);
7361     QTRY_COMPARE(testerChild->repaints, 11);
7362     QTRY_COMPARE(testerChild2->repaints, 5);
7363
7364     // Move the large item - will cause a repaint as the
7365     // cache is clipped.
7366     tester->setPos(5, 0);
7367     QTRY_COMPARE(tester->repaints, 13);
7368     QTRY_COMPARE(testerChild->repaints, 11);
7369     QTRY_COMPARE(testerChild2->repaints, 5);
7370
7371     // Hiding and showing should invalidate the cache
7372     tester->hide();
7373     QTest::qWait(25);
7374     tester->show();
7375     QTRY_COMPARE(tester->repaints, 14);
7376     QTRY_COMPARE(testerChild->repaints, 12);
7377     QTRY_COMPARE(testerChild2->repaints, 6);
7378 }
7379
7380 void tst_QGraphicsItem::cacheMode2()
7381 {
7382     QGraphicsScene scene(0, 0, 100, 100);
7383     QGraphicsView view(&scene);
7384     view.resize(150, 150);
7385     view.show();
7386     QApplication::setActiveWindow(&view);
7387     QTest::qWaitForWindowShown(&view);
7388
7389     // Increase the probability of window activation
7390     // not causing another repaint of test items.
7391     QTest::qWait(50);
7392
7393     EventTester *tester = new EventTester;
7394     scene.addItem(tester);
7395     QTest::qWait(10);
7396     QTRY_COMPARE(tester->repaints, 1);
7397
7398     // Switching from NoCache to NoCache (no repaint)
7399     tester->setCacheMode(QGraphicsItem::NoCache);
7400     QTest::qWait(50);
7401     QTRY_COMPARE(tester->repaints, 1);
7402
7403     // Switching from NoCache to DeviceCoordinateCache (no repaint)
7404     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7405     QTest::qWait(50);
7406     QTRY_COMPARE(tester->repaints, 1);
7407
7408     // Switching from DeviceCoordinateCache to DeviceCoordinateCache (no repaint)
7409     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7410     QTest::qWait(50);
7411     QTRY_COMPARE(tester->repaints, 1);
7412
7413     // Switching from DeviceCoordinateCache to NoCache (no repaint)
7414     tester->setCacheMode(QGraphicsItem::NoCache);
7415     QTest::qWait(50);
7416     QTRY_COMPARE(tester->repaints, 1);
7417
7418     // Switching from NoCache to ItemCoordinateCache (repaint)
7419     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7420     QTest::qWait(50);
7421     QTRY_COMPARE(tester->repaints, 2);
7422
7423     // Switching from ItemCoordinateCache to ItemCoordinateCache (no repaint)
7424     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7425     QTest::qWait(50);
7426     QTRY_COMPARE(tester->repaints, 2);
7427
7428     // Switching from ItemCoordinateCache to ItemCoordinateCache with different size (repaint)
7429     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(100, 100));
7430     QTest::qWait(50);
7431     QTRY_COMPARE(tester->repaints, 3);
7432
7433     // Switching from ItemCoordinateCache to NoCache (repaint)
7434     tester->setCacheMode(QGraphicsItem::NoCache);
7435     QTest::qWait(50);
7436     QTRY_COMPARE(tester->repaints, 4);
7437
7438     // Switching from DeviceCoordinateCache to ItemCoordinateCache (repaint)
7439     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7440     QTest::qWait(50);
7441     QTRY_COMPARE(tester->repaints, 4);
7442     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7443     QTest::qWait(50);
7444     QTRY_COMPARE(tester->repaints, 5);
7445
7446     // Switching from ItemCoordinateCache to DeviceCoordinateCache (repaint)
7447     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7448     QTest::qWait(50);
7449     QTRY_COMPARE(tester->repaints, 6);
7450 }
7451
7452 void tst_QGraphicsItem::updateCachedItemAfterMove()
7453 {
7454     // A simple item that uses ItemCoordinateCache
7455     EventTester *tester = new EventTester;
7456     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7457
7458     // Add to a scene, show in a view, ensure it's painted and reset its
7459     // repaint counter.
7460     QGraphicsScene scene;
7461     scene.addItem(tester);
7462     QGraphicsView view(&scene);
7463     view.show();
7464     QTest::qWaitForWindowShown(&view);
7465
7466     QTest::qWait(12);
7467     QTRY_VERIFY(tester->repaints > 0);
7468     tester->repaints = 0;
7469
7470     // Move the item, should not cause repaints
7471     tester->setPos(10, 0);
7472     QTest::qWait(12);
7473     QCOMPARE(tester->repaints, 0);
7474
7475     // Move then update, should cause one repaint
7476     tester->setPos(20, 0);
7477     tester->update();
7478     QTest::qWait(12);
7479     QCOMPARE(tester->repaints, 1);
7480
7481     // Hiding the item doesn't cause a repaint
7482     tester->hide();
7483     QTest::qWait(12);
7484     QCOMPARE(tester->repaints, 1);
7485
7486     // Moving a hidden item doesn't cause a repaint
7487     tester->setPos(30, 0);
7488     tester->update();
7489     QTest::qWait(12);
7490     QCOMPARE(tester->repaints, 1);
7491 }
7492
7493 class Track : public QGraphicsRectItem
7494 {
7495 public:
7496     Track(const QRectF &rect)
7497         : QGraphicsRectItem(rect)
7498     {
7499         setAcceptHoverEvents(true);
7500     }
7501
7502     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7503     {
7504         QGraphicsRectItem::paint(painter, option, widget);
7505         painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1x%2\n%3x%4").arg(p.x()).arg(p.y()).arg(sp.x()).arg(sp.y()));
7506     }
7507
7508 protected:
7509     void hoverMoveEvent(QGraphicsSceneHoverEvent *event)
7510     {
7511         p = event->pos();
7512         sp = event->widget()->mapFromGlobal(event->screenPos());
7513         update();
7514     }
7515 private:
7516     QPointF p;
7517     QPoint sp;
7518 };
7519
7520 void tst_QGraphicsItem::deviceTransform_data()
7521 {
7522     QTest::addColumn<bool>("untransformable1");
7523     QTest::addColumn<bool>("untransformable2");
7524     QTest::addColumn<bool>("untransformable3");
7525     QTest::addColumn<qreal>("rotation1");
7526     QTest::addColumn<qreal>("rotation2");
7527     QTest::addColumn<qreal>("rotation3");
7528     QTest::addColumn<QTransform>("deviceX");
7529     QTest::addColumn<QPointF>("mapResult1");
7530     QTest::addColumn<QPointF>("mapResult2");
7531     QTest::addColumn<QPointF>("mapResult3");
7532
7533     QTest::newRow("nil") << false << false << false
7534                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7535                          << QTransform()
7536                          << QPointF(150, 150) << QPointF(250, 250) << QPointF(350, 350);
7537     QTest::newRow("deviceX rot 90") << false << false << false
7538                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7539                          << QTransform().rotate(90)
7540                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-350, 350);
7541     QTest::newRow("deviceX rot 90 100") << true << false << false
7542                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7543                          << QTransform().rotate(90)
7544                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7545     QTest::newRow("deviceX rot 90 010") << false << true << false
7546                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7547                          << QTransform().rotate(90)
7548                          << QPointF(-150, 150) << QPointF(-150, 250) << QPointF(-50, 350);
7549     QTest::newRow("deviceX rot 90 001") << false << false << true
7550                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7551                          << QTransform().rotate(90)
7552                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-250, 350);
7553     QTest::newRow("deviceX rot 90 111") << true << true << true
7554                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7555                          << QTransform().rotate(90)
7556                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7557     QTest::newRow("deviceX rot 90 101") << true << false << true
7558                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7559                          << QTransform().rotate(90)
7560                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7561 }
7562
7563 void tst_QGraphicsItem::deviceTransform()
7564 {
7565     QFETCH(bool, untransformable1);
7566     QFETCH(bool, untransformable2);
7567     QFETCH(bool, untransformable3);
7568     QFETCH(qreal, rotation1);
7569     QFETCH(qreal, rotation2);
7570     QFETCH(qreal, rotation3);
7571     QFETCH(QTransform, deviceX);
7572     QFETCH(QPointF, mapResult1);
7573     QFETCH(QPointF, mapResult2);
7574     QFETCH(QPointF, mapResult3);
7575
7576     QGraphicsScene scene;
7577     Track *rect1 = new Track(QRectF(0, 0, 100, 100));
7578     Track *rect2 = new Track(QRectF(0, 0, 100, 100));
7579     Track *rect3 = new Track(QRectF(0, 0, 100, 100));
7580     rect2->setParentItem(rect1);
7581     rect3->setParentItem(rect2);
7582     rect1->setPos(100, 100);
7583     rect2->setPos(100, 100);
7584     rect3->setPos(100, 100);
7585     rect1->rotate(rotation1);
7586     rect2->rotate(rotation2);
7587     rect3->rotate(rotation3);
7588     rect1->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable1);
7589     rect2->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable2);
7590     rect3->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable3);
7591     rect1->setBrush(Qt::red);
7592     rect2->setBrush(Qt::green);
7593     rect3->setBrush(Qt::blue);
7594     scene.addItem(rect1);
7595
7596     QCOMPARE(rect1->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult1);
7597     QCOMPARE(rect2->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult2);
7598     QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3);
7599 }
7600
7601 void tst_QGraphicsItem::update()
7602 {
7603     QGraphicsScene scene;
7604     scene.setSceneRect(-100, -100, 200, 200);
7605     QWidget topLevel;
7606     MyGraphicsView view(&scene,&topLevel);
7607
7608     topLevel.resize(300, 300);
7609     topLevel.show();
7610 #ifdef Q_WS_X11
7611     qt_x11_wait_for_window_manager(&view);
7612 #endif
7613     QTest::qWait(100);
7614
7615     EventTester *item = new EventTester;
7616     scene.addItem(item);
7617     QTest::qWait(100); // Make sure all pending updates are processed.
7618     item->repaints = 0;
7619
7620     item->update(); // Item marked as dirty
7621     scene.update(); // Entire scene marked as dirty
7622     qApp->processEvents();
7623     QCOMPARE(item->repaints, 1);
7624
7625     // Make sure the dirty state from the previous update is reset so that
7626     // the item don't think it is already dirty and discards this update.
7627     item->update();
7628     qApp->processEvents();
7629     QCOMPARE(item->repaints, 2);
7630
7631     // Make sure a partial update doesn't cause a full update to be discarded.
7632     view.reset();
7633     item->repaints = 0;
7634     item->update(QRectF(0, 0, 5, 5));
7635     item->update();
7636     qApp->processEvents();
7637     QCOMPARE(item->repaints, 1);
7638     QCOMPARE(view.repaints, 1);
7639     QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7640                                                          .mapRect(item->boundingRect()).toAlignedRect();
7641     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7642     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7643     QCOMPARE(view.paintedRegion, expectedRegion);
7644
7645     // Make sure update requests outside the bounding rect are discarded.
7646     view.reset();
7647     item->repaints = 0;
7648     item->update(-15, -15, 5, 5); // Item's brect: (-10, -10, 20, 20)
7649     qApp->processEvents();
7650     QCOMPARE(item->repaints, 0);
7651     QCOMPARE(view.repaints, 0);
7652
7653     // Make sure the area occupied by an item is repainted when hiding it.
7654     view.reset();
7655     item->repaints = 0;
7656     item->update(); // Full update; all sub-sequent update requests are discarded.
7657     item->hide(); // visible set to 0. ignoreVisible must be set to 1; the item won't be processed otherwise.
7658     qApp->processEvents();
7659     QCOMPARE(item->repaints, 0);
7660     QCOMPARE(view.repaints, 1);
7661     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7662     QCOMPARE(view.paintedRegion, expectedRegion);
7663
7664     // Make sure item is repainted when shown (after being hidden).
7665     view.reset();
7666     item->repaints = 0;
7667     item->show();
7668     qApp->processEvents();
7669     QCOMPARE(item->repaints, 1);
7670     QCOMPARE(view.repaints, 1);
7671     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7672     QCOMPARE(view.paintedRegion, expectedRegion);
7673
7674     item->repaints = 0;
7675     item->hide();
7676     qApp->processEvents();
7677     view.reset();
7678     const QPointF originalPos = item->pos();
7679     item->setPos(5000, 5000);
7680     qApp->processEvents();
7681     QCOMPARE(item->repaints, 0);
7682     QCOMPARE(view.repaints, 0);
7683     qApp->processEvents();
7684
7685     item->setPos(originalPos);
7686     qApp->processEvents();
7687     QCOMPARE(item->repaints, 0);
7688     QCOMPARE(view.repaints, 0);
7689     item->show();
7690     qApp->processEvents();
7691     QCOMPARE(item->repaints, 1);
7692     QCOMPARE(view.repaints, 1);
7693     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7694     QCOMPARE(view.paintedRegion, expectedRegion);
7695
7696     QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
7697     item->setPos(originalPos + QPoint(50, 50));
7698     viewPrivate->updateAll();
7699     QVERIFY(viewPrivate->fullUpdatePending);
7700     QTest::qWait(50);
7701     item->repaints = 0;
7702     view.reset();
7703     item->setPos(originalPos);
7704     QTest::qWait(50);
7705     qApp->processEvents();
7706     QCOMPARE(item->repaints, 1);
7707     QCOMPARE(view.repaints, 1);
7708     COMPARE_REGIONS(view.paintedRegion, expectedRegion + expectedRegion.translated(50, 50));
7709
7710     // Make sure moving a parent item triggers an update on the children
7711     // (even though the parent itself is outside the viewport).
7712     QGraphicsRectItem *parent = new QGraphicsRectItem(0, 0, 10, 10);
7713     parent->setPos(-400, 0);
7714     item->setParentItem(parent);
7715     item->setPos(400, 0);
7716     scene.addItem(parent);
7717     QTest::qWait(50);
7718     itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7719                                                    .mapRect(item->boundingRect()).toAlignedRect();
7720     expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7721     view.reset();
7722     item->repaints = 0;
7723     parent->translate(-400, 0);
7724     qApp->processEvents();
7725     QCOMPARE(item->repaints, 0);
7726     QCOMPARE(view.repaints, 1);
7727     QCOMPARE(view.paintedRegion, expectedRegion);
7728     view.reset();
7729     item->repaints = 0;
7730     parent->translate(400, 0);
7731     qApp->processEvents();
7732     QCOMPARE(item->repaints, 1);
7733     QCOMPARE(view.repaints, 1);
7734     QCOMPARE(view.paintedRegion, expectedRegion);
7735     QCOMPARE(view.paintedRegion, expectedRegion);
7736 }
7737
7738 void tst_QGraphicsItem::setTransformProperties_data()
7739 {
7740     QTest::addColumn<QPointF>("origin");
7741     QTest::addColumn<qreal>("rotation");
7742     QTest::addColumn<qreal>("scale");
7743
7744     QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(1.0);
7745
7746     QTest::newRow("rotation") << QPointF() << qreal(42.2) << qreal(1.0);
7747
7748     QTest::newRow("rotation dicentred") << QPointF(qreal(22.3), qreal(-56.2))
7749                                 << qreal(-2578.2)
7750                                 << qreal(1.0);
7751
7752     QTest::newRow("Scale")    << QPointF() << qreal(0.0)
7753                                           << qreal(6);
7754
7755     QTest::newRow("Everything dicentred")  << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196);
7756 }
7757
7758 /**
7759  * the normal QCOMPARE doesn't work because it doesn't use qFuzzyCompare
7760  */
7761 #define QCOMPARE_TRANSFORM(X1, X2)   QVERIFY(((X1)*(X2).inverted()).isIdentity())
7762
7763 void tst_QGraphicsItem::setTransformProperties()
7764 {
7765     QFETCH(QPointF,origin);
7766     QFETCH(qreal,rotation);
7767     QFETCH(qreal,scale);
7768
7769     QTransform result;
7770     result.translate(origin.x(), origin.y());
7771     result.rotate(rotation, Qt::ZAxis);
7772     result.scale(scale, scale);
7773     result.translate(-origin.x(), -origin.y());
7774
7775     QGraphicsScene scene;
7776     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
7777     scene.addItem(item);
7778
7779     item->setRotation(rotation);
7780     item->setScale(scale);
7781     item->setTransformOriginPoint(origin);
7782
7783     QCOMPARE(item->rotation(), rotation);
7784     QCOMPARE(item->scale(), scale);
7785     QCOMPARE(item->transformOriginPoint(), origin);
7786
7787     QCOMPARE(QTransform(), item->transform());
7788     QCOMPARE(result, item->sceneTransform());
7789
7790     //-----------------------------------------------------------------
7791     //Change the rotation Z
7792     item->setRotation(45);
7793     QTransform result2;
7794     result2.translate(origin.x(), origin.y());
7795     result2.rotate(45);
7796     result2.scale(scale, scale);
7797     result2.translate(-origin.x(), -origin.y());
7798
7799     QCOMPARE(item->rotation(), 45.);
7800     QCOMPARE(item->scale(), scale);
7801     QCOMPARE(item->transformOriginPoint(), origin);
7802
7803     QCOMPARE(QTransform(), item->transform());
7804     QCOMPARE(result2, item->sceneTransform());
7805
7806     //-----------------------------------------------------------------
7807     // calling setTransform() and setPos should change the sceneTransform
7808     item->setTransform(result);
7809     item->setPos(100, -150.5);
7810
7811     QCOMPARE(item->rotation(), 45.);
7812     QCOMPARE(item->scale(), scale);
7813     QCOMPARE(item->transformOriginPoint(), origin);
7814     QCOMPARE(result, item->transform());
7815
7816     QTransform result3(result);
7817
7818     result3.translate(origin.x(), origin.y());
7819     result3.rotate(45);
7820     result3.scale(scale, scale);
7821     result3.translate(-origin.x(), -origin.y());
7822
7823     result3 *= QTransform::fromTranslate(100, -150.5); //the pos;
7824
7825     QCOMPARE(result3, item->sceneTransform());
7826
7827     //-----------------------------------------------------
7828     // setting the propertiees should be the same as setting a transform
7829     {//with center origin on the matrix
7830         QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7831         scene.addItem(item1);
7832         QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7833         scene.addItem(item2);
7834
7835         item1->setPos(12.3, -5);
7836         item2->setPos(12.3, -5);
7837         item1->setRotation(rotation);
7838         item1->setScale(scale);
7839         item1->setTransformOriginPoint(origin);
7840
7841         item2->setTransform(result);
7842
7843         QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform());
7844
7845         QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform());
7846         QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform());
7847     }
7848 }
7849
7850 class MyStyleOptionTester : public QGraphicsRectItem
7851 {
7852 public:
7853     MyStyleOptionTester(const QRectF &rect)
7854         : QGraphicsRectItem(rect), startTrack(false)
7855     {}
7856
7857     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7858     {
7859         if (startTrack) {
7860             //Doesn't use the extended style option so the exposed rect is the boundingRect
7861             if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) {
7862                 QCOMPARE(option->exposedRect, boundingRect());
7863                 QCOMPARE(option->matrix, QMatrix());
7864             } else {
7865                 QVERIFY(option->exposedRect != QRect());
7866                 QVERIFY(option->exposedRect != boundingRect());
7867                 QCOMPARE(option->matrix, sceneTransform().toAffine());
7868             }
7869         }
7870         QGraphicsRectItem::paint(painter, option, widget);
7871     }
7872     bool startTrack;
7873 };
7874
7875 void tst_QGraphicsItem::itemUsesExtendedStyleOption()
7876 {
7877     QGraphicsScene scene(0, 0, 300, 300);
7878     QGraphicsPixmapItem item;
7879     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7880     QCOMPARE(item.flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
7881     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
7882     QCOMPARE(item.flags(), 0);
7883
7884     //We now test the content of the style option
7885     MyStyleOptionTester *rect = new MyStyleOptionTester(QRect(0, 0, 100, 100));
7886     scene.addItem(rect);
7887     rect->setPos(200, 200);
7888     QWidget topLevel;
7889     QGraphicsView view(&scene, &topLevel);
7890     topLevel.setWindowFlags(Qt::X11BypassWindowManagerHint);
7891     rect->startTrack = false;
7892     topLevel.show();
7893     QTest::qWaitForWindowShown(&view);
7894     QTest::qWait(60);
7895     rect->startTrack = true;
7896     rect->update(10, 10, 10, 10);
7897     QTest::qWait(60);
7898     rect->startTrack = false;
7899     rect->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7900     QVERIFY((rect->flags() & QGraphicsItem::ItemUsesExtendedStyleOption));
7901     QTest::qWait(60);
7902     rect->startTrack = true;
7903     rect->update(10, 10, 10, 10);
7904     QTest::qWait(60);
7905 }
7906
7907 void tst_QGraphicsItem::itemSendsGeometryChanges()
7908 {
7909     ItemChangeTester item;
7910     item.setFlags(0);
7911     item.clear();
7912
7913     QTransform x = QTransform().rotate(45);
7914     QPointF pos(10, 10);
7915     qreal o(0.5);
7916     qreal r(10.0);
7917     qreal s(1.5);
7918     QPointF origin(1.0, 1.0);
7919     item.setTransform(x);
7920     item.setPos(pos);
7921     item.setRotation(r);
7922     item.setScale(s);
7923     item.setTransformOriginPoint(origin);
7924     QCOMPARE(item.transform(), x);
7925     QCOMPARE(item.pos(), pos);
7926     QCOMPARE(item.rotation(), r);
7927     QCOMPARE(item.scale(), s);
7928     QCOMPARE(item.transformOriginPoint(), origin);
7929     QCOMPARE(item.changes.size(), 0);
7930
7931     item.setOpacity(o);
7932     QCOMPARE(item.changes.size(), 2); // opacity
7933
7934     item.setFlag(QGraphicsItem::ItemSendsGeometryChanges);
7935     QCOMPARE(item.changes.size(), 4); // flags
7936     item.setTransform(QTransform());
7937     item.setPos(QPointF());
7938     QCOMPARE(item.changes.size(), 8); // transform + pos
7939     QCOMPARE(item.transform(), QTransform());
7940     QCOMPARE(item.pos(), QPointF());
7941     QCOMPARE(item.opacity(), o);
7942     item.setRotation(0.0);
7943     item.setScale(1.0);
7944     item.setTransformOriginPoint(0.0, 0.0);
7945     QCOMPARE(item.changes.size(), 14); // rotation + scale + origin
7946     QCOMPARE(item.rotation(), qreal(0.0));
7947     QCOMPARE(item.scale(), qreal(1.0));
7948     QCOMPARE(item.transformOriginPoint(), QPointF(0.0, 0.0));
7949
7950     QCOMPARE(item.changes, QList<QGraphicsItem::GraphicsItemChange>()
7951              << QGraphicsItem::ItemOpacityChange
7952              << QGraphicsItem::ItemOpacityHasChanged
7953              << QGraphicsItem::ItemFlagsChange
7954              << QGraphicsItem::ItemFlagsHaveChanged
7955              << QGraphicsItem::ItemTransformChange
7956              << QGraphicsItem::ItemTransformHasChanged
7957              << QGraphicsItem::ItemPositionChange
7958              << QGraphicsItem::ItemPositionHasChanged
7959              << QGraphicsItem::ItemRotationChange
7960              << QGraphicsItem::ItemRotationHasChanged
7961              << QGraphicsItem::ItemScaleChange
7962              << QGraphicsItem::ItemScaleHasChanged
7963              << QGraphicsItem::ItemTransformOriginPointChange
7964              << QGraphicsItem::ItemTransformOriginPointHasChanged);
7965 }
7966
7967 // Make sure we update moved items correctly.
7968 void tst_QGraphicsItem::moveItem()
7969 {
7970     QGraphicsScene scene;
7971     scene.setSceneRect(-50, -50, 200, 200);
7972
7973     MyGraphicsView view(&scene);
7974     view.show();
7975 #ifdef Q_WS_X11
7976     qt_x11_wait_for_window_manager(&view);
7977 #endif
7978     QTest::qWait(100);
7979
7980     EventTester *parent = new EventTester;
7981     EventTester *child = new EventTester(parent);
7982     EventTester *grandChild = new EventTester(child);
7983
7984 #define RESET_COUNTERS \
7985     parent->repaints = 0; \
7986     child->repaints = 0; \
7987     grandChild->repaints = 0; \
7988     view.reset();
7989
7990     scene.addItem(parent);
7991     QTest::qWait(100);
7992
7993     RESET_COUNTERS
7994
7995     // Item's boundingRect:  (-10, -10, 20, 20).
7996     QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
7997                                      .mapRect(parent->boundingRect()).toAlignedRect()
7998                                      .adjusted(-2, -2, 2, 2); // Adjusted for antialiasing.
7999
8000     parent->setPos(20, 20);
8001     qApp->processEvents();
8002     QCOMPARE(parent->repaints, 1);
8003     QCOMPARE(view.repaints, 1);
8004     QRegion expectedParentRegion = parentDeviceBoundingRect; // old position
8005     parentDeviceBoundingRect.translate(20, 20);
8006     expectedParentRegion += parentDeviceBoundingRect; // new position
8007     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
8008
8009     RESET_COUNTERS
8010
8011     child->setPos(20, 20);
8012     qApp->processEvents();
8013     QCOMPARE(parent->repaints, 1);
8014     QCOMPARE(child->repaints, 1);
8015     QCOMPARE(view.repaints, 1);
8016     const QRegion expectedChildRegion = expectedParentRegion.translated(20, 20);
8017     COMPARE_REGIONS(view.paintedRegion, expectedChildRegion);
8018
8019     RESET_COUNTERS
8020
8021     grandChild->setPos(20, 20);
8022     qApp->processEvents();
8023     QCOMPARE(parent->repaints, 1);
8024     QCOMPARE(child->repaints, 1);
8025     QCOMPARE(grandChild->repaints, 1);
8026     QCOMPARE(view.repaints, 1);
8027     const QRegion expectedGrandChildRegion = expectedParentRegion.translated(40, 40);
8028     COMPARE_REGIONS(view.paintedRegion, expectedGrandChildRegion);
8029
8030     RESET_COUNTERS
8031
8032     parent->translate(20, 20);
8033     qApp->processEvents();
8034     QCOMPARE(parent->repaints, 1);
8035     QCOMPARE(child->repaints, 1);
8036     QCOMPARE(grandChild->repaints, 1);
8037     QCOMPARE(view.repaints, 1);
8038     expectedParentRegion.translate(20, 20);
8039     expectedParentRegion += expectedChildRegion.translated(20, 20);
8040     expectedParentRegion += expectedGrandChildRegion.translated(20, 20);
8041     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
8042 }
8043
8044 void tst_QGraphicsItem::moveLineItem()
8045 {
8046     QGraphicsScene scene;
8047     scene.setSceneRect(0, 0, 200, 200);
8048     QGraphicsLineItem *item = new QGraphicsLineItem(0, 0, 100, 0);
8049     item->setPos(50, 50);
8050     scene.addItem(item);
8051
8052     MyGraphicsView view(&scene);
8053     view.show();
8054 #ifdef Q_WS_X11
8055     qt_x11_wait_for_window_manager(&view);
8056 #endif
8057     QTest::qWait(200);
8058     view.reset();
8059
8060     QRectF brect = item->boundingRect();
8061     // Do same adjustments as in qgraphicsscene.cpp
8062     if (!brect.width())
8063         brect.adjust(qreal(-0.00001), 0, qreal(0.00001), 0);
8064     if (!brect.height())
8065         brect.adjust(0, qreal(-0.00001), 0, qreal(0.00001));
8066     const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
8067                                          .mapRect(brect).toAlignedRect();
8068     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // antialiasing
8069
8070     // Make sure the calculated region is correct.
8071     item->update();
8072     QTest::qWait(10);
8073     QTRY_COMPARE(view.paintedRegion, expectedRegion);
8074     view.reset();
8075
8076     // Old position: (50, 50)
8077     item->setPos(50, 100);
8078     expectedRegion += expectedRegion.translated(0, 50);
8079     QTest::qWait(10);
8080     QCOMPARE(view.paintedRegion, expectedRegion);
8081 }
8082
8083 void tst_QGraphicsItem::sorting_data()
8084 {
8085     QTest::addColumn<int>("index");
8086
8087     QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex);
8088     QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex);
8089 }
8090
8091 void tst_QGraphicsItem::sorting()
8092 {
8093     if (PlatformQuirks::isAutoMaximizing())
8094         QSKIP("Skipped because Platform is auto maximizing");
8095
8096     _paintedItems.clear();
8097
8098     QGraphicsScene scene;
8099     QGraphicsItem *grid[100][100];
8100     for (int x = 0; x < 100; ++x) {
8101         for (int y = 0; y < 100; ++y) {
8102             PainterItem *item = new PainterItem;
8103             item->setPos(x * 25, y * 25);
8104             item->setData(0, QString("%1x%2").arg(x).arg(y));
8105             grid[x][y] = item;
8106             scene.addItem(item);
8107         }
8108     }
8109
8110     PainterItem *item1 = new PainterItem;
8111     PainterItem *item2 = new PainterItem;
8112     item1->setData(0, "item1");
8113     item2->setData(0, "item2");
8114     scene.addItem(item1);
8115     scene.addItem(item2);
8116
8117     QGraphicsView view(&scene);
8118     view.setResizeAnchor(QGraphicsView::NoAnchor);
8119     view.setTransformationAnchor(QGraphicsView::NoAnchor);
8120     view.resize(120, 100);
8121     view.setFrameStyle(0);
8122     view.show();
8123 #ifdef Q_WS_X11
8124     qt_x11_wait_for_window_manager(&view);
8125 #endif
8126     QTest::qWait(100);
8127
8128     _paintedItems.clear();
8129
8130     view.viewport()->repaint();
8131 #if defined(Q_WS_MAC)
8132     // There's no difference between repaint and update on the Mac,
8133     // so we have to process events here to make sure we get the event.
8134     QTest::qWait(100);
8135 #endif
8136
8137     QCOMPARE(_paintedItems, QList<QGraphicsItem *>()
8138                  << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3]
8139                  << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3]
8140                  << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3]
8141                  << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3]
8142                  << grid[4][0] << grid[4][1] << grid[4][2] << grid[4][3]
8143                  << item1 << item2);
8144 }
8145
8146 void tst_QGraphicsItem::itemHasNoContents()
8147 {
8148     PainterItem *item1 = new PainterItem;
8149     PainterItem *item2 = new PainterItem;
8150     item2->setParentItem(item1);
8151     item2->setPos(50, 50);
8152     item1->setFlag(QGraphicsItem::ItemHasNoContents);
8153     item1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
8154
8155     QGraphicsScene scene;
8156     scene.addItem(item1);
8157
8158     QGraphicsView view(&scene);
8159     view.show();
8160     QTest::qWaitForWindowShown(&view);
8161     QTRY_VERIFY(!_paintedItems.isEmpty());
8162
8163     _paintedItems.clear();
8164
8165     view.viewport()->repaint();
8166 #ifdef Q_WS_MAC
8167     // There's no difference between update() and repaint() on the Mac,
8168     // so we have to process events here to make sure we get the event.
8169     QTest::qWait(10);
8170 #endif
8171
8172     QTRY_COMPARE(_paintedItems, QList<QGraphicsItem *>() << item2);
8173 }
8174
8175 void tst_QGraphicsItem::hitTestUntransformableItem()
8176 {
8177     QGraphicsScene scene;
8178     scene.setSceneRect(-100, -100, 200, 200);
8179
8180     QGraphicsView view(&scene);
8181     view.show();
8182 #ifdef Q_WS_X11
8183     qt_x11_wait_for_window_manager(&view);
8184 #endif
8185     QTest::qWait(100);
8186
8187     // Confuse the BSP with dummy items.
8188     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8189     dummy->setPos(-100, -100);
8190     scene.addItem(dummy);
8191     for (int i = 0; i < 100; ++i) {
8192         QGraphicsItem *parent = dummy;
8193         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8194         dummy->setPos(-100 + i, -100 + i);
8195         dummy->setParentItem(parent);
8196     }
8197
8198     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
8199     item1->setPos(-200, -200);
8200
8201     QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 20, 20);
8202     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8203     item2->setParentItem(item1);
8204     item2->setPos(200, 200);
8205
8206     QGraphicsRectItem *item3 = new QGraphicsRectItem(0, 0, 20, 20);
8207     item3->setParentItem(item2);
8208     item3->setPos(80, 80);
8209
8210     scene.addItem(item1);
8211     QTest::qWait(100);
8212
8213     QList<QGraphicsItem *> items = scene.items(QPointF(80, 80));
8214     QCOMPARE(items.size(), 1);
8215     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8216
8217     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8218     QTest::qWait(100);
8219
8220     items = scene.items(QPointF(80, 80));
8221     QCOMPARE(items.size(), 1);
8222     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8223 }
8224
8225 void tst_QGraphicsItem::hitTestGraphicsEffectItem()
8226 {
8227     QGraphicsScene scene;
8228     scene.setSceneRect(-100, -100, 200, 200);
8229
8230     QWidget toplevel;
8231
8232     QGraphicsView view(&scene, &toplevel);
8233     toplevel.resize(300, 300);
8234     toplevel.show();
8235 #ifdef Q_WS_X11
8236     qt_x11_wait_for_window_manager(&toplevel);
8237 #endif
8238     QTest::qWait(100);
8239
8240     // Confuse the BSP with dummy items.
8241     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8242     dummy->setPos(-100, -100);
8243     scene.addItem(dummy);
8244     for (int i = 0; i < 100; ++i) {
8245         QGraphicsItem *parent = dummy;
8246         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8247         dummy->setPos(-100 + i, -100 + i);
8248         dummy->setParentItem(parent);
8249     }
8250
8251     const QRectF itemBoundingRect(0, 0, 20, 20);
8252     EventTester *item1 = new EventTester;
8253     item1->br = itemBoundingRect;
8254     item1->setPos(-200, -200);
8255     item1->brush = Qt::red;
8256
8257     EventTester *item2 = new EventTester;
8258     item2->br = itemBoundingRect;
8259     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8260     item2->setParentItem(item1);
8261     item2->setPos(200, 200);
8262     item2->brush = Qt::green;
8263
8264     EventTester *item3 = new EventTester;
8265     item3->br = itemBoundingRect;
8266     item3->setParentItem(item2);
8267     item3->setPos(80, 80);
8268     item3->brush = Qt::blue;
8269
8270     scene.addItem(item1);
8271     QTest::qWait(100);
8272
8273     item1->repaints = 0;
8274     item2->repaints = 0;
8275     item3->repaints = 0;
8276
8277     // Apply shadow effect to the entire sub-tree.
8278     QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
8279     shadow->setOffset(-20, -20);
8280     item1->setGraphicsEffect(shadow);
8281     QTest::qWait(50);
8282
8283     // Make sure all visible items are repainted.
8284     QCOMPARE(item1->repaints, 1);
8285     QCOMPARE(item2->repaints, 1);
8286     QCOMPARE(item3->repaints, 1);
8287
8288     // Make sure an item doesn't respond to a click on its shadow.
8289     QList<QGraphicsItem *> items = scene.items(QPointF(75, 75));
8290     QVERIFY(items.isEmpty());
8291     items = scene.items(QPointF(80, 80));
8292     QCOMPARE(items.size(), 1);
8293     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8294
8295     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8296     QTest::qWait(100);
8297
8298     items = scene.items(QPointF(75, 75));
8299     QVERIFY(items.isEmpty());
8300     items = scene.items(QPointF(80, 80));
8301     QCOMPARE(items.size(), 1);
8302     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8303 }
8304
8305 void tst_QGraphicsItem::focusProxy()
8306 {
8307     QGraphicsScene scene;
8308     QEvent activate(QEvent::WindowActivate);
8309     QApplication::sendEvent(&scene, &activate);
8310
8311     QGraphicsItem *item = scene.addRect(0, 0, 10, 10);
8312     item->setFlag(QGraphicsItem::ItemIsFocusable);
8313     QVERIFY(!item->focusProxy());
8314
8315     QGraphicsItem *item2 = scene.addRect(0, 0, 10, 10);
8316     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8317     item->setFocusProxy(item2);
8318     QCOMPARE(item->focusProxy(), item2);
8319
8320     item->setFocus();
8321     QVERIFY(item->hasFocus());
8322     QVERIFY(item2->hasFocus());
8323
8324     // Try to make a focus chain loop
8325     QString err;
8326     QTextStream stream(&err);
8327     stream << "QGraphicsItem::setFocusProxy: "
8328            << (void*)item << " is already in the focus proxy chain" << flush;
8329     QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
8330     item2->setFocusProxy(item); // fails
8331     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8332     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8333
8334     // Try to assign self as focus proxy
8335     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
8336     item->setFocusProxy(item); // fails
8337     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8338     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8339
8340     // Reset the focus proxy
8341     item->setFocusProxy(0);
8342     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8343     QVERIFY(!item->hasFocus());
8344     QVERIFY(item2->hasFocus());
8345
8346     // Test deletion
8347     item->setFocusProxy(item2);
8348     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8349     delete item2;
8350     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8351
8352     // Test event delivery
8353     item2 = scene.addRect(0, 0, 10, 10);
8354     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8355     item->setFocusProxy(item2);
8356     item->clearFocus();
8357
8358     EventSpy focusInSpy(&scene, item, QEvent::FocusIn);
8359     EventSpy focusOutSpy(&scene, item, QEvent::FocusOut);
8360     EventSpy focusInSpy2(&scene, item2, QEvent::FocusIn);
8361     EventSpy focusOutSpy2(&scene, item2, QEvent::FocusOut);
8362     QCOMPARE(focusInSpy.count(), 0);
8363     QCOMPARE(focusOutSpy.count(), 0);
8364     QCOMPARE(focusInSpy2.count(), 0);
8365     QCOMPARE(focusOutSpy2.count(), 0);
8366
8367     item->setFocus();
8368     QCOMPARE(focusInSpy.count(), 0);
8369     QCOMPARE(focusInSpy2.count(), 1);
8370     item->clearFocus();
8371     QCOMPARE(focusOutSpy.count(), 0);
8372     QCOMPARE(focusOutSpy2.count(), 1);
8373
8374     // Test two items proxying one item.
8375     QGraphicsItem *item3 = scene.addRect(0, 0, 10, 10);
8376     item3->setFlag(QGraphicsItem::ItemIsFocusable);
8377     item3->setFocusProxy(item2); // item and item3 use item2 as proxy
8378
8379     QCOMPARE(item->focusProxy(), item2);
8380     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8381     QCOMPARE(item3->focusProxy(), item2);
8382     delete item2;
8383     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8384     QCOMPARE(item3->focusProxy(), (QGraphicsItem *)0);
8385 }
8386
8387 void tst_QGraphicsItem::subFocus()
8388 {
8389     // Construct a text item that's not part of a scene (yet)
8390     // and has no parent. Setting focus on it will not make
8391     // the item gain input focus; that requires a scene. But
8392     // it does set subfocus, indicating that the item wishes
8393     // to gain focus later.
8394     QGraphicsTextItem *text = new QGraphicsTextItem("Hello");
8395     text->setTextInteractionFlags(Qt::TextEditorInteraction);
8396     QVERIFY(!text->hasFocus());
8397     text->setFocus();
8398     QVERIFY(!text->hasFocus());
8399     QCOMPARE(text->focusItem(), (QGraphicsItem *)text);
8400
8401     // Add a sibling.
8402     QGraphicsTextItem *text2 = new QGraphicsTextItem("Hi");
8403     text2->setTextInteractionFlags(Qt::TextEditorInteraction);
8404     text2->setPos(30, 30);
8405
8406     // Add both items to a scene and check that it's text that
8407     // got input focus.
8408     QGraphicsScene scene;
8409     QEvent activate(QEvent::WindowActivate);
8410     QApplication::sendEvent(&scene, &activate);
8411
8412     scene.addItem(text);
8413     scene.addItem(text2);
8414     QVERIFY(text->hasFocus());
8415
8416     text->setData(0, "text");
8417     text2->setData(0, "text2");
8418
8419     // Remove text2 and set subfocus on it. Then readd. Reparent it onto the
8420     // other item and see that it gains input focus.
8421     scene.removeItem(text2);
8422     text2->setFocus();
8423     scene.addItem(text2);
8424     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8425     text2->setParentItem(text);
8426     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8427     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8428     QVERIFY(!text->hasFocus());
8429     QVERIFY(text2->hasFocus());
8430
8431     // Remove both items from the scene, restore subfocus and
8432     // readd them. Now the subfocus should kick in and give
8433     // text2 focus.
8434     scene.removeItem(text);
8435     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8436     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8437     text2->setFocus();
8438     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8439     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8440     scene.addItem(text);
8441
8442     // Hiding and showing text should pass focus to text2.
8443     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8444     QVERIFY(text2->hasFocus());
8445
8446     // Subfocus should repropagate to root when reparenting.
8447     QGraphicsRectItem *rect = new QGraphicsRectItem;
8448     QGraphicsRectItem *rect2 = new QGraphicsRectItem(rect);
8449     QGraphicsRectItem *rect3 = new QGraphicsRectItem(rect2);
8450     rect3->setFlag(QGraphicsItem::ItemIsFocusable);
8451
8452     text->setData(0, "text");
8453     text2->setData(0, "text2");
8454     rect->setData(0, "rect");
8455     rect2->setData(0, "rect2");
8456     rect3->setData(0, "rect3");
8457
8458     rect3->setFocus();
8459     QVERIFY(!rect3->hasFocus());
8460     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8461     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8462     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8463     rect->setParentItem(text2);
8464     QCOMPARE(text->focusItem(), (QGraphicsItem *)rect3);
8465     QCOMPARE(text2->focusItem(), (QGraphicsItem *)rect3);
8466     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8467     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8468     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8469     QVERIFY(!rect->hasFocus());
8470     QVERIFY(!rect2->hasFocus());
8471     QVERIFY(rect3->hasFocus());
8472
8473     delete rect2;
8474     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8475     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8476     QCOMPARE(rect->focusItem(), (QGraphicsItem *)0);
8477 }
8478
8479 void tst_QGraphicsItem::focusProxyDeletion()
8480 {
8481     QGraphicsRectItem *rect = new QGraphicsRectItem;
8482     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8483     rect->setFocusProxy(rect2);
8484     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8485
8486     delete rect2;
8487     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8488
8489     rect2 = new QGraphicsRectItem;
8490     rect->setFocusProxy(rect2);
8491     delete rect; // don't crash
8492
8493     rect = new QGraphicsRectItem;
8494     rect->setFocusProxy(rect2);
8495     QGraphicsScene *scene = new QGraphicsScene;
8496     scene->addItem(rect);
8497     scene->addItem(rect2);
8498     delete rect2;
8499     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8500
8501     rect2 = new QGraphicsRectItem;
8502     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
8503     rect->setFocusProxy(rect2);
8504     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8505     scene->addItem(rect2);
8506     rect->setFocusProxy(rect2);
8507     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8508     delete rect; // don't crash
8509
8510     rect = new QGraphicsRectItem;
8511     rect2 = new QGraphicsRectItem;
8512     rect->setFocusProxy(rect2);
8513     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8514     scene->addItem(rect);
8515     scene->addItem(rect2);
8516     rect->setFocusProxy(rect2);
8517     delete scene; // don't crash
8518 }
8519
8520 void tst_QGraphicsItem::negativeZStacksBehindParent()
8521 {
8522     QGraphicsRectItem rect;
8523     QCOMPARE(rect.zValue(), qreal(0.0));
8524     QVERIFY(!(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent));
8525     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8526     rect.setZValue(-1);
8527     QCOMPARE(rect.zValue(), qreal(-1.0));
8528     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8529     rect.setZValue(0);
8530     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
8531     QVERIFY(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent);
8532     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8533     rect.setZValue(-1);
8534     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8535     rect.setZValue(0);
8536     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8537     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8538     rect.setZValue(-1);
8539     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, true);
8540     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8541     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8542     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8543 }
8544
8545 void tst_QGraphicsItem::setGraphicsEffect()
8546 {
8547     // Check that we don't have any effect by default.
8548     QGraphicsItem *item = new QGraphicsRectItem(0, 0, 10, 10);
8549     QVERIFY(!item->graphicsEffect());
8550
8551     // SetGet check.
8552     QPointer<QGraphicsEffect> blurEffect = new QGraphicsBlurEffect;
8553     item->setGraphicsEffect(blurEffect);
8554     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(blurEffect));
8555
8556     // Ensure the existing effect is deleted when setting a new one.
8557     QPointer<QGraphicsEffect> shadowEffect = new QGraphicsDropShadowEffect;
8558     item->setGraphicsEffect(shadowEffect);
8559     QVERIFY(!blurEffect);
8560     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(shadowEffect));
8561     blurEffect = new QGraphicsBlurEffect;
8562
8563     // Ensure the effect is uninstalled when setting it on a new target.
8564     QGraphicsItem *anotherItem = new QGraphicsRectItem(0, 0, 10, 10);
8565     anotherItem->setGraphicsEffect(blurEffect);
8566     item->setGraphicsEffect(blurEffect);
8567     QVERIFY(!anotherItem->graphicsEffect());
8568     QVERIFY(!shadowEffect);
8569
8570     // Ensure the existing effect is deleted when deleting the item.
8571     delete item;
8572     QVERIFY(!blurEffect);
8573     delete anotherItem;
8574
8575     // Ensure the effect is uninstalled when deleting it
8576     item = new QGraphicsRectItem(0, 0, 10, 10);
8577     blurEffect = new QGraphicsBlurEffect;
8578     item->setGraphicsEffect(blurEffect);
8579     delete blurEffect;
8580     QVERIFY(!item->graphicsEffect());
8581
8582     // Ensure the existing effect is uninstalled and deleted when setting a null effect
8583     blurEffect = new QGraphicsBlurEffect;
8584     item->setGraphicsEffect(blurEffect);
8585     item->setGraphicsEffect(0);
8586     QVERIFY(!item->graphicsEffect());
8587     QVERIFY(!blurEffect);
8588
8589     delete item;
8590 }
8591
8592 void tst_QGraphicsItem::panel()
8593 {
8594     QGraphicsScene scene;
8595
8596     QGraphicsRectItem *panel1 = new QGraphicsRectItem;
8597     QGraphicsRectItem *panel2 = new QGraphicsRectItem;
8598     QGraphicsRectItem *panel3 = new QGraphicsRectItem;
8599     QGraphicsRectItem *panel4 = new QGraphicsRectItem;
8600     QGraphicsRectItem *notPanel1 = new QGraphicsRectItem;
8601     QGraphicsRectItem *notPanel2 = new QGraphicsRectItem;
8602     panel1->setFlag(QGraphicsItem::ItemIsPanel);
8603     panel2->setFlag(QGraphicsItem::ItemIsPanel);
8604     panel3->setFlag(QGraphicsItem::ItemIsPanel);
8605     panel4->setFlag(QGraphicsItem::ItemIsPanel);
8606     scene.addItem(panel1);
8607     scene.addItem(panel2);
8608     scene.addItem(panel3);
8609     scene.addItem(panel4);
8610     scene.addItem(notPanel1);
8611     scene.addItem(notPanel2);
8612
8613     EventSpy spy_activate_panel1(&scene, panel1, QEvent::WindowActivate);
8614     EventSpy spy_deactivate_panel1(&scene, panel1, QEvent::WindowDeactivate);
8615     EventSpy spy_activate_panel2(&scene, panel2, QEvent::WindowActivate);
8616     EventSpy spy_deactivate_panel2(&scene, panel2, QEvent::WindowDeactivate);
8617     EventSpy spy_activate_panel3(&scene, panel3, QEvent::WindowActivate);
8618     EventSpy spy_deactivate_panel3(&scene, panel3, QEvent::WindowDeactivate);
8619     EventSpy spy_activate_panel4(&scene, panel4, QEvent::WindowActivate);
8620     EventSpy spy_deactivate_panel4(&scene, panel4, QEvent::WindowDeactivate);
8621     EventSpy spy_activate_notPanel1(&scene, notPanel1, QEvent::WindowActivate);
8622     EventSpy spy_deactivate_notPanel1(&scene, notPanel1, QEvent::WindowDeactivate);
8623     EventSpy spy_activate_notPanel2(&scene, notPanel1, QEvent::WindowActivate);
8624     EventSpy spy_deactivate_notPanel2(&scene, notPanel1, QEvent::WindowDeactivate);
8625
8626     QCOMPARE(spy_activate_panel1.count(), 0);
8627     QCOMPARE(spy_deactivate_panel1.count(), 0);
8628     QCOMPARE(spy_activate_panel2.count(), 0);
8629     QCOMPARE(spy_deactivate_panel2.count(), 0);
8630     QCOMPARE(spy_activate_panel3.count(), 0);
8631     QCOMPARE(spy_deactivate_panel3.count(), 0);
8632     QCOMPARE(spy_activate_panel4.count(), 0);
8633     QCOMPARE(spy_deactivate_panel4.count(), 0);
8634     QCOMPARE(spy_activate_notPanel1.count(), 0);
8635     QCOMPARE(spy_deactivate_notPanel1.count(), 0);
8636     QCOMPARE(spy_activate_notPanel2.count(), 0);
8637     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8638
8639     QVERIFY(!scene.activePanel());
8640     QVERIFY(!scene.isActive());
8641
8642     QEvent activate(QEvent::WindowActivate);
8643     QEvent deactivate(QEvent::WindowDeactivate);
8644
8645     QApplication::sendEvent(&scene, &activate);
8646
8647     // No previous activation, so the scene is active.
8648     QVERIFY(scene.isActive());
8649     QCOMPARE(scene.activePanel(), (QGraphicsItem *)panel1);
8650     QVERIFY(panel1->isActive());
8651     QVERIFY(!panel2->isActive());
8652     QVERIFY(!panel3->isActive());
8653     QVERIFY(!panel4->isActive());
8654     QVERIFY(!notPanel1->isActive());
8655     QVERIFY(!notPanel2->isActive());
8656     QCOMPARE(spy_deactivate_notPanel1.count(), 0);
8657     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8658     QCOMPARE(spy_activate_panel1.count(), 1);
8659     QCOMPARE(spy_activate_panel2.count(), 0);
8660     QCOMPARE(spy_activate_panel3.count(), 0);
8661     QCOMPARE(spy_activate_panel4.count(), 0);
8662
8663     // Switch back to scene.
8664     scene.setActivePanel(0);
8665     QVERIFY(!scene.activePanel());
8666     QVERIFY(!panel1->isActive());
8667     QVERIFY(!panel2->isActive());
8668     QVERIFY(!panel3->isActive());
8669     QVERIFY(!panel4->isActive());
8670     QVERIFY(notPanel1->isActive());
8671     QVERIFY(notPanel2->isActive());
8672     QCOMPARE(spy_activate_notPanel1.count(), 1);
8673     QCOMPARE(spy_activate_notPanel2.count(), 1);
8674
8675     // Deactivate the scene
8676     QApplication::sendEvent(&scene, &deactivate);
8677     QVERIFY(!scene.activePanel());
8678     QVERIFY(!panel1->isActive());
8679     QVERIFY(!panel2->isActive());
8680     QVERIFY(!panel3->isActive());
8681     QVERIFY(!panel4->isActive());
8682     QVERIFY(!notPanel1->isActive());
8683     QVERIFY(!notPanel2->isActive());
8684     QCOMPARE(spy_deactivate_notPanel1.count(), 1);
8685     QCOMPARE(spy_deactivate_notPanel2.count(), 1);
8686
8687     // Reactivate the scene
8688     QApplication::sendEvent(&scene, &activate);
8689     QVERIFY(!scene.activePanel());
8690     QVERIFY(!panel1->isActive());
8691     QVERIFY(!panel2->isActive());
8692     QVERIFY(!panel3->isActive());
8693     QVERIFY(!panel4->isActive());
8694     QVERIFY(notPanel1->isActive());
8695     QVERIFY(notPanel2->isActive());
8696     QCOMPARE(spy_activate_notPanel1.count(), 2);
8697     QCOMPARE(spy_activate_notPanel2.count(), 2);
8698
8699     // Switch to panel1
8700     scene.setActivePanel(panel1);
8701     QVERIFY(panel1->isActive());
8702     QCOMPARE(spy_deactivate_notPanel1.count(), 2);
8703     QCOMPARE(spy_deactivate_notPanel2.count(), 2);
8704     QCOMPARE(spy_activate_panel1.count(), 2);
8705
8706     // Deactivate the scene
8707     QApplication::sendEvent(&scene, &deactivate);
8708     QVERIFY(!panel1->isActive());
8709     QCOMPARE(spy_deactivate_panel1.count(), 2);
8710
8711     // Reactivate the scene
8712     QApplication::sendEvent(&scene, &activate);
8713     QVERIFY(panel1->isActive());
8714     QCOMPARE(spy_activate_panel1.count(), 3);
8715
8716     // Deactivate the scene
8717     QApplication::sendEvent(&scene, &deactivate);
8718     QVERIFY(!panel1->isActive());
8719     QVERIFY(!scene.activePanel());
8720     scene.setActivePanel(0);
8721
8722     // Reactivate the scene
8723     QApplication::sendEvent(&scene, &activate);
8724     QVERIFY(!panel1->isActive());
8725 }
8726
8727 void tst_QGraphicsItem::panelWithFocusItem()
8728 {
8729     QGraphicsScene scene;
8730     QEvent activate(QEvent::WindowActivate);
8731     QApplication::sendEvent(&scene, &activate);
8732
8733     QGraphicsRectItem *parentPanel = new QGraphicsRectItem;
8734     QGraphicsRectItem *parentPanelFocusItem = new QGraphicsRectItem(parentPanel);
8735     parentPanel->setFlag(QGraphicsItem::ItemIsPanel);
8736     parentPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8737     parentPanelFocusItem->setFocus();
8738     scene.addItem(parentPanel);
8739
8740     QVERIFY(parentPanel->isActive());
8741     QVERIFY(parentPanelFocusItem->hasFocus());
8742     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8743     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8744
8745     QGraphicsRectItem *childPanel = new QGraphicsRectItem;
8746     QGraphicsRectItem *childPanelFocusItem = new QGraphicsRectItem(childPanel);
8747     childPanel->setFlag(QGraphicsItem::ItemIsPanel);
8748     childPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8749     childPanelFocusItem->setFocus();
8750
8751     QVERIFY(!childPanelFocusItem->hasFocus());
8752     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8753     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8754
8755     childPanel->setParentItem(parentPanel);
8756
8757     QVERIFY(!parentPanel->isActive());
8758     QVERIFY(!parentPanelFocusItem->hasFocus());
8759     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8760     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8761
8762     QVERIFY(childPanel->isActive());
8763     QVERIFY(childPanelFocusItem->hasFocus());
8764     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8765     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8766
8767     childPanel->hide();
8768
8769     QVERIFY(parentPanel->isActive());
8770     QVERIFY(parentPanelFocusItem->hasFocus());
8771     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8772     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8773 }
8774
8775 void tst_QGraphicsItem::addPanelToActiveScene()
8776 {
8777     QGraphicsScene scene;
8778     QVERIFY(!scene.isActive());
8779
8780     QGraphicsRectItem *rect = new QGraphicsRectItem;
8781     scene.addItem(rect);
8782     QVERIFY(!rect->isActive());
8783     scene.removeItem(rect);
8784
8785     QEvent activate(QEvent::WindowActivate);
8786     QEvent deactivate(QEvent::WindowDeactivate);
8787
8788     QApplication::sendEvent(&scene, &activate);
8789     QVERIFY(scene.isActive());
8790     scene.addItem(rect);
8791     QVERIFY(rect->isActive());
8792     scene.removeItem(rect);
8793
8794     rect->setFlag(QGraphicsItem::ItemIsPanel);
8795     scene.addItem(rect);
8796     QVERIFY(rect->isActive());
8797     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8798
8799     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8800     scene.addItem(rect2);
8801     QVERIFY(rect->isActive());
8802     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8803 }
8804
8805 void tst_QGraphicsItem::activate()
8806 {
8807     QGraphicsScene scene;
8808     QGraphicsRectItem *rect = scene.addRect(-10, -10, 20, 20);
8809     QVERIFY(!rect->isActive());
8810
8811     QEvent activate(QEvent::WindowActivate);
8812     QEvent deactivate(QEvent::WindowDeactivate);
8813
8814     QApplication::sendEvent(&scene, &activate);
8815
8816     // Non-panel item (active when scene is active).
8817     QVERIFY(rect->isActive());
8818
8819     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8820     rect2->setFlag(QGraphicsItem::ItemIsPanel);
8821     QGraphicsRectItem *rect3 = new QGraphicsRectItem;
8822     rect3->setFlag(QGraphicsItem::ItemIsPanel);
8823
8824     // Test normal activation.
8825     QVERIFY(!rect2->isActive());
8826     scene.addItem(rect2);
8827     QVERIFY(rect2->isActive()); // first panel item is activated
8828     scene.addItem(rect3);
8829     QVERIFY(!rect3->isActive()); // second panel item is _not_ activated
8830     rect3->setActive(true);
8831     QVERIFY(rect3->isActive());
8832     scene.removeItem(rect3);
8833     QVERIFY(!rect3->isActive()); // no panel is active anymore
8834     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8835     scene.addItem(rect3);
8836     QVERIFY(rect3->isActive()); // second panel item is activated
8837
8838     // Test pending activation.
8839     scene.removeItem(rect3);
8840     rect2->setActive(true);
8841     QVERIFY(rect2->isActive()); // first panel item is activated
8842     rect3->setActive(true);
8843     QVERIFY(!rect3->isActive()); // not active (yet)
8844     scene.addItem(rect3);
8845     QVERIFY(rect3->isActive()); // now becomes active
8846
8847     // Test pending deactivation.
8848     scene.removeItem(rect3);
8849     rect3->setActive(false);
8850     scene.addItem(rect3);
8851     QVERIFY(!rect3->isActive()); // doesn't become active
8852
8853     // Child of panel activation.
8854     rect3->setActive(true);
8855     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
8856     rect4->setFlag(QGraphicsItem::ItemIsPanel);
8857     QGraphicsRectItem *rect5 = new QGraphicsRectItem(rect4);
8858     QGraphicsRectItem *rect6 = new QGraphicsRectItem(rect5);
8859     scene.addItem(rect4);
8860     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect3);
8861     scene.removeItem(rect4);
8862     rect6->setActive(true);
8863     scene.addItem(rect4);
8864     QVERIFY(rect4->isActive());
8865     QVERIFY(rect5->isActive());
8866     QVERIFY(rect6->isActive());
8867     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect4);
8868     scene.removeItem(rect4); // no active panel
8869     rect6->setActive(false);
8870     scene.addItem(rect4);
8871     QVERIFY(!rect4->isActive());
8872     QVERIFY(!rect5->isActive());
8873     QVERIFY(!rect6->isActive());
8874     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8875
8876     // Controlling auto-activation when the scene changes activation.
8877     rect4->setActive(true);
8878     QApplication::sendEvent(&scene, &deactivate);
8879     QVERIFY(!scene.isActive());
8880     QVERIFY(!rect4->isActive());
8881     rect4->setActive(false);
8882     QApplication::sendEvent(&scene, &activate);
8883     QVERIFY(scene.isActive());
8884     QVERIFY(!scene.activePanel());
8885     QVERIFY(!rect4->isActive());
8886 }
8887
8888 void tst_QGraphicsItem::setActivePanelOnInactiveScene()
8889 {
8890     QGraphicsScene scene;
8891     QGraphicsRectItem *item = scene.addRect(QRectF());
8892     QGraphicsRectItem *panel = scene.addRect(QRectF());
8893     panel->setFlag(QGraphicsItem::ItemIsPanel);
8894
8895     EventSpy itemActivateSpy(&scene, item, QEvent::WindowActivate);
8896     EventSpy itemDeactivateSpy(&scene, item, QEvent::WindowDeactivate);
8897     EventSpy panelActivateSpy(&scene, panel, QEvent::WindowActivate);
8898     EventSpy panelDeactivateSpy(&scene, panel, QEvent::WindowDeactivate);
8899     EventSpy sceneActivationChangeSpy(&scene, QEvent::ActivationChange);
8900
8901     scene.setActivePanel(panel);
8902     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8903     QCOMPARE(itemActivateSpy.count(), 0);
8904     QCOMPARE(itemDeactivateSpy.count(), 0);
8905     QCOMPARE(panelActivateSpy.count(), 0);
8906     QCOMPARE(panelDeactivateSpy.count(), 0);
8907     QCOMPARE(sceneActivationChangeSpy.count(), 0);
8908 }
8909
8910 void tst_QGraphicsItem::activationOnShowHide()
8911 {
8912     QGraphicsScene scene;
8913     QEvent activate(QEvent::WindowActivate);
8914     QApplication::sendEvent(&scene, &activate);
8915
8916     QGraphicsRectItem *rootPanel = scene.addRect(QRectF());
8917     rootPanel->setFlag(QGraphicsItem::ItemIsPanel);
8918     rootPanel->setActive(true);
8919
8920     QGraphicsRectItem *subPanel = new QGraphicsRectItem;
8921     subPanel->setFlag(QGraphicsItem::ItemIsPanel);
8922
8923     // Reparenting onto an active panel auto-activates the child panel.
8924     subPanel->setParentItem(rootPanel);
8925     QVERIFY(subPanel->isActive());
8926     QVERIFY(!rootPanel->isActive());
8927
8928     // Hiding an active child panel will reactivate the parent panel.
8929     subPanel->hide();
8930     QVERIFY(rootPanel->isActive());
8931
8932     // Showing a child panel will auto-activate it.
8933     subPanel->show();
8934     QVERIFY(subPanel->isActive());
8935     QVERIFY(!rootPanel->isActive());
8936
8937     // Adding an unrelated panel doesn't affect activation.
8938     QGraphicsRectItem *otherPanel = new QGraphicsRectItem;
8939     otherPanel->setFlag(QGraphicsItem::ItemIsPanel);
8940     scene.addItem(otherPanel);
8941     QVERIFY(subPanel->isActive());
8942
8943     // Showing an unrelated panel doesn't affect activation.
8944     otherPanel->hide();
8945     otherPanel->show();
8946     QVERIFY(subPanel->isActive());
8947
8948     // Add a non-panel item.
8949     QGraphicsRectItem *otherItem = new QGraphicsRectItem;
8950     scene.addItem(otherItem);
8951     otherItem->setActive(true);
8952     QVERIFY(otherItem->isActive());
8953
8954     // Reparent a panel onto an active non-panel item.
8955     subPanel->setParentItem(otherItem);
8956     QVERIFY(subPanel->isActive());
8957
8958     // Showing a child panel of a non-panel item will activate it.
8959     subPanel->hide();
8960     QVERIFY(!subPanel->isActive());
8961     QVERIFY(otherItem->isActive());
8962     subPanel->show();
8963     QVERIFY(subPanel->isActive());
8964
8965     // Hiding a toplevel active panel will pass activation back
8966     // to the non-panel items.
8967     rootPanel->setActive(true);
8968     rootPanel->hide();
8969     QVERIFY(!rootPanel->isActive());
8970     QVERIFY(otherItem->isActive());
8971 }
8972
8973 class MoveWhileDying : public QGraphicsRectItem
8974 {
8975 public:
8976     MoveWhileDying(QGraphicsItem *parent = 0)
8977         : QGraphicsRectItem(parent)
8978     { }
8979     ~MoveWhileDying()
8980     {
8981         foreach (QGraphicsItem *c, childItems()) {
8982             foreach (QGraphicsItem *cc, c->childItems()) {
8983                 cc->moveBy(10, 10);
8984             }
8985             c->moveBy(10, 10);
8986         }
8987         if (QGraphicsItem *p = parentItem()) { p->moveBy(10, 10); }
8988     }
8989 };
8990
8991 void tst_QGraphicsItem::moveWhileDeleting()
8992 {
8993     QGraphicsScene scene;
8994     QGraphicsRectItem *rect = new QGraphicsRectItem;
8995     MoveWhileDying *silly = new MoveWhileDying(rect);
8996     QGraphicsRectItem *child = new QGraphicsRectItem(silly);
8997     scene.addItem(rect);
8998     delete rect; // don't crash!
8999
9000     rect = new QGraphicsRectItem;
9001     silly = new MoveWhileDying(rect);
9002     child = new QGraphicsRectItem(silly);
9003
9004     QGraphicsView view(&scene);
9005     view.show();
9006 #ifdef Q_WS_X11
9007     qt_x11_wait_for_window_manager(&view);
9008 #endif
9009     QTest::qWait(125);
9010
9011     delete rect;
9012
9013     rect = new QGraphicsRectItem;
9014     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
9015     silly = new MoveWhileDying(rect);
9016     child = new QGraphicsRectItem(silly);
9017
9018     QTest::qWait(125);
9019
9020     delete rect;
9021
9022     rect = new MoveWhileDying;
9023     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
9024     child = new QGraphicsRectItem(rect);
9025     silly = new MoveWhileDying(child);
9026
9027     QTest::qWait(125);
9028
9029     delete rect;
9030 }
9031
9032 class MyRectItem : public QGraphicsWidget
9033 {
9034     Q_OBJECT
9035 public:
9036     MyRectItem(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
9037     {
9038
9039     }
9040
9041     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
9042     {
9043         painter->setBrush(brush);
9044         painter->drawRect(boundingRect());
9045     }
9046     void move()
9047     {
9048         setPos(-100,-100);
9049         topLevel->collidingItems(Qt::IntersectsItemBoundingRect);
9050     }
9051 public:
9052     QGraphicsItem *topLevel;
9053     QBrush brush;
9054 };
9055
9056
9057 void tst_QGraphicsItem::ensureDirtySceneTransform()
9058 {
9059     QGraphicsScene scene;
9060
9061     MyRectItem *topLevel = new MyRectItem;
9062     topLevel->setGeometry(0, 0, 100, 100);
9063     topLevel->setPos(-50, -50);
9064     topLevel->brush = QBrush(QColor(Qt::black));
9065     scene.addItem(topLevel);
9066
9067     MyRectItem *parent = new MyRectItem;
9068     parent->topLevel = topLevel;
9069     parent->setGeometry(0, 0, 100, 100);
9070     parent->setPos(0, 0);
9071     parent->brush = QBrush(QColor(Qt::magenta));
9072     parent->setObjectName("parent");
9073     scene.addItem(parent);
9074
9075     MyRectItem *child = new MyRectItem(parent);
9076     child->setGeometry(0, 0, 80, 80);
9077     child->setPos(10, 10);
9078     child->setObjectName("child");
9079     child->brush = QBrush(QColor(Qt::blue));
9080
9081     MyRectItem *child2 = new MyRectItem(parent);
9082     child2->setGeometry(0, 0, 80, 80);
9083     child2->setPos(15, 15);
9084     child2->setObjectName("child2");
9085     child2->brush = QBrush(QColor(Qt::green));
9086
9087     MyRectItem *child3 = new MyRectItem(parent);
9088     child3->setGeometry(0, 0, 80, 80);
9089     child3->setPos(20, 20);
9090     child3->setObjectName("child3");
9091     child3->brush = QBrush(QColor(Qt::gray));
9092
9093     QGraphicsView view(&scene);
9094     view.show();
9095     QTest::qWaitForWindowShown(&view);
9096     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
9097
9098     //We move the parent
9099     parent->move();
9100     QApplication::processEvents();
9101
9102     //We check if all items moved
9103     QCOMPARE(child->pos(), QPointF(10, 10));
9104     QCOMPARE(child2->pos(), QPointF(15, 15));
9105     QCOMPARE(child3->pos(), QPointF(20, 20));
9106
9107     QCOMPARE(child->sceneBoundingRect(), QRectF(-90, -90, 80, 80));
9108     QCOMPARE(child2->sceneBoundingRect(), QRectF(-85, -85, 80, 80));
9109     QCOMPARE(child3->sceneBoundingRect(), QRectF(-80, -80, 80, 80));
9110
9111     QCOMPARE(child->sceneTransform(), QTransform::fromTranslate(-90, -90));
9112     QCOMPARE(child2->sceneTransform(), QTransform::fromTranslate(-85, -85));
9113     QCOMPARE(child3->sceneTransform(), QTransform::fromTranslate(-80, -80));
9114 }
9115
9116 void tst_QGraphicsItem::focusScope()
9117 {
9118     // ItemIsFocusScope is an internal feature (for now).
9119     QGraphicsScene scene;
9120
9121     QGraphicsRectItem *scope3 = new QGraphicsRectItem;
9122     scope3->setData(0, "scope3");
9123     scope3->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9124     scope3->setFocus();
9125     QVERIFY(!scope3->focusScopeItem());
9126     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9127
9128     QGraphicsRectItem *scope2 = new QGraphicsRectItem;
9129     scope2->setData(0, "scope2");
9130     scope2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9131     scope2->setFocus();
9132     QVERIFY(!scope2->focusScopeItem());
9133     scope3->setParentItem(scope2);
9134     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9135     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9136
9137     QGraphicsRectItem *scope1 = new QGraphicsRectItem;
9138     scope1->setData(0, "scope1");
9139     scope1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9140     scope1->setFocus();
9141     QVERIFY(!scope1->focusScopeItem());
9142     scope2->setParentItem(scope1);
9143
9144     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9145     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9146     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9147     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9148     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9149     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9150
9151     scene.addItem(scope1);
9152
9153     QEvent windowActivate(QEvent::WindowActivate);
9154     qApp->sendEvent(&scene, &windowActivate);
9155     scene.setFocus();
9156
9157     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9158     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9159     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9160     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9161     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9162     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9163
9164     QVERIFY(scope3->hasFocus());
9165
9166     scope3->hide();
9167     QVERIFY(scope2->hasFocus());
9168     scope2->hide();
9169     QVERIFY(scope1->hasFocus());
9170     scope2->show();
9171     QVERIFY(scope2->hasFocus());
9172     scope3->show();
9173     QVERIFY(scope3->hasFocus());
9174     scope1->hide();
9175     QVERIFY(!scope3->hasFocus());
9176     scope1->show();
9177     QVERIFY(scope3->hasFocus());
9178     scope3->clearFocus();
9179     QVERIFY(scope2->hasFocus());
9180     scope2->clearFocus();
9181     QVERIFY(scope1->hasFocus());
9182     scope2->hide();
9183     scope2->show();
9184     QVERIFY(!scope2->hasFocus());
9185     QVERIFY(scope1->hasFocus());
9186     scope2->setFocus();
9187     QVERIFY(scope2->hasFocus());
9188     scope3->setFocus();
9189     QVERIFY(scope3->hasFocus());
9190
9191     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
9192     rect4->setData(0, "rect4");
9193     rect4->setParentItem(scope3);
9194
9195     QGraphicsRectItem *rect5 = new QGraphicsRectItem;
9196     rect5->setData(0, "rect5");
9197     rect5->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9198     rect5->setFocus();
9199     rect5->setParentItem(rect4);
9200     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)rect5);
9201     QVERIFY(rect5->hasFocus());
9202
9203     rect4->setParentItem(0);
9204     QVERIFY(rect5->hasFocus());
9205     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9206     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)0);
9207     QVERIFY(!scope3->hasFocus());
9208
9209     QGraphicsRectItem *rectA = new QGraphicsRectItem;
9210     QGraphicsRectItem *scopeA = new QGraphicsRectItem(rectA);
9211     scopeA->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9212     scopeA->setFocus();
9213     QGraphicsRectItem *scopeB = new QGraphicsRectItem(scopeA);
9214     scopeB->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9215     scopeB->setFocus();
9216
9217     scene.addItem(rectA);
9218     QVERIFY(rect5->hasFocus());
9219     QVERIFY(!scopeB->hasFocus());
9220
9221     scopeA->setFocus();
9222     QVERIFY(scopeB->hasFocus());
9223     QCOMPARE(scopeB->focusItem(), (QGraphicsItem *)scopeB);
9224 }
9225
9226 void tst_QGraphicsItem::focusScope2()
9227 {
9228     QGraphicsRectItem *child1 = new QGraphicsRectItem;
9229     child1->setFlags(QGraphicsItem::ItemIsFocusable);
9230     child1->setFocus();
9231     QCOMPARE(child1->focusItem(), (QGraphicsItem *)child1);
9232
9233     QGraphicsRectItem *child2 = new QGraphicsRectItem;
9234     child2->setFlags(QGraphicsItem::ItemIsFocusable);
9235
9236     QGraphicsRectItem *rootFocusScope = new QGraphicsRectItem;
9237     rootFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9238     rootFocusScope->setFocus();
9239     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)rootFocusScope);
9240
9241     child1->setParentItem(rootFocusScope);
9242     child2->setParentItem(rootFocusScope);
9243
9244     QCOMPARE(rootFocusScope->focusScopeItem(), (QGraphicsItem *)child1);
9245     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)child1);
9246
9247     QGraphicsRectItem *siblingChild1 = new QGraphicsRectItem;
9248     siblingChild1->setFlags(QGraphicsItem::ItemIsFocusable);
9249     siblingChild1->setFocus();
9250
9251     QGraphicsRectItem *siblingChild2 = new QGraphicsRectItem;
9252     siblingChild2->setFlags(QGraphicsItem::ItemIsFocusable);
9253
9254     QGraphicsRectItem *siblingFocusScope = new QGraphicsRectItem;
9255     siblingFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9256
9257     siblingChild1->setParentItem(siblingFocusScope);
9258     siblingChild2->setParentItem(siblingFocusScope);
9259
9260     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild1);
9261     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9262
9263     QGraphicsItem *root = new QGraphicsRectItem;
9264     rootFocusScope->setParentItem(root);
9265     siblingFocusScope->setParentItem(root);
9266
9267     QCOMPARE(root->focusItem(), (QGraphicsItem *)child1);
9268
9269     QGraphicsScene scene;
9270     scene.addItem(root);
9271
9272     QEvent activate(QEvent::WindowActivate);
9273     qApp->sendEvent(&scene, &activate);
9274     scene.setFocus();
9275
9276     QCOMPARE(scene.focusItem(), (QGraphicsItem *)child1);
9277
9278     // You cannot set focus on a descendant of a focus scope directly;
9279     // this will only change the scope's focus scope item pointer. If
9280     // you want to give true input focus, you must set it directly on
9281     // the scope itself
9282     siblingChild2->setFocus();
9283     QVERIFY(!siblingChild2->hasFocus());
9284     QVERIFY(!siblingChild2->focusItem());
9285     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9286     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9287
9288     // Set focus on the scope; focus is forwarded to the focus scope item.
9289     siblingFocusScope->setFocus();
9290     QVERIFY(siblingChild2->hasFocus());
9291     QVERIFY(siblingChild2->focusItem());
9292     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9293     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)siblingChild2);
9294 }
9295
9296 void tst_QGraphicsItem::stackBefore()
9297 {
9298     QGraphicsRectItem parent;
9299     QGraphicsRectItem *child1 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9300     QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9301     QGraphicsRectItem *child3 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9302     QGraphicsRectItem *child4 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9303     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9304     child1->setData(0, "child1");
9305     child2->setData(0, "child2");
9306     child3->setData(0, "child3");
9307     child4->setData(0, "child4");
9308
9309     // Remove and append
9310     child2->setParentItem(0);
9311     child2->setParentItem(&parent);
9312     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9313
9314     // Move child2 before child1
9315     child2->stackBefore(child1); // 2134
9316     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9317     child2->stackBefore(child2); // 2134
9318     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9319     child1->setZValue(1); // 2341
9320     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9321     child1->stackBefore(child2); // 2341
9322     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9323     child1->setZValue(0); // 1234
9324     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9325     child4->stackBefore(child1); // 4123
9326     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9327     child4->setZValue(1); // 1234 (4123)
9328     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9329     child3->stackBefore(child1); // 3124 (4312)
9330     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9331     child4->setZValue(0); // 4312
9332     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9333
9334     // Make them all toplevels
9335     child1->setParentItem(0);
9336     child2->setParentItem(0);
9337     child3->setParentItem(0);
9338     child4->setParentItem(0);
9339
9340     QGraphicsScene scene;
9341     scene.addItem(child1);
9342     scene.addItem(child2);
9343     scene.addItem(child3);
9344     scene.addItem(child4);
9345     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder),
9346              (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9347
9348     // Remove and append
9349     scene.removeItem(child2);
9350     scene.addItem(child2);
9351     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9352
9353     // Move child2 before child1
9354     child2->stackBefore(child1); // 2134
9355     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9356     child2->stackBefore(child2); // 2134
9357     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9358     child1->setZValue(1); // 2341
9359     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9360     child1->stackBefore(child2); // 2341
9361     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9362     child1->setZValue(0); // 1234
9363     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9364     child4->stackBefore(child1); // 4123
9365     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9366     child4->setZValue(1); // 1234 (4123)
9367     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9368     child3->stackBefore(child1); // 3124 (4312)
9369     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9370     child4->setZValue(0); // 4312
9371     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9372 }
9373
9374 void tst_QGraphicsItem::QTBUG_4233_updateCachedWithSceneRect()
9375 {
9376     EventTester *tester = new EventTester;
9377     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
9378
9379     QGraphicsScene scene;
9380     scene.addItem(tester);
9381     scene.setSceneRect(-100, -100, 200, 200); // contains the tester item
9382
9383     QGraphicsView view(&scene);
9384     view.show();
9385     QTest::qWaitForWindowShown(&view);
9386     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
9387
9388     QTRY_COMPARE(tester->repaints, 1);
9389
9390     scene.update(); // triggers "updateAll" optimization
9391     qApp->processEvents();
9392     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9393
9394     QCOMPARE(tester->repaints, 1);
9395
9396     scene.update(); // triggers "updateAll" optimization
9397     tester->update();
9398     qApp->processEvents();
9399     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9400
9401     QCOMPARE(tester->repaints, 2);
9402 }
9403
9404 void tst_QGraphicsItem::sceneModality()
9405 {
9406     // 1) Test mouse events (delivery/propagation/redirection)
9407     // 2) Test hover events (incl. leave on block, enter on unblock)
9408     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9409     // 4) Test clickfocus
9410     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9411     // 6) ### modality for non-panels is unsupported for now
9412     QGraphicsScene scene;
9413
9414     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9415     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9416     bottomItem->setBrush(Qt::yellow);
9417
9418     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9419     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9420     leftParent->setBrush(Qt::blue);
9421
9422     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9423     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9424     leftChild->setBrush(Qt::green);
9425     leftChild->setParentItem(leftParent);
9426
9427     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9428     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9429     rightParent->setBrush(Qt::red);
9430     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9431     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9432     rightChild->setBrush(Qt::gray);
9433     rightChild->setParentItem(rightParent);
9434
9435     leftParent->setPos(-75, 0);
9436     rightParent->setPos(75, 0);
9437
9438     bottomItem->setData(0, "bottomItem");
9439     leftParent->setData(0, "leftParent");
9440     leftChild->setData(0, "leftChild");
9441     rightParent->setData(0, "rightParent");
9442     rightChild->setData(0, "rightChild");
9443
9444     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9445
9446     EventSpy2 leftParentSpy(&scene, leftParent);
9447     EventSpy2 leftChildSpy(&scene, leftChild);
9448     EventSpy2 rightParentSpy(&scene, rightParent);
9449     EventSpy2 rightChildSpy(&scene, rightChild);
9450     EventSpy2 bottomItemSpy(&scene, bottomItem);
9451
9452     // Scene modality, also test multiple scene modal items
9453     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9454     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9455     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9456     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9457     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9458     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // not a panel
9459
9460     // Click inside left child
9461     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9462     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9463     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9464     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9465     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9466     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9467     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9468
9469     // Click on left parent, event goes to modal child
9470     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9471     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9472     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9473     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9474     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9475     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9476     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9477
9478     // Click on all other items and outside the items
9479     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9480     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9481     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9482     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9483     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9484     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9485     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9486     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9487     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9488     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9489     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9490     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9491     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9492
9493     leftChildSpy.counts.clear();
9494     rightChildSpy.counts.clear();
9495     leftParentSpy.counts.clear();
9496     rightParentSpy.counts.clear();
9497     bottomItemSpy.counts.clear();
9498
9499     leftChild->setPanelModality(QGraphicsItem::NonModal);
9500     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9501     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9502     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9503     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 1);
9504     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9505
9506     // Left parent enters scene modality.
9507     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9508     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9509     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9510     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9511     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9512     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9513
9514     // Click inside left child.
9515     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9516     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9517     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9518     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // panel stops propagation
9519     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9520     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9521     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9522
9523    // Click on left parent.
9524     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9525     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9526     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9527     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9528     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9529     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9530     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9531
9532     // Click on all other items and outside the items
9533     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9534     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9535     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9536     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9537     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9538     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9539     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9540     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9541     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9542     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9543     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9544     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9545     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9546
9547     leftChildSpy.counts.clear();
9548     rightChildSpy.counts.clear();
9549     leftParentSpy.counts.clear();
9550     rightParentSpy.counts.clear();
9551     bottomItemSpy.counts.clear();
9552
9553     // Now both left parent and child are scene modal. Left parent is blocked.
9554     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9555     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9556     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9557     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9558     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9559     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9560
9561     // Click inside left child
9562     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9563     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9564     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9565     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9566     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9567     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9568     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9569
9570     // Click on left parent, event goes to modal child
9571     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9572     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9573     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9574     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9575     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9576     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9577     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9578
9579     // Click on all other items and outside the items
9580     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9581     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9582     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9583     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9584     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9585     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9586     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9587     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9588     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9589     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9590     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9591     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9592     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9593
9594     leftChildSpy.counts.clear();
9595     rightChildSpy.counts.clear();
9596     leftParentSpy.counts.clear();
9597     rightParentSpy.counts.clear();
9598     bottomItemSpy.counts.clear();
9599
9600     // Right child enters scene modality, only left child is blocked.
9601     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9602     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9603     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9604     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9605     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9606     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9607 }
9608
9609 void tst_QGraphicsItem::panelModality()
9610 {
9611     // 1) Test mouse events (delivery/propagation/redirection)
9612     // 2) Test hover events (incl. leave on block, enter on unblock)
9613     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9614     // 4) Test clickfocus
9615     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9616     // 6) ### modality for non-panels is unsupported for now
9617     QGraphicsScene scene;
9618
9619     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9620     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9621     bottomItem->setBrush(Qt::yellow);
9622
9623     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9624     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9625     leftParent->setBrush(Qt::blue);
9626
9627     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9628     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9629     leftChild->setBrush(Qt::green);
9630     leftChild->setParentItem(leftParent);
9631
9632     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9633     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9634     rightParent->setBrush(Qt::red);
9635     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9636     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9637     rightChild->setBrush(Qt::gray);
9638     rightChild->setParentItem(rightParent);
9639
9640     leftParent->setPos(-75, 0);
9641     rightParent->setPos(75, 0);
9642
9643     bottomItem->setData(0, "bottomItem");
9644     leftParent->setData(0, "leftParent");
9645     leftChild->setData(0, "leftChild");
9646     rightParent->setData(0, "rightParent");
9647     rightChild->setData(0, "rightChild");
9648
9649     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9650
9651     EventSpy2 leftParentSpy(&scene, leftParent);
9652     EventSpy2 leftChildSpy(&scene, leftChild);
9653     EventSpy2 rightParentSpy(&scene, rightParent);
9654     EventSpy2 rightChildSpy(&scene, rightChild);
9655     EventSpy2 bottomItemSpy(&scene, bottomItem);
9656
9657     // Left Child enters panel modality, only left parent is blocked.
9658     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9659     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9660     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9661     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9662     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9663     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9664
9665     leftChild->setPanelModality(QGraphicsItem::NonModal);
9666     leftChildSpy.counts.clear();
9667     rightChildSpy.counts.clear();
9668     leftParentSpy.counts.clear();
9669     rightParentSpy.counts.clear();
9670     bottomItemSpy.counts.clear();
9671
9672     // Left parent enter panel modality, nothing is blocked.
9673     leftParent->setPanelModality(QGraphicsItem::PanelModal);
9674     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9675     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9676     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9677     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9678     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9679
9680     // Left child enters panel modality, left parent is blocked again.
9681     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9682     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9683     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9684     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9685     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9686     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9687
9688     leftChildSpy.counts.clear();
9689     rightChildSpy.counts.clear();
9690     leftParentSpy.counts.clear();
9691     rightParentSpy.counts.clear();
9692     bottomItemSpy.counts.clear();
9693
9694     leftChild->setPanelModality(QGraphicsItem::NonModal);
9695     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9696     leftParent->setPanelModality(QGraphicsItem::NonModal);
9697     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9698     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9699     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9700     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9701     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9702
9703     leftChildSpy.counts.clear();
9704     rightChildSpy.counts.clear();
9705     leftParentSpy.counts.clear();
9706     rightParentSpy.counts.clear();
9707     bottomItemSpy.counts.clear();
9708
9709     // Left and right child enter panel modality, both parents are blocked.
9710     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9711     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9712     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9713     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9714     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9715     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9716 }
9717
9718 void tst_QGraphicsItem::mixedModality()
9719 {
9720     // 1) Test mouse events (delivery/propagation/redirection)
9721     // 2) Test hover events (incl. leave on block, enter on unblock)
9722     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9723     // 4) Test clickfocus
9724     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9725     // 6) ### modality for non-panels is unsupported for now
9726     QGraphicsScene scene;
9727
9728     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9729     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9730     bottomItem->setBrush(Qt::yellow);
9731
9732     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9733     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9734     leftParent->setBrush(Qt::blue);
9735
9736     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9737     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9738     leftChild->setBrush(Qt::green);
9739     leftChild->setParentItem(leftParent);
9740
9741     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9742     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9743     rightParent->setBrush(Qt::red);
9744     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9745     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9746     rightChild->setBrush(Qt::gray);
9747     rightChild->setParentItem(rightParent);
9748
9749     leftParent->setPos(-75, 0);
9750     rightParent->setPos(75, 0);
9751
9752     bottomItem->setData(0, "bottomItem");
9753     leftParent->setData(0, "leftParent");
9754     leftChild->setData(0, "leftChild");
9755     rightParent->setData(0, "rightParent");
9756     rightChild->setData(0, "rightChild");
9757
9758     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9759
9760     EventSpy2 leftParentSpy(&scene, leftParent);
9761     EventSpy2 leftChildSpy(&scene, leftChild);
9762     EventSpy2 rightParentSpy(&scene, rightParent);
9763     EventSpy2 rightChildSpy(&scene, rightChild);
9764     EventSpy2 bottomItemSpy(&scene, bottomItem);
9765
9766     // Left Child enters panel modality, only left parent is blocked.
9767     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9768     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9769     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9770     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9771     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9772
9773     // Left parent enters scene modality, which blocks everything except the child.
9774     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9775     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9776     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9777     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9778     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9779     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9780     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9781     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9782     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9783
9784     // Right child enters panel modality (changes nothing).
9785     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9786     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9787     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9788     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9789     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9790     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9791     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9792     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9793     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9794
9795     // Left parent leaves modality. Right child is unblocked.
9796     leftParent->setPanelModality(QGraphicsItem::NonModal);
9797     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9798     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9799     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9800     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9801     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9802     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9803     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9804     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9805
9806     // Right child "upgrades" its modality to scene modal. Left child is blocked.
9807     // Right parent is unaffected.
9808     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9809     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9810     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9811     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9812     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9813     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9814     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9815     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9816     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9817
9818     // "downgrade" right child back to panel modal, left child is unblocked
9819     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9820     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9821     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 1);
9822     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9823     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9824     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9825     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9826     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9827     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9828 }
9829
9830 void tst_QGraphicsItem::modality_hover()
9831 {
9832     QGraphicsScene scene;
9833     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9834     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9835     rect1->setAcceptHoverEvents(true);
9836     rect1->setData(0, "rect1");
9837
9838     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9839     rect2->setParentItem(rect1);
9840     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9841     rect2->setAcceptHoverEvents(true);
9842     rect2->setPos(50, 50);
9843     rect2->setPanelModality(QGraphicsItem::SceneModal);
9844     rect2->setData(0, "rect2");
9845
9846     EventSpy2 rect1Spy(&scene, rect1);
9847     EventSpy2 rect2Spy(&scene, rect2);
9848
9849     sendMouseMove(&scene, QPointF(-25, -25));
9850
9851     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9852     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9853     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9854
9855     sendMouseMove(&scene, QPointF(75, 75));
9856
9857     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9858     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9859     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9860     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9861     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9862     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9863
9864     sendMouseMove(&scene, QPointF(-25, -25));
9865
9866     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9867     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9868     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9869     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9870
9871     rect2->setPanelModality(QGraphicsItem::NonModal);
9872
9873     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9874     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9875
9876     sendMouseMove(&scene, QPointF(75, 75));
9877
9878     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9879     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9880
9881     rect2->setPanelModality(QGraphicsItem::SceneModal);
9882
9883     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9884     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9885     // changing modality causes a spurious GraphicsSceneHoveMove, even though the mouse didn't
9886     // actually move
9887     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9888
9889     sendMouseMove(&scene, QPointF(-25, -25));
9890
9891     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9892     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9893     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9894     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9895
9896     rect2->setPanelModality(QGraphicsItem::PanelModal);
9897
9898     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9899     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9900     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9901     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9902     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9903     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9904
9905     rect2->setPanelModality(QGraphicsItem::NonModal);
9906
9907     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9908     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9909     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9910     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9911     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9912 }
9913
9914 void tst_QGraphicsItem::modality_mouseGrabber()
9915 {
9916     QGraphicsScene scene;
9917     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9918     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9919     rect1->setFlag(QGraphicsItem::ItemIsMovable);
9920     rect1->setData(0, "rect1");
9921
9922     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9923     rect2->setParentItem(rect1);
9924     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9925     rect2->setFlag(QGraphicsItem::ItemIsMovable);
9926     rect2->setPos(50, 50);
9927     rect2->setData(0, "rect2");
9928
9929     EventSpy2 rect1Spy(&scene, rect1);
9930     EventSpy2 rect2Spy(&scene, rect2);
9931
9932     {
9933         // pressing mouse on rect1 starts implicit grab
9934         sendMousePress(&scene, QPoint(-25, -25));
9935         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9936         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9937         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
9938         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9939         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9940         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9941
9942         // grab lost when rect1 is modally shadowed
9943         rect2->setPanelModality(QGraphicsItem::SceneModal);
9944         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9945         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9946         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9947         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9948         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9949
9950         // releasing goes nowhere
9951         sendMouseRelease(&scene, QPoint(-25, -25));
9952         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9953         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9954         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9955         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9956         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9957         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9958         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9959
9960         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
9961         sendMouseClick(&scene, QPoint(-25, -25));
9962         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9963         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9964         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9965         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9966         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9967         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9968         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
9969         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9970
9971         rect2->setPanelModality(QGraphicsItem::NonModal);
9972
9973         // pressing mouse on rect1 starts implicit grab
9974         sendMousePress(&scene, QPoint(-25, -25));
9975         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9976         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
9977         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9978         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9979         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9980         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9981
9982         // grab lost to rect2 when rect1 is modally shadowed
9983         rect2->setPanelModality(QGraphicsItem::SceneModal);
9984         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9985         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9986         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9987         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9988         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9989
9990         // rect1 does *not* re-grab when rect2 is no longer modal
9991         rect2->setPanelModality(QGraphicsItem::NonModal);
9992         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9993         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9994         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9995         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9996         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9997
9998         // release goes nowhere
9999         sendMouseRelease(&scene, QPoint(-25, -25));
10000         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10001         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10002         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10003         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10004         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10005         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10006     }
10007     {
10008         // repeat the test using PanelModal
10009         rect2->setPanelModality(QGraphicsItem::NonModal);
10010         rect1Spy.counts.clear();
10011         rect2Spy.counts.clear();
10012
10013         // pressing mouse on rect1 starts implicit grab
10014         sendMousePress(&scene, QPoint(-25, -25));
10015         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10016         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10017         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10018         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10019         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10020         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10021
10022         // grab lost when rect1 is modally shadowed
10023         rect2->setPanelModality(QGraphicsItem::PanelModal);
10024         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10025         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10026         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10027         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10028         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10029
10030         // releasing goes nowhere
10031         sendMouseRelease(&scene, QPoint(-25, -25));
10032         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10033         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10034         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10035         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10036         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10037         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10038         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10039
10040         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
10041         sendMouseClick(&scene, QPoint(-25, -25));
10042         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10043         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10044         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10045         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10046         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10047         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10048         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10049         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10050
10051         rect2->setPanelModality(QGraphicsItem::NonModal);
10052
10053         // pressing mouse on rect1 starts implicit grab
10054         sendMousePress(&scene, QPoint(-25, -25));
10055         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10056         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
10057         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10058         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10059         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10060         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10061
10062         // grab lost to rect2 when rect1 is modally shadowed
10063         rect2->setPanelModality(QGraphicsItem::PanelModal);
10064         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10065         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10066         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10067         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10068         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10069
10070         // rect1 does *not* re-grab when rect2 is no longer modal
10071         rect2->setPanelModality(QGraphicsItem::NonModal);
10072         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10073         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10074         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10075         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10076         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10077
10078         // release goes nowhere
10079         sendMouseRelease(&scene, QPoint(-25, -25));
10080         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10081         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10082         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10083         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10084         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10085         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10086     }
10087
10088     {
10089         // repeat the PanelModal tests, but this time the mouse events will be on a non-modal item,
10090         // meaning normal grabbing should work
10091         rect2->setPanelModality(QGraphicsItem::NonModal);
10092         rect1Spy.counts.clear();
10093         rect2Spy.counts.clear();
10094
10095         QGraphicsRectItem *rect3 = scene.addRect(-50, -50, 100, 100);
10096         rect3->setFlag(QGraphicsItem::ItemIsPanel);
10097         rect3->setFlag(QGraphicsItem::ItemIsMovable);
10098         rect3->setPos(150, 50);
10099         rect3->setData(0, "rect3");
10100
10101         EventSpy2 rect3Spy(&scene, rect3);
10102
10103         // pressing mouse on rect3 starts implicit grab
10104         sendMousePress(&scene, QPoint(150, 50));
10105         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10106         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10107         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10108         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10109         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10110         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10111         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10112         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10113
10114         // grab is *not* lost when rect1 is modally shadowed by rect2
10115         rect2->setPanelModality(QGraphicsItem::PanelModal);
10116         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10117         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10118         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10119         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10120         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10121         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10122         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10123
10124         // releasing goes to rect3
10125         sendMouseRelease(&scene, QPoint(150, 50));
10126         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10127         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10128         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10129         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10130         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10131         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10132         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10133         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10134
10135         rect2->setPanelModality(QGraphicsItem::NonModal);
10136
10137         // pressing mouse on rect3 starts implicit grab
10138         sendMousePress(&scene, QPoint(150, 50));
10139         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10140         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10141         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10142         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10143         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10144         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10145         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10146
10147         // grab is not lost
10148         rect2->setPanelModality(QGraphicsItem::PanelModal);
10149         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10150         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10151         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10152         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10153         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10154         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10155         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10156
10157         // grab stays on rect3
10158         rect2->setPanelModality(QGraphicsItem::NonModal);
10159         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10160         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10161         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10162         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10163         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10164         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10165         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10166
10167         // release goes to rect3
10168         sendMouseRelease(&scene, QPoint(150, 50));
10169         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10170         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10171         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10172         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10173         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10174         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 2);
10175         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10176     }
10177 }
10178
10179 void tst_QGraphicsItem::modality_clickFocus()
10180 {
10181     QGraphicsScene scene;
10182     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10183     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10184     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10185     rect1->setData(0, "rect1");
10186
10187     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10188     rect2->setParentItem(rect1);
10189     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10190     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10191     rect2->setPos(50, 50);
10192     rect2->setData(0, "rect2");
10193
10194     QEvent windowActivateEvent(QEvent::WindowActivate);
10195     QApplication::sendEvent(&scene, &windowActivateEvent);
10196
10197     EventSpy2 rect1Spy(&scene, rect1);
10198     EventSpy2 rect2Spy(&scene, rect2);
10199
10200     // activate rect1, it should not get focus
10201     rect1->setActive(true);
10202     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10203
10204     // focus stays unset when rect2 becomes modal
10205     rect2->setPanelModality(QGraphicsItem::SceneModal);
10206     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10207     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10208     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10209     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10210     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10211
10212     // clicking on rect1 should not set it's focus item
10213     sendMouseClick(&scene, QPointF(-25, -25));
10214     QCOMPARE(rect1->focusItem(), (QGraphicsItem *) 0);
10215     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10216     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10217     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10218     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10219
10220     // clicking on rect2 gives it focus
10221     rect2->setActive(true);
10222     sendMouseClick(&scene, QPointF(75, 75));
10223     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect2);
10224     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10225     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10226     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10227     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10228
10229     // clicking on rect1 does *not* give it focus
10230     rect1->setActive(true);
10231     sendMouseClick(&scene, QPointF(-25, -25));
10232     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10233     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10234     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10235     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10236     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10237
10238     // focus doesn't change when leaving modality either
10239     rect2->setPanelModality(QGraphicsItem::NonModal);
10240     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10241     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10242     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10243     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10244     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10245
10246     // click on rect1, it should get focus now
10247     sendMouseClick(&scene, QPointF(-25, -25));
10248     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1);
10249     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 1);
10250     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10251     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10252     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10253 }
10254
10255 void tst_QGraphicsItem::modality_keyEvents()
10256 {
10257     QGraphicsScene scene;
10258     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10259     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10260     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10261     rect1->setData(0, "rect1");
10262
10263     QGraphicsRectItem *rect1child = scene.addRect(-10, -10, 20, 20);
10264     rect1child->setParentItem(rect1);
10265     rect1child->setFlag(QGraphicsItem::ItemIsFocusable);
10266     rect1child->setData(0, "rect1child1");
10267
10268     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10269     rect2->setParentItem(rect1);
10270     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10271     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10272     rect2->setPos(50, 50);
10273     rect2->setData(0, "rect2");
10274
10275     QGraphicsRectItem *rect2child = scene.addRect(-10, -10, 20, 20);
10276     rect2child->setParentItem(rect2);
10277     rect2child->setFlag(QGraphicsItem::ItemIsFocusable);
10278     rect2child->setData(0, "rect2child1");
10279
10280     QEvent windowActivateEvent(QEvent::WindowActivate);
10281     QApplication::sendEvent(&scene, &windowActivateEvent);
10282
10283     EventSpy2 rect1Spy(&scene, rect1);
10284     EventSpy2 rect1childSpy(&scene, rect1child);
10285     EventSpy2 rect2Spy(&scene, rect2);
10286     EventSpy2 rect2childSpy(&scene, rect2child);
10287
10288     // activate rect1 and give it rect1child focus
10289     rect1->setActive(true);
10290     rect1child->setFocus();
10291     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10292
10293     // focus stays on rect1child when rect2 becomes modal
10294     rect2->setPanelModality(QGraphicsItem::SceneModal);
10295     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10296
10297     // but key events to rect1child should be neither delivered nor propagated
10298     sendKeyClick(&scene, Qt::Key_A);
10299     sendKeyClick(&scene, Qt::Key_S);
10300     sendKeyClick(&scene, Qt::Key_D);
10301     sendKeyClick(&scene, Qt::Key_F);
10302     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10303     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10304     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10305     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10306
10307     // change to panel modality, rect1child1 keeps focus
10308     rect2->setPanelModality(QGraphicsItem::PanelModal);
10309     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10310
10311     // still no key events
10312     sendKeyClick(&scene, Qt::Key_J);
10313     sendKeyClick(&scene, Qt::Key_K);
10314     sendKeyClick(&scene, Qt::Key_L);
10315     sendKeyClick(&scene, Qt::Key_Semicolon);
10316     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10317     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10318     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10319     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10320 }
10321
10322 void tst_QGraphicsItem::itemIsInFront()
10323 {
10324     QGraphicsScene scene;
10325     QGraphicsRectItem *rect1 = new QGraphicsRectItem;
10326     rect1->setData(0, "rect1");
10327     scene.addItem(rect1);
10328
10329     QGraphicsRectItem *rect1child1 = new QGraphicsRectItem(rect1);
10330     rect1child1->setZValue(1);
10331     rect1child1->setData(0, "rect1child1");
10332
10333     QGraphicsRectItem *rect1child2 = new QGraphicsRectItem(rect1);
10334     rect1child2->setParentItem(rect1);
10335     rect1child2->setData(0, "rect1child2");
10336
10337     QGraphicsRectItem *rect1child1_1 = new QGraphicsRectItem(rect1child1);
10338     rect1child1_1->setData(0, "rect1child1_1");
10339
10340     QGraphicsRectItem *rect1child1_2 = new QGraphicsRectItem(rect1child1);
10341     rect1child1_2->setFlag(QGraphicsItem::ItemStacksBehindParent);
10342     rect1child1_2->setData(0, "rect1child1_2");
10343
10344     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
10345     rect2->setData(0, "rect2");
10346     scene.addItem(rect2);
10347
10348     QGraphicsRectItem *rect2child1 = new QGraphicsRectItem(rect2);
10349     rect2child1->setData(0, "rect2child1");
10350
10351     QCOMPARE(qt_closestItemFirst(rect1, rect1), false);
10352     QCOMPARE(qt_closestItemFirst(rect1, rect2), false);
10353     QCOMPARE(qt_closestItemFirst(rect1child1, rect2child1), false);
10354     QCOMPARE(qt_closestItemFirst(rect1child1, rect1child2), true);
10355     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child2), true);
10356     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child1), true);
10357     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child2), true);
10358     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child1), false);
10359     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1), true);
10360     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2), false);
10361     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2child1), false);
10362 }
10363
10364 class ScenePosChangeTester : public ItemChangeTester
10365 {
10366 public:
10367     ScenePosChangeTester()
10368     { }
10369     ScenePosChangeTester(QGraphicsItem *parent) : ItemChangeTester(parent)
10370     { }
10371 };
10372
10373 void tst_QGraphicsItem::scenePosChange()
10374 {
10375     ScenePosChangeTester* root = new ScenePosChangeTester;
10376     ScenePosChangeTester* child1 = new ScenePosChangeTester(root);
10377     ScenePosChangeTester* grandChild1 = new ScenePosChangeTester(child1);
10378     ScenePosChangeTester* child2 = new ScenePosChangeTester(root);
10379     ScenePosChangeTester* grandChild2 = new ScenePosChangeTester(child2);
10380
10381     child1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10382     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10383
10384     QVERIFY(child1->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10385     QVERIFY(grandChild2->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10386
10387     QGraphicsScene scene;
10388     scene.addItem(root);
10389
10390     // ignore uninteresting changes
10391     child1->clear();
10392     child2->clear();
10393     grandChild1->clear();
10394     grandChild2->clear();
10395
10396     // move whole tree
10397     root->moveBy(1.0, 1.0);
10398     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10399     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10400     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10401     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10402
10403     // move subtree
10404     child2->moveBy(1.0, 1.0);
10405     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10406     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10407     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10408     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10409
10410     // reparent
10411     grandChild2->setParentItem(child1);
10412     child1->moveBy(1.0, 1.0);
10413     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10414     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10415     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10416     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10417
10418     // change flags
10419     grandChild1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10420     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false);
10421     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10422     child1->moveBy(1.0, 1.0);
10423     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10424     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10425     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10426     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10427
10428     // remove
10429     scene.removeItem(grandChild1);
10430     delete grandChild2; grandChild2 = 0;
10431     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10432     root->moveBy(1.0, 1.0);
10433     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 4);
10434     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10435     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10436
10437     root->setX(1);
10438     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 5);
10439     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10440     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10441
10442     root->setY(1);
10443     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 6);
10444     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10445     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10446 }
10447
10448 class MyInputContext : public QInputContext
10449 {
10450 public:
10451     MyInputContext() : nbUpdates(0) {}
10452     ~MyInputContext() {}
10453
10454     QString identifierName() { return QString(); }
10455     QString language() { return QString(); }
10456
10457     void reset() {}
10458
10459     bool isComposing() const { return false; }
10460
10461     void update() { nbUpdates++; }
10462
10463     bool nbUpdates;
10464 };
10465
10466 class MyInputWidget : public QGraphicsWidget
10467 {
10468 public:
10469     MyInputWidget()
10470     {
10471         setFlag(QGraphicsItem::ItemIsFocusable, true);
10472         setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
10473     }
10474     void mousePressEvent(QGraphicsSceneMouseEvent *event)
10475     {
10476         event->accept();
10477     }
10478
10479     void doUpdateMicroFocus()
10480     {
10481         if (QWidget *fw = QApplication::focusWidget()) {
10482             if (scene()) {
10483                 for (int i = 0 ; i < scene()->views().count() ; ++i) {
10484                     if (scene()->views().at(i) == fw) {
10485                         if (QInputContext *inputContext = fw->inputContext()) {
10486                             inputContext->update();
10487                         }
10488                     }
10489                 }
10490             }
10491         }
10492     }
10493 };
10494
10495 void tst_QGraphicsItem::updateMicroFocus()
10496 {
10497 #if defined Q_OS_WIN || defined Q_OS_MAC
10498     QSKIP("QTBUG-9578");
10499 #endif
10500     QGraphicsScene scene;
10501     QWidget parent;
10502     QGridLayout layout;
10503     parent.setLayout(&layout);
10504     QGraphicsView view(&scene);
10505     QGraphicsView view2(&scene);
10506     layout.addWidget(&view, 0, 0);
10507     layout.addWidget(&view2, 0, 1);
10508     MyInputContext *ic = new MyInputContext;
10509     qApp->setInputContext(ic);
10510     MyInputWidget input;
10511     input.setPos(0, 0);
10512     input.resize(150, 150);
10513     scene.addItem(&input);
10514     input.setFocus();
10515     parent.show();
10516     view.setFocus();
10517     qApp->setAutoSipEnabled(true);
10518     QApplication::setActiveWindow(&parent);
10519     QTest::qWaitForWindowShown(&parent);
10520     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&parent));
10521     //We reset the number of updates that happened previously (initialisation)
10522     ic->nbUpdates = 0;
10523     input.doUpdateMicroFocus();
10524     QApplication::processEvents();
10525     QTRY_COMPARE(ic->nbUpdates, 1);
10526 }
10527
10528 void tst_QGraphicsItem::textItem_shortcuts()
10529 {
10530     QWidget w;
10531     QVBoxLayout l;
10532     w.setLayout(&l);
10533     QGraphicsScene scene;
10534     QGraphicsView view(&scene);
10535     l.addWidget(&view);
10536     QPushButton b("Push Me");
10537     l.addWidget(&b);
10538
10539     QGraphicsTextItem *item = scene.addText("Troll Text");
10540     item->setFlag(QGraphicsItem::ItemIsFocusable);
10541     item->setTextInteractionFlags(Qt::TextEditorInteraction);
10542     w.show();
10543     QTest::qWaitForWindowShown(&w);
10544
10545     item->setFocus();
10546     QTRY_VERIFY(item->hasFocus());
10547     QVERIFY(item->textCursor().selectedText().isEmpty());
10548
10549     // Shortcut should work (select all)
10550     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10551     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10552     QTextCursor tc = item->textCursor();
10553     tc.clearSelection();
10554     item->setTextCursor(tc);
10555     QVERIFY(item->textCursor().selectedText().isEmpty());
10556
10557     // Shortcut should also work if the text item has the focus and another widget
10558     // has the same shortcut.
10559     b.setShortcut(QKeySequence("CTRL+A"));
10560     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10561     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10562 }
10563
10564 void tst_QGraphicsItem::scroll()
10565 {
10566     // Create two overlapping rectangles in the scene:
10567     // +-------+
10568     // |       | <- item1
10569     // |   +-------+
10570     // |   |       |
10571     // +---|       | <- item2
10572     //     |       |
10573     //     +-------+
10574
10575     EventTester *item1 = new EventTester;
10576     item1->br = QRectF(0, 0, 200, 200);
10577     item1->brush = Qt::red;
10578     item1->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10579
10580     EventTester *item2 = new EventTester;
10581     item2->br = QRectF(0, 0, 200, 200);
10582     item2->brush = Qt::blue;
10583     item2->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10584     item2->setPos(100, 100);
10585
10586     QGraphicsScene scene(0, 0, 300, 300);
10587     scene.addItem(item1);
10588     scene.addItem(item2);
10589
10590     MyGraphicsView view(&scene);
10591     view.setFrameStyle(0);
10592     view.show();
10593     QTest::qWaitForWindowShown(&view);
10594     QTRY_VERIFY(view.repaints > 0);
10595
10596     view.reset();
10597     item1->reset();
10598     item2->reset();
10599
10600     const QRectF item1BoundingRect = item1->boundingRect();
10601     const QRectF item2BoundingRect = item2->boundingRect();
10602
10603     // Scroll item1:
10604     // Item1 should get full exposure
10605     // Item2 should get exposure for the part that overlaps item1.
10606     item1->scroll(0, -10);
10607     QTRY_VERIFY(view.repaints > 0);
10608     QCOMPARE(item1->lastExposedRect, item1BoundingRect);
10609
10610     QRectF expectedItem2Expose = item2BoundingRect;
10611     // NB! Adjusted by 2 pixels for antialiasing
10612     expectedItem2Expose &= item1->mapRectToItem(item2, item1BoundingRect.adjusted(-2, -2, 2, 2));
10613     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10614
10615     // Enable ItemCoordinateCache on item1.
10616     view.reset();
10617     item1->setCacheMode(QGraphicsItem::ItemCoordinateCache);
10618     QTRY_VERIFY(view.repaints > 0);
10619     view.reset();
10620     item1->reset();
10621     item2->reset();
10622
10623     // Scroll item1:
10624     // Item1 should only get expose for the newly exposed area (accelerated scroll).
10625     // Item2 should get exposure for the part that overlaps item1.
10626     item1->scroll(0, -10, QRectF(50, 50, 100, 100));
10627     QTRY_VERIFY(view.repaints > 0);
10628     QCOMPARE(item1->lastExposedRect, QRectF(50, 140, 100, 10));
10629
10630     expectedItem2Expose = item2BoundingRect;
10631     // NB! Adjusted by 2 pixels for antialiasing
10632     expectedItem2Expose &= item1->mapRectToItem(item2, QRectF(50, 50, 100, 100).adjusted(-2, -2, 2, 2));
10633     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10634 }
10635
10636 Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlag);
10637
10638 void tst_QGraphicsItem::focusHandling_data()
10639 {
10640     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("focusFlag");
10641     QTest::addColumn<bool>("useStickyFocus");
10642     QTest::addColumn<int>("expectedFocusItem"); // 0: none, 1: focusableUnder, 2: itemWithFocus
10643
10644     QTest::newRow("Focus goes through.")
10645         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << false << 1;
10646
10647     QTest::newRow("Focus goes through, even with sticky scene.")
10648         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << true  << 1;
10649
10650     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (but can still focus-out).")
10651         << QGraphicsItem::ItemStopsClickFocusPropagation << false << 0;
10652
10653     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (and cannot focus-out if scene is sticky).")
10654         << QGraphicsItem::ItemStopsClickFocusPropagation << true << 2;
10655
10656     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses.")
10657         << QGraphicsItem::ItemStopsFocusHandling << false << 2;
10658
10659     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses (even if scene is sticky).")
10660         << QGraphicsItem::ItemStopsFocusHandling << true << 2;
10661 }
10662
10663 void tst_QGraphicsItem::focusHandling()
10664 {
10665     QFETCH(QGraphicsItem::GraphicsItemFlag, focusFlag);
10666     QFETCH(bool, useStickyFocus);
10667     QFETCH(int, expectedFocusItem);
10668
10669     class MyItem : public QGraphicsRectItem
10670     {
10671     public:
10672         MyItem() : QGraphicsRectItem(0, 0, 100, 100) {}
10673         void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
10674         {
10675             painter->fillRect(boundingRect(), hasFocus() ? QBrush(Qt::red) : brush());
10676         }
10677     };
10678
10679     QGraphicsRectItem *noFocusOnTop = new MyItem;
10680     noFocusOnTop->setFlag(QGraphicsItem::ItemIsFocusable, false);
10681     noFocusOnTop->setBrush(Qt::yellow);
10682
10683     QGraphicsRectItem *focusableUnder = new MyItem;
10684     focusableUnder->setBrush(Qt::blue);
10685     focusableUnder->setFlag(QGraphicsItem::ItemIsFocusable);
10686     focusableUnder->setPos(50, 50);
10687
10688     QGraphicsRectItem *itemWithFocus = new MyItem;
10689     itemWithFocus->setBrush(Qt::black);
10690     itemWithFocus->setFlag(QGraphicsItem::ItemIsFocusable);
10691     itemWithFocus->setPos(250, 10);
10692
10693     QGraphicsScene scene(-50, -50, 400, 400);
10694     scene.addItem(noFocusOnTop);
10695     scene.addItem(focusableUnder);
10696     scene.addItem(itemWithFocus);
10697     scene.setStickyFocus(useStickyFocus);
10698
10699     noFocusOnTop->setFlag(focusFlag);
10700     focusableUnder->stackBefore(noFocusOnTop);
10701     itemWithFocus->setFocus();
10702
10703     QGraphicsView view(&scene);
10704     view.show();
10705     QTest::qWaitForWindowShown(&view);
10706
10707     QApplication::setActiveWindow(&view);
10708     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
10709     QVERIFY(itemWithFocus->hasFocus());
10710
10711     const QPointF mousePressPoint = noFocusOnTop->mapToScene(noFocusOnTop->boundingRect().center());
10712     const QList<QGraphicsItem *> itemsAtMousePressPosition = scene.items(mousePressPoint);
10713     QVERIFY(itemsAtMousePressPosition.contains(noFocusOnTop));
10714
10715     sendMousePress(&scene, mousePressPoint);
10716
10717     switch (expectedFocusItem) {
10718     case 0:
10719         QCOMPARE(scene.focusItem(), static_cast<QGraphicsRectItem *>(0));
10720         break;
10721     case 1:
10722         QCOMPARE(scene.focusItem(), focusableUnder);
10723         break;
10724     case 2:
10725         QCOMPARE(scene.focusItem(), itemWithFocus);
10726         break;
10727     }
10728
10729     // Sanity check - manually setting the focus must work regardless of our
10730     // focus handling flags:
10731     focusableUnder->setFocus();
10732     QCOMPARE(scene.focusItem(), focusableUnder);
10733 }
10734
10735 void tst_QGraphicsItem::touchEventPropagation_data()
10736 {
10737     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("flag");
10738     QTest::addColumn<int>("expectedCount");
10739
10740     QTest::newRow("ItemIsPanel")
10741         << QGraphicsItem::ItemIsPanel << 0;
10742     QTest::newRow("ItemStopsClickFocusPropagation")
10743         << QGraphicsItem::ItemStopsClickFocusPropagation << 1;
10744     QTest::newRow("ItemStopsFocusHandling")
10745         << QGraphicsItem::ItemStopsFocusHandling << 1;
10746 }
10747
10748 void tst_QGraphicsItem::touchEventPropagation()
10749 {
10750     QFETCH(QGraphicsItem::GraphicsItemFlag, flag);
10751     QFETCH(int, expectedCount);
10752
10753     class Testee : public QGraphicsRectItem
10754     {
10755     public:
10756         int touchBeginEventCount;
10757
10758         Testee()
10759             : QGraphicsRectItem(0, 0, 100, 100)
10760             , touchBeginEventCount(0)
10761         {
10762             setAcceptTouchEvents(true);
10763             setFlag(QGraphicsItem::ItemIsFocusable, false);
10764         }
10765
10766         bool sceneEvent(QEvent *ev)
10767         {
10768             if (ev->type() == QEvent::TouchBegin)
10769                 ++touchBeginEventCount;
10770
10771             return QGraphicsRectItem::sceneEvent(ev);
10772         }
10773     };
10774
10775     Testee *touchEventReceiver = new Testee;
10776     QGraphicsItem *topMost = new QGraphicsRectItem(touchEventReceiver->boundingRect());
10777
10778     QGraphicsScene scene;
10779     scene.addItem(topMost);
10780     scene.addItem(touchEventReceiver);
10781
10782     topMost->setAcceptTouchEvents(true);
10783     topMost->setZValue(FLT_MAX);
10784     topMost->setFlag(QGraphicsItem::ItemIsFocusable, false);
10785     topMost->setFlag(flag, true);
10786
10787     QGraphicsView view(&scene);
10788     view.setSceneRect(touchEventReceiver->boundingRect());
10789     view.show();
10790     QTest::qWaitForWindowShown(&view);
10791
10792     QCOMPARE(touchEventReceiver->touchBeginEventCount, 0);
10793
10794     QTouchEvent::TouchPoint tp(0);
10795     tp.setState(Qt::TouchPointPressed);
10796     tp.setScenePos(view.sceneRect().center());
10797     tp.setLastScenePos(view.sceneRect().center());
10798
10799     QList<QTouchEvent::TouchPoint> touchPoints;
10800     touchPoints << tp;
10801
10802     sendMousePress(&scene, tp.scenePos());
10803     QTouchEvent touchBegin(QEvent::TouchBegin, QTouchEvent::TouchScreen, Qt::NoModifier, Qt::TouchPointPressed, touchPoints);
10804
10805     qApp->sendEvent(&scene, &touchBegin);
10806     QCOMPARE(touchEventReceiver->touchBeginEventCount, expectedCount);
10807 }
10808
10809 void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations()
10810 {
10811     // Make sure we don't invalidate the cache when applying simple
10812     // (90, 180, 270, 360) rotation transforms to the item.
10813     QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 300, 200);
10814     item->setBrush(Qt::red);
10815     item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
10816
10817     QGraphicsScene scene;
10818     scene.setSceneRect(0, 0, 300, 200);
10819     scene.addItem(item);
10820
10821     MyGraphicsView view(&scene);
10822     view.show();
10823     QTest::qWaitForWindowShown(&view);
10824     QTRY_VERIFY(view.repaints > 0);
10825
10826     QGraphicsItemCache *itemCache = QGraphicsItemPrivate::get(item)->extraItemCache();
10827     QVERIFY(itemCache);
10828     QPixmapCache::Key currentKey = itemCache->deviceData.value(view.viewport()).key;
10829
10830     // Trigger an update and verify that the cache is unchanged.
10831     QPixmapCache::Key oldKey = currentKey;
10832     view.reset();
10833     view.viewport()->update();
10834     QTRY_VERIFY(view.repaints > 0);
10835     currentKey = itemCache->deviceData.value(view.viewport()).key;
10836     QCOMPARE(currentKey, oldKey);
10837
10838     // Check 90, 180, 270 and 360 degree rotations.
10839     for (int angle = 90; angle <= 360; angle += 90) {
10840         // Rotate item and verify that the cache was invalidated.
10841         oldKey = currentKey;
10842         view.reset();
10843         QTransform transform;
10844         transform.translate(150, 100);
10845         transform.rotate(angle);
10846         transform.translate(-150, -100);
10847         item->setTransform(transform);
10848         QTRY_VERIFY(view.repaints > 0);
10849         currentKey = itemCache->deviceData.value(view.viewport()).key;
10850         QVERIFY(currentKey != oldKey);
10851
10852         // IMPORTANT PART:
10853         // Trigger an update and verify that the cache is unchanged.
10854         oldKey = currentKey;
10855         view.reset();
10856         view.viewport()->update();
10857         QTRY_VERIFY(view.repaints > 0);
10858         currentKey = itemCache->deviceData.value(view.viewport()).key;
10859         QCOMPARE(currentKey, oldKey);
10860     }
10861
10862     // 45 degree rotation.
10863     oldKey = currentKey;
10864     view.reset();
10865     QTransform transform;
10866     transform.translate(150, 100);
10867     transform.rotate(45);
10868     transform.translate(-150, -100);
10869     item->setTransform(transform);
10870     QTRY_VERIFY(view.repaints > 0);
10871     currentKey = itemCache->deviceData.value(view.viewport()).key;
10872     QVERIFY(currentKey != oldKey);
10873
10874     // Trigger an update and verify that the cache was invalidated.
10875     // We should always invalidate the cache for non-trivial transforms.
10876     oldKey = currentKey;
10877     view.reset();
10878     view.viewport()->update();
10879     QTRY_VERIFY(view.repaints > 0);
10880     currentKey = itemCache->deviceData.value(view.viewport()).key;
10881     QVERIFY(currentKey != oldKey);
10882 }
10883
10884 void tst_QGraphicsItem::QTBUG_5418_textItemSetDefaultColor()
10885 {
10886     struct Item : public QGraphicsTextItem
10887     {
10888         int painted;
10889         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
10890         {
10891             painted++;
10892             QGraphicsTextItem::paint(painter, opt, wid);
10893         }
10894     };
10895
10896     Item *i = new Item;
10897     i->painted = 0;
10898     i->setPlainText("I AM A TROLL");
10899
10900     QGraphicsScene scene;
10901     QGraphicsView view(&scene);
10902     view.show();
10903     QTest::qWaitForWindowShown(&view);
10904     scene.addItem(i);
10905     QApplication::processEvents();
10906     QTRY_VERIFY(i->painted);
10907     QApplication::processEvents();
10908
10909     i->painted = 0;
10910     QColor col(Qt::red);
10911     i->setDefaultTextColor(col);
10912     QApplication::processEvents();
10913     QTRY_COMPARE(i->painted, 1); //check that changing the color force an update
10914
10915     i->painted = false;
10916     QImage image(400, 200, QImage::Format_RGB32);
10917     image.fill(0);
10918     QPainter painter(&image);
10919     scene.render(&painter);
10920     painter.end();
10921     QCOMPARE(i->painted, 1);
10922
10923     int numRedPixel = 0;
10924     QRgb rgb = col.rgb();
10925     for (int y = 0; y < image.height(); ++y) {
10926         for (int x = 0; x < image.width(); ++x) {
10927             // Because of antialiasing we allow a certain range of errors here.
10928             QRgb pixel = image.pixel(x, y);
10929             if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) +
10930                 qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) +
10931                 qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) {
10932                 if (++numRedPixel >= 10) {
10933                     return;
10934                 }
10935             }
10936         }
10937     }
10938     QCOMPARE(numRedPixel, -1); //color not found, FAIL!
10939
10940     i->painted = 0;
10941     i->setDefaultTextColor(col);
10942     QApplication::processEvents();
10943     QCOMPARE(i->painted, 0); //same color as before should not trigger an update (QTBUG-6242)
10944 }
10945
10946 void tst_QGraphicsItem::QTBUG_6738_missingUpdateWithSetParent()
10947 {
10948     // In all 3 test cases below the reparented item should disappear
10949     EventTester *parent = new EventTester;
10950     EventTester *child = new EventTester(parent);
10951     EventTester *child2 = new EventTester(parent);
10952     EventTester *child3 = new EventTester(parent);
10953     EventTester *child4 = new EventTester(parent);
10954
10955     child->setPos(10, 10);
10956     child2->setPos(20, 20);
10957     child3->setPos(30, 30);
10958     child4->setPos(40, 40);
10959
10960     QGraphicsScene scene;
10961     scene.addItem(parent);
10962
10963     MyGraphicsView view(&scene);
10964     if(PlatformQuirks::isAutoMaximizing())
10965         view.showFullScreen();
10966     else
10967         view.show();
10968     QTest::qWaitForWindowShown(&view);
10969     QTRY_VERIFY(view.repaints > 0);
10970
10971     // test case #1
10972     view.reset();
10973     child2->setVisible(false);
10974     child2->setParentItem(child);
10975
10976     QTRY_VERIFY(view.repaints == 1);
10977
10978     // test case #2
10979     view.reset();
10980     child3->setOpacity(0.0);
10981     child3->setParentItem(child);
10982
10983     QTRY_VERIFY(view.repaints == 1);
10984
10985     // test case #3
10986     view.reset();
10987     child4->setParentItem(child);
10988     child4->setVisible(false);
10989
10990     QTRY_VERIFY(view.repaints == 1);
10991 }
10992
10993 void tst_QGraphicsItem::QT_2653_fullUpdateDiscardingOpacityUpdate()
10994 {
10995     QGraphicsScene scene(0, 0, 200, 200);
10996     MyGraphicsView view(&scene);
10997
10998     EventTester *parentGreen = new EventTester();
10999     parentGreen->setGeometry(QRectF(20, 20, 100, 100));
11000     parentGreen->brush = Qt::green;
11001
11002     EventTester *childYellow = new EventTester(parentGreen);
11003     childYellow->setGeometry(QRectF(10, 10, 50, 50));
11004     childYellow->brush = Qt::yellow;
11005
11006     scene.addItem(parentGreen);
11007
11008     childYellow->setOpacity(0.0);
11009     parentGreen->setOpacity(0.0);
11010
11011     // set any of the flags below to trigger a fullUpdate to reproduce the bug:
11012     // ItemIgnoresTransformations, ItemClipsChildrenToShape, ItemIsSelectable
11013     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
11014
11015     if (PlatformQuirks::isAutoMaximizing())
11016         view.showFullScreen();
11017     else
11018         view.show();
11019     QTest::qWaitForWindowShown(&view);
11020     view.reset();
11021
11022     parentGreen->setOpacity(1.0);
11023
11024     QTRY_COMPARE(view.repaints, 1);
11025
11026     view.reset();
11027     childYellow->repaints = 0;
11028
11029     childYellow->setOpacity(1.0);
11030
11031     QTRY_COMPARE(view.repaints, 1);
11032     QTRY_COMPARE(childYellow->repaints, 1);
11033 }
11034
11035 void tst_QGraphicsItem::QTBUG_7714_fullUpdateDiscardingOpacityUpdate2()
11036 {
11037     QGraphicsScene scene(0, 0, 200, 200);
11038     MyGraphicsView view(&scene);
11039     MyGraphicsView origView(&scene);
11040
11041     EventTester *parentGreen = new EventTester();
11042     parentGreen->setGeometry(QRectF(20, 20, 100, 100));
11043     parentGreen->brush = Qt::green;
11044
11045     EventTester *childYellow = new EventTester(parentGreen);
11046     childYellow->setGeometry(QRectF(10, 10, 50, 50));
11047     childYellow->brush = Qt::yellow;
11048
11049     scene.addItem(parentGreen);
11050
11051     origView.show();
11052     QTest::qWaitForWindowShown(&origView);
11053     origView.setGeometry(origView.width() + 20, 20,
11054                          origView.width(), origView.height());
11055
11056     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
11057
11058     origView.reset();
11059     childYellow->setOpacity(0.0);
11060
11061     QTRY_COMPARE(origView.repaints, 1);
11062
11063     view.show();
11064
11065     QTest::qWaitForWindowShown(&view);
11066     view.reset();
11067     origView.reset();
11068
11069     childYellow->setOpacity(1.0);
11070
11071     QTRY_COMPARE(origView.repaints, 1);
11072     QTRY_COMPARE(view.repaints, 1);
11073 }
11074
11075 void tst_QGraphicsItem::QT_2649_focusScope()
11076 {
11077     QGraphicsScene *scene = new QGraphicsScene;
11078
11079     QGraphicsRectItem *subFocusItem = new QGraphicsRectItem;
11080     subFocusItem->setFlags(QGraphicsItem::ItemIsFocusable);
11081     subFocusItem->setFocus();
11082     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11083
11084     QGraphicsRectItem *scope = new QGraphicsRectItem;
11085     scope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
11086     scope->setFocus();
11087     subFocusItem->setParentItem(scope);
11088     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11089     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11090     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11091     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11092
11093     QGraphicsRectItem *rootItem = new QGraphicsRectItem;
11094     rootItem->setFlags(QGraphicsItem::ItemIsFocusable);
11095     scope->setParentItem(rootItem);
11096     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11097     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11098     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11099     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11100     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11101     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11102
11103     scene->addItem(rootItem);
11104
11105     QEvent windowActivate(QEvent::WindowActivate);
11106     qApp->sendEvent(scene, &windowActivate);
11107     scene->setFocus();
11108
11109     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11110     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11111     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11112     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11113     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11114     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11115     QVERIFY(subFocusItem->hasFocus());
11116
11117     scope->hide();
11118
11119     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)0);
11120     QCOMPARE(scope->focusItem(), (QGraphicsItem *)0);
11121     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)0);
11122     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11123     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11124     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11125     QVERIFY(!subFocusItem->hasFocus());
11126
11127     scope->show();
11128
11129     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11130     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11131     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11132     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11133     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11134     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11135     QVERIFY(subFocusItem->hasFocus());
11136
11137     // This should not crash
11138     scope->hide();
11139     delete scene;
11140 }
11141
11142 class MyGraphicsItemWithItemChange : public QGraphicsWidget
11143 {
11144 public:
11145     MyGraphicsItemWithItemChange(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
11146     {}
11147
11148     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
11149     {
11150         if (change == QGraphicsItem::ItemSceneHasChanged) {
11151             foreach (QGraphicsView *view, scene()->views()) {
11152                 //We trigger a sort of unindexed items in the BSP
11153                 view->sceneRect();
11154             }
11155         }
11156         return QGraphicsWidget::itemChange(change, value);
11157     }
11158 };
11159
11160 void tst_QGraphicsItem::sortItemsWhileAdding()
11161 {
11162     QGraphicsScene scene;
11163     QGraphicsView view(&scene);
11164     QGraphicsWidget grandGrandParent;
11165     grandGrandParent.resize(200, 200);
11166     scene.addItem(&grandGrandParent);
11167     QGraphicsWidget grandParent;
11168     grandParent.resize(200, 200);
11169     QGraphicsWidget parent(&grandParent);
11170     parent.resize(200, 200);
11171     MyGraphicsItemWithItemChange item(&parent);
11172     grandParent.setParentItem(&grandGrandParent);
11173 }
11174
11175 void tst_QGraphicsItem::doNotMarkFullUpdateIfNotInScene()
11176 {
11177     struct Item : public QGraphicsTextItem
11178     {
11179         int painted;
11180         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
11181         {
11182             painted++;
11183             QGraphicsTextItem::paint(painter, opt, wid);
11184         }
11185     };
11186     QGraphicsScene scene;
11187     MyGraphicsView view(&scene);
11188     Item *item = new Item;
11189     item->painted = 0;
11190     item->setPlainText("Grandparent");
11191     Item *item2 = new Item;
11192     item2->setPlainText("parent");
11193     item2->painted = 0;
11194     Item *item3 = new Item;
11195     item3->setPlainText("child");
11196     item3->painted = 0;
11197     QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect;
11198     effect->setOpacity(0.5);
11199     item2->setGraphicsEffect(effect);
11200     item3->setParentItem(item2);
11201     item2->setParentItem(item);
11202     scene.addItem(item);
11203     if(PlatformQuirks::isAutoMaximizing())
11204         view.showFullScreen();
11205     else
11206         view.show();
11207     QTest::qWaitForWindowShown(&view);
11208     QTRY_COMPARE(view.repaints, 1);
11209     QTRY_COMPARE(item->painted, 1);
11210     QTRY_COMPARE(item2->painted, 1);
11211     QTRY_COMPARE(item3->painted, 1);
11212     item2->update();
11213     QApplication::processEvents();
11214     QTRY_COMPARE(item->painted, 2);
11215     QTRY_COMPARE(item2->painted, 2);
11216     QTRY_COMPARE(item3->painted, 2);
11217     item2->update();
11218     QApplication::processEvents();
11219     QTRY_COMPARE(item->painted, 3);
11220     QTRY_COMPARE(item2->painted, 3);
11221     QTRY_COMPARE(item3->painted, 3);
11222 }
11223
11224 void tst_QGraphicsItem::itemDiesDuringDraggingOperation()
11225 {
11226     QGraphicsScene scene;
11227     QGraphicsView view(&scene);
11228     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
11229     item->setFlag(QGraphicsItem::ItemIsMovable);
11230     item->setAcceptDrops(true);
11231     scene.addItem(item);
11232     view.show();
11233     QApplication::setActiveWindow(&view);
11234     QTest::qWaitForWindowShown(&view);
11235     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
11236     QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
11237     dragEnter.setScenePos(item->boundingRect().center());
11238     QApplication::sendEvent(&scene, &dragEnter);
11239     QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragMove);
11240     event.setScenePos(item->boundingRect().center());
11241     QApplication::sendEvent(&scene, &event);
11242     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == item);
11243     delete item;
11244     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == 0);
11245 }
11246
11247 void tst_QGraphicsItem::QTBUG_12112_focusItem()
11248 {
11249     QGraphicsScene scene;
11250     QGraphicsView view(&scene);
11251     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
11252     item1->setFlag(QGraphicsItem::ItemIsFocusable);
11253     QGraphicsRectItem *item2 = new QGraphicsRectItem(20, 20, 20, 20);
11254     item2->setFlag(QGraphicsItem::ItemIsFocusable);
11255     item1->setFocus();
11256     scene.addItem(item2);
11257     scene.addItem(item1);
11258
11259     view.show();
11260     QApplication::setActiveWindow(&view);
11261     QTest::qWaitForWindowShown(&view);
11262     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
11263
11264     QVERIFY(item1->focusItem());
11265     QVERIFY(!item2->focusItem());
11266
11267     item2->setFocus();
11268     QVERIFY(!item1->focusItem());
11269     QVERIFY(item2->focusItem());
11270 }
11271
11272 void tst_QGraphicsItem::QTBUG_13473_sceneposchange()
11273 {
11274     ScenePosChangeTester* parent = new ScenePosChangeTester;
11275     ScenePosChangeTester* child = new ScenePosChangeTester(parent);
11276
11277     // parent's disabled ItemSendsGeometryChanges flag must not affect
11278     // child's scene pos change notifications
11279     parent->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
11280     child->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
11281
11282     QGraphicsScene scene;
11283     scene.addItem(parent);
11284
11285     // ignore uninteresting changes
11286     parent->clear();
11287     child->clear();
11288
11289     // move
11290     parent->moveBy(1.0, 1.0);
11291     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
11292
11293     // transform
11294     parent->setTransform(QTransform::fromScale(0.5, 0.5));
11295     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
11296 }
11297
11298 class MyGraphicsWidget : public QGraphicsWidget {
11299 Q_OBJECT
11300 public:
11301     MyGraphicsWidget()
11302         : QGraphicsWidget(0)
11303     {
11304         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11305         QLatin1String wiseWords("AZ BUKI VEDI");
11306         QString sentence(wiseWords);
11307         QStringList words = sentence.split(QLatin1Char(' '), QString::SkipEmptyParts);
11308         for (int i = 0; i < words.count(); ++i) {
11309             QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(this);
11310             QLabel *label = new QLabel(words.at(i));
11311             proxy->setWidget(label);
11312             proxy->setFocusPolicy(Qt::StrongFocus);
11313             proxy->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
11314             if (i%2 == 0)
11315                 proxy->setVisible(false);
11316             proxy->setFocus();
11317             lay->addItem(proxy);
11318         }
11319         setLayout(lay);
11320     }
11321
11322 };
11323
11324 class MyWidgetWindow : public QGraphicsWidget
11325 {
11326 public:
11327     MyWidgetWindow()
11328         : QGraphicsWidget(0, Qt::Window)
11329     {
11330         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11331         MyGraphicsWidget *widget = new MyGraphicsWidget();
11332         lay->addItem(widget);
11333         setLayout(lay);
11334     }
11335 };
11336
11337 void tst_QGraphicsItem::QTBUG_16374_crashInDestructor()
11338 {
11339     QGraphicsScene scene;
11340     QGraphicsView view(&scene);
11341
11342     MyWidgetWindow win;
11343     scene.addItem(&win);
11344
11345     view.show();
11346     QTest::qWaitForWindowShown(&view);
11347 }
11348
11349 void tst_QGraphicsItem::QTBUG_20699_focusScopeCrash()
11350 {
11351     QGraphicsScene scene;
11352     QGraphicsView view(&scene);
11353     QGraphicsPixmapItem fs;
11354     fs.setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11355     scene.addItem(&fs);
11356     QGraphicsPixmapItem* fs2 = new QGraphicsPixmapItem(&fs);
11357     fs2->setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11358     QGraphicsPixmapItem* fi2 = new QGraphicsPixmapItem(&fs);
11359     fi2->setFlags(QGraphicsItem::ItemIsFocusable);
11360     QGraphicsPixmapItem* fi = new QGraphicsPixmapItem(fs2);
11361     fi->setFlags(QGraphicsItem::ItemIsFocusable);
11362     fs.setFocus();
11363     fi->setFocus();
11364
11365     view.show();
11366     QTest::qWaitForWindowShown(&view);
11367
11368     fi->setParentItem(fi2);
11369     fi->setFocus();
11370     fs.setFocus();
11371     fi->setParentItem(fs2);
11372     fi->setFocus();
11373     fs2->setFocus();
11374     fs.setFocus();
11375     fi->setParentItem(fi2);
11376     fi->setFocus();
11377     fs.setFocus();
11378 }
11379
11380 QTEST_MAIN(tst_QGraphicsItem)
11381 #include "tst_qgraphicsitem.moc"