f78b40bdf0cce1fe5c9eb55263e797b5683f2c7f
[profile/ivi/qtbase.git] / tests / auto / widgets / graphicsview / qgraphicsitem / tst_qgraphicsitem.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 <QPushButton>
65 #include <QLineEdit>
66 #include <QGraphicsLinearLayout>
67 #include <float.h>
68 #include <QStyleHints>
69
70 Q_DECLARE_METATYPE(QList<int>)
71 Q_DECLARE_METATYPE(QList<QRectF>)
72 Q_DECLARE_METATYPE(QPainterPath)
73 Q_DECLARE_METATYPE(QPointF)
74 Q_DECLARE_METATYPE(QRectF)
75
76 #include "../../../qtest-config.h"
77
78 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
79 #include <windows.h>
80 #define Q_CHECK_PAINTEVENTS \
81     if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \
82         QSKIP("The Graphics View doesn't get the paint events");
83 #else
84 #define Q_CHECK_PAINTEVENTS
85 #endif
86
87 #if defined(Q_OS_MAC)
88 // On mac (cocoa) we always get full update.
89 // So check that the expected region is contained inside the actual
90 #define COMPARE_REGIONS(ACTUAL, EXPECTED) QVERIFY((EXPECTED).subtracted(ACTUAL).isEmpty())
91 #else
92 #define COMPARE_REGIONS QTRY_COMPARE
93 #endif
94
95 static QGraphicsRectItem staticItem; //QTBUG-7629, we should not crash at exit.
96
97 static void sendMousePress(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
98 {
99     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
100     event.setScenePos(point);
101     event.setButton(button);
102     event.setButtons(button);
103     QApplication::sendEvent(scene, &event);
104 }
105
106 static void sendMouseMove(QGraphicsScene *scene, const QPointF &point,
107                           Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons /* buttons */ = 0)
108 {
109     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
110     event.setScenePos(point);
111     event.setButton(button);
112     event.setButtons(button);
113     QApplication::sendEvent(scene, &event);
114 }
115
116 static void sendMouseRelease(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
117 {
118     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
119     event.setScenePos(point);
120     event.setButton(button);
121     QApplication::sendEvent(scene, &event);
122 }
123
124 static void sendMouseClick(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton)
125 {
126     sendMousePress(scene, point, button);
127     sendMouseRelease(scene, point, button);
128 }
129
130 static void sendKeyPress(QGraphicsScene *scene, Qt::Key key)
131 {
132     QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier);
133     QApplication::sendEvent(scene, &keyEvent);
134 }
135
136 static void sendKeyRelease(QGraphicsScene *scene, Qt::Key key)
137 {
138     QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier);
139     QApplication::sendEvent(scene, &keyEvent);
140 }
141
142 static void sendKeyClick(QGraphicsScene *scene, Qt::Key key)
143 {
144     sendKeyPress(scene, key);
145     sendKeyRelease(scene, key);
146 }
147
148 class EventSpy : public QGraphicsWidget
149 {
150     Q_OBJECT
151 public:
152     EventSpy(QObject *watched, QEvent::Type type)
153         : _count(0), spied(type)
154     {
155         watched->installEventFilter(this);
156     }
157
158     EventSpy(QGraphicsScene *scene, QGraphicsItem *watched, QEvent::Type type)
159         : _count(0), spied(type)
160     {
161         scene->addItem(this);
162         watched->installSceneEventFilter(this);
163     }
164
165     int count() const { return _count; }
166
167 protected:
168     bool eventFilter(QObject *watched, QEvent *event)
169     {
170         Q_UNUSED(watched);
171         if (event->type() == spied)
172             ++_count;
173         return false;
174     }
175
176     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
177     {
178         Q_UNUSED(watched);
179         if (event->type() == spied)
180             ++_count;
181         return false;
182     }
183
184     int _count;
185     QEvent::Type spied;
186 };
187
188 class EventSpy2 : public QGraphicsWidget
189 {
190     Q_OBJECT
191 public:
192     EventSpy2(QObject *watched)
193     {
194         watched->installEventFilter(this);
195     }
196
197     EventSpy2(QGraphicsScene *scene, QGraphicsItem *watched)
198     {
199         scene->addItem(this);
200         watched->installSceneEventFilter(this);
201     }
202
203     QMap<QEvent::Type, int> counts;
204
205 protected:
206     bool eventFilter(QObject *watched, QEvent *event)
207     {
208         Q_UNUSED(watched);
209         ++counts[event->type()];
210         return false;
211     }
212
213     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
214     {
215         Q_UNUSED(watched);
216         ++counts[event->type()];
217         return false;
218     }
219 };
220
221 class EventTester : public QGraphicsItem
222 {
223 public:
224     EventTester(QGraphicsItem *parent = 0) : QGraphicsItem(parent), repaints(0)
225     { br = QRectF(-10, -10, 20, 20); }
226
227     void setGeometry(const QRectF &rect)
228     {
229         prepareGeometryChange();
230         br = rect;
231         update();
232     }
233
234     QRectF boundingRect() const
235     { return br; }
236
237     void paint(QPainter *painter, const QStyleOptionGraphicsItem *o, QWidget *)
238     {
239         hints = painter->renderHints();
240         painter->setBrush(brush);
241         painter->drawRect(boundingRect());
242         lastExposedRect = o->exposedRect;
243         ++repaints;
244     }
245
246     bool sceneEvent(QEvent *event)
247     {
248         events << event->type();
249         return QGraphicsItem::sceneEvent(event);
250     }
251
252     void reset()
253     {
254         events.clear();
255         hints = QPainter::RenderHints(0);
256         repaints = 0;
257         lastExposedRect = QRectF();
258     }
259
260     QList<QEvent::Type> events;
261     QPainter::RenderHints hints;
262     int repaints;
263     QRectF br;
264     QRectF lastExposedRect;
265     QBrush brush;
266 };
267
268 class MyGraphicsView : public QGraphicsView
269 {
270 public:
271     int repaints;
272     QRegion paintedRegion;
273     MyGraphicsView(QGraphicsScene *scene, QWidget *parent=0) : QGraphicsView(scene,parent), repaints(0) {}
274     void paintEvent(QPaintEvent *e)
275     {
276         paintedRegion += e->region();
277         ++repaints;
278         QGraphicsView::paintEvent(e);
279     }
280     void reset() { repaints = 0; paintedRegion = QRegion(); }
281 };
282
283 class tst_QGraphicsItem : public QObject
284 {
285     Q_OBJECT
286
287 public slots:
288     void init();
289
290 private slots:
291     void construction();
292     void constructionWithParent();
293     void destruction();
294     void deleteChildItem();
295     void scene();
296     void parentItem();
297     void setParentItem();
298     void children();
299     void flags();
300     void inputMethodHints();
301     void toolTip();
302     void visible();
303     void isVisibleTo();
304     void explicitlyVisible();
305     void enabled();
306     void explicitlyEnabled();
307     void selected();
308     void selected2();
309     void selected_group();
310     void selected_textItem();
311     void selected_multi();
312     void acceptedMouseButtons();
313     void acceptsHoverEvents();
314     void childAcceptsHoverEvents();
315     void hasFocus();
316     void pos();
317     void scenePos();
318     void matrix();
319     void sceneMatrix();
320     void setMatrix();
321     void zValue();
322     void shape();
323     void contains();
324     void collidesWith_item();
325     void collidesWith_path_data();
326     void collidesWith_path();
327     void collidesWithItemWithClip();
328     void isObscuredBy();
329     void isObscured();
330     void mapFromToParent();
331     void mapFromToScene();
332     void mapFromToItem();
333     void mapRectFromToParent_data();
334     void mapRectFromToParent();
335     void isAncestorOf();
336     void commonAncestorItem();
337     void data();
338     void type();
339     void graphicsitem_cast();
340     void hoverEventsGenerateRepaints();
341     void boundingRects_data();
342     void boundingRects();
343     void boundingRects2();
344     void sceneBoundingRect();
345     void childrenBoundingRect();
346     void childrenBoundingRectTransformed();
347     void childrenBoundingRect2();
348     void childrenBoundingRect3();
349     void childrenBoundingRect4();
350     void childrenBoundingRect5();
351     void group();
352     void setGroup();
353     void setGroup2();
354     void nestedGroups();
355     void warpChildrenIntoGroup();
356     void removeFromGroup();
357     void handlesChildEvents();
358     void handlesChildEvents2();
359     void handlesChildEvents3();
360     void filtersChildEvents();
361     void filtersChildEvents2();
362     void ensureVisible();
363 #ifndef QTEST_NO_CURSOR
364     void cursor();
365 #endif
366     //void textControlGetterSetter();
367     void defaultItemTest_QGraphicsLineItem();
368     void defaultItemTest_QGraphicsPixmapItem();
369     void defaultItemTest_QGraphicsTextItem();
370     void defaultItemTest_QGraphicsEllipseItem();
371     void itemChange();
372     void sceneEventFilter();
373     void prepareGeometryChange();
374     void paint();
375     void deleteItemInEventHandlers();
376     void itemClipsToShape();
377     void itemClipsChildrenToShape();
378     void itemClipsChildrenToShape2();
379     void itemClipsChildrenToShape3();
380     void itemClipsChildrenToShape4();
381     void itemClipsChildrenToShape5();
382     void itemClipsTextChildToShape();
383     void itemClippingDiscovery();
384     void ancestorFlags();
385     void untransformable();
386     void contextMenuEventPropagation();
387     void itemIsMovable();
388     void boundingRegion_data();
389     void boundingRegion();
390     void itemTransform_parentChild();
391     void itemTransform_siblings();
392     void itemTransform_unrelated();
393     void opacity_data();
394     void opacity();
395     void opacity2();
396     void opacityZeroUpdates();
397     void itemStacksBehindParent();
398     void nestedClipping();
399     void nestedClippingTransforms();
400     void sceneTransformCache();
401     void tabChangesFocus();
402     void tabChangesFocus_data();
403     void cacheMode();
404     void cacheMode2();
405     void updateCachedItemAfterMove();
406     void deviceTransform_data();
407     void deviceTransform();
408     void update();
409     void setTransformProperties_data();
410     void setTransformProperties();
411     void itemUsesExtendedStyleOption();
412     void itemSendsGeometryChanges();
413     void moveItem();
414     void moveLineItem();
415     void sorting_data();
416     void sorting();
417     void itemHasNoContents();
418     void hitTestUntransformableItem();
419     void hitTestGraphicsEffectItem();
420     void focusProxy();
421     void subFocus();
422     void focusProxyDeletion();
423     void negativeZStacksBehindParent();
424     void setGraphicsEffect();
425     void panel();
426     void addPanelToActiveScene();
427     void panelWithFocusItem();
428     void activate();
429     void setActivePanelOnInactiveScene();
430     void activationOnShowHide();
431     void moveWhileDeleting();
432     void ensureDirtySceneTransform();
433     void focusScope();
434     void focusScope2();
435     void stackBefore();
436     void sceneModality();
437     void panelModality();
438     void mixedModality();
439     void modality_hover();
440     void modality_mouseGrabber();
441     void modality_clickFocus();
442     void modality_keyEvents();
443     void itemIsInFront();
444     void scenePosChange();
445     void textItem_shortcuts();
446     void scroll();
447     void focusHandling_data();
448     void focusHandling();
449     void touchEventPropagation_data();
450     void touchEventPropagation();
451     void deviceCoordinateCache_simpleRotations();
452
453     // task specific tests below me
454     void task141694_textItemEnsureVisible();
455     void task128696_textItemEnsureMovable();
456     void ensureUpdateOnTextItem();
457     void task177918_lineItemUndetected();
458     void task240400_clickOnTextItem_data();
459     void task240400_clickOnTextItem();
460     void task243707_addChildBeforeParent();
461     void task197802_childrenVisibility();
462     void QTBUG_4233_updateCachedWithSceneRect();
463     void QTBUG_5418_textItemSetDefaultColor();
464     void QTBUG_6738_missingUpdateWithSetParent();
465     void QTBUG_7714_fullUpdateDiscardingOpacityUpdate2();
466     void QT_2653_fullUpdateDiscardingOpacityUpdate();
467     void QT_2649_focusScope();
468     void sortItemsWhileAdding();
469     void doNotMarkFullUpdateIfNotInScene();
470     void itemDiesDuringDraggingOperation();
471     void QTBUG_12112_focusItem();
472     void QTBUG_13473_sceneposchange();
473     void QTBUG_16374_crashInDestructor();
474     void QTBUG_20699_focusScopeCrash();
475
476 private:
477     QList<QGraphicsItem *> paintedItems;
478 };
479
480 void tst_QGraphicsItem::init()
481 {
482 #ifdef Q_OS_WINCE //disable magic for WindowsCE
483     qApp->setAutoMaximizeThreshold(-1);
484 #endif
485 }
486
487 void tst_QGraphicsItem::construction()
488 {
489     for (int i = 0; i < 7; ++i) {
490         QGraphicsItem *item;
491         switch (i) {
492         case 0:
493             item = new QGraphicsEllipseItem;
494             QCOMPARE(int(item->type()), int(QGraphicsEllipseItem::Type));
495             QCOMPARE(qgraphicsitem_cast<QGraphicsEllipseItem *>(item), (QGraphicsEllipseItem *)item);
496             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
497             QCOMPARE(item->flags(), 0);
498             break;
499         case 1:
500             item = new QGraphicsLineItem;
501             QCOMPARE(int(item->type()), int(QGraphicsLineItem::Type));
502             QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)item);
503             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
504             QCOMPARE(item->flags(), 0);
505             break;
506         case 2:
507             item = new QGraphicsPathItem;
508             QCOMPARE(int(item->type()), int(QGraphicsPathItem::Type));
509             QCOMPARE(qgraphicsitem_cast<QGraphicsPathItem *>(item), (QGraphicsPathItem *)item);
510             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
511             QCOMPARE(item->flags(), 0);
512             break;
513         case 3:
514             item = new QGraphicsPixmapItem;
515             QCOMPARE(int(item->type()), int(QGraphicsPixmapItem::Type));
516             QCOMPARE(qgraphicsitem_cast<QGraphicsPixmapItem *>(item), (QGraphicsPixmapItem *)item);
517             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
518             QCOMPARE(item->flags(), 0);
519             break;
520         case 4:
521             item = new QGraphicsPolygonItem;
522             QCOMPARE(int(item->type()), int(QGraphicsPolygonItem::Type));
523             QCOMPARE(qgraphicsitem_cast<QGraphicsPolygonItem *>(item), (QGraphicsPolygonItem *)item);
524             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
525             QCOMPARE(item->flags(), 0);
526             break;
527         case 5:
528             item = new QGraphicsRectItem;
529             QCOMPARE(int(item->type()), int(QGraphicsRectItem::Type));
530             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)item);
531             QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)0);
532             QCOMPARE(item->flags(), 0);
533             break;
534         case 6:
535             item = new QGraphicsTextItem;
536             QCOMPARE(int(item->type()), int(QGraphicsTextItem::Type));
537             QCOMPARE(qgraphicsitem_cast<QGraphicsTextItem *>(item), (QGraphicsTextItem *)item);
538             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
539             // This is the only item that uses an extended style option.
540             QCOMPARE(item->flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
541             break;
542         default:
543             qFatal("You broke the logic, please fix!");
544             break;
545         }
546
547         QCOMPARE(item->scene(), (QGraphicsScene *)0);
548         QCOMPARE(item->parentItem(), (QGraphicsItem *)0);
549         QVERIFY(item->children().isEmpty());
550         QVERIFY(item->isVisible());
551         QVERIFY(item->isEnabled());
552         QVERIFY(!item->isSelected());
553         QCOMPARE(item->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
554         if (item->type() == QGraphicsTextItem::Type)
555             QVERIFY(item->acceptsHoverEvents());
556         else
557             QVERIFY(!item->acceptsHoverEvents());
558         QVERIFY(!item->hasFocus());
559         QCOMPARE(item->pos(), QPointF());
560         QCOMPARE(item->matrix(), QMatrix());
561         QCOMPARE(item->sceneMatrix(), QMatrix());
562         QCOMPARE(item->zValue(), qreal(0));
563         QCOMPARE(item->sceneBoundingRect(), QRectF());
564         QCOMPARE(item->shape(), QPainterPath());
565         QVERIFY(!item->contains(QPointF(0, 0)));
566         QVERIFY(!item->collidesWithItem(0));
567         QVERIFY(item->collidesWithItem(item));
568         QVERIFY(!item->collidesWithPath(QPainterPath()));
569         QVERIFY(!item->isAncestorOf(0));
570         QVERIFY(!item->isAncestorOf(item));
571         QCOMPARE(item->data(0), QVariant());
572         delete item;
573     }
574 }
575
576 class BoundingRectItem : public QGraphicsRectItem
577 {
578 public:
579     BoundingRectItem(QGraphicsItem *parent = 0)
580         : QGraphicsRectItem(0, 0, parent ? 200 : 100, parent ? 200 : 100,
581                             parent)
582     {}
583
584     QRectF boundingRect() const
585     {
586         QRectF tmp = QGraphicsRectItem::boundingRect();
587         foreach (QGraphicsItem *child, children())
588             tmp |= child->boundingRect(); // <- might be pure virtual
589         return tmp;
590     }
591 };
592
593 void tst_QGraphicsItem::constructionWithParent()
594 {
595     // This test causes a crash if item1 calls item2's pure virtuals before the
596     // object has been constructed.
597     QGraphicsItem *item0 = new BoundingRectItem;
598     QGraphicsItem *item1 = new BoundingRectItem;
599     QGraphicsScene scene;
600     scene.addItem(item0);
601     scene.addItem(item1);
602     QGraphicsItem *item2 = new BoundingRectItem(item1);
603     QCOMPARE(item1->children(), QList<QGraphicsItem *>() << item2);
604     QCOMPARE(item1->boundingRect(), QRectF(0, 0, 200, 200));
605
606     item2->setParentItem(item0);
607     QCOMPARE(item0->children(), QList<QGraphicsItem *>() << item2);
608     QCOMPARE(item0->boundingRect(), QRectF(0, 0, 200, 200));
609 }
610
611 static int itemDeleted = 0;
612 class Item : public QGraphicsRectItem
613 {
614 public:
615     ~Item()
616     { ++itemDeleted; }
617 };
618
619 void tst_QGraphicsItem::destruction()
620 {
621     QCOMPARE(itemDeleted, 0);
622     {
623         QGraphicsItem *parent = new QGraphicsRectItem;
624         Item *child = new Item;
625         child->setParentItem(parent);
626         QCOMPARE(child->parentItem(), parent);
627         delete parent;
628         QCOMPARE(itemDeleted, 1);
629     }
630     {
631         QGraphicsItem *parent = new QGraphicsRectItem;
632         Item *child = new Item;
633         child->setParentItem(parent);
634         QCOMPARE(parent->children().size(), 1);
635         delete child;
636         QCOMPARE(parent->children().size(), 0);
637         delete parent;
638         QCOMPARE(itemDeleted, 2);
639     }
640     {
641         QGraphicsScene scene;
642         QGraphicsItem *parent = new QGraphicsRectItem;
643         Item *child = new Item;
644         QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
645         child->setParentItem(parent);
646         QCOMPARE(child->parentItem(), parent);
647         scene.addItem(parent);
648         QCOMPARE(child->parentItem(), parent);
649         delete parent;
650         QCOMPARE(itemDeleted, 3);
651     }
652     {
653         QGraphicsScene scene;
654         QGraphicsItem *parent = new QGraphicsRectItem;
655         Item *child = new Item;
656         child->setParentItem(parent);
657         scene.addItem(parent);
658         QCOMPARE(child->scene(), &scene);
659         QCOMPARE(parent->children().size(), 1);
660         delete child;
661         QCOMPARE(parent->children().size(), 0);
662         delete parent;
663         QCOMPARE(itemDeleted, 4);
664     }
665     {
666         QGraphicsScene scene;
667         QGraphicsItem *parent = new QGraphicsRectItem;
668         Item *child = new Item;
669         child->setParentItem(parent);
670         scene.addItem(parent);
671         QCOMPARE(child->scene(), &scene);
672         scene.removeItem(parent);
673         QCOMPARE(child->scene(), (QGraphicsScene *)0);
674         delete parent;
675         QCOMPARE(itemDeleted, 5);
676     }
677     {
678         QGraphicsScene scene;
679         QGraphicsItem *parent = new QGraphicsRectItem;
680         Item *child = new Item;
681         child->setParentItem(parent);
682         QCOMPARE(child->scene(), (QGraphicsScene *)0);
683         QCOMPARE(parent->scene(), (QGraphicsScene *)0);
684         scene.addItem(parent);
685         QCOMPARE(child->scene(), &scene);
686         scene.removeItem(child);
687         QCOMPARE(child->scene(), (QGraphicsScene *)0);
688         QCOMPARE(parent->scene(), &scene);
689         QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
690         QVERIFY(parent->children().isEmpty());
691         delete parent;
692         QCOMPARE(itemDeleted, 5);
693         delete child;
694         QCOMPARE(itemDeleted, 6);
695     }
696     {
697         QGraphicsScene scene;
698         QGraphicsItem *parent = new QGraphicsRectItem;
699         Item *child = new Item;
700         child->setParentItem(parent);
701         scene.addItem(parent);
702         scene.removeItem(child);
703         scene.removeItem(parent);
704         delete child;
705         delete parent;
706         QCOMPARE(itemDeleted, 7);
707     }
708     {
709         QGraphicsScene scene;
710         QGraphicsItem *parent = new QGraphicsRectItem;
711         Item *child = new Item;
712         child->setParentItem(parent);
713         scene.addItem(parent);
714         QGraphicsScene scene2;
715         scene2.addItem(parent);
716         delete parent;
717         QCOMPARE(itemDeleted, 8);
718     }
719     {
720         QGraphicsScene scene;
721         QGraphicsItem *parent = new QGraphicsRectItem;
722         Item *child = new Item;
723         child->setParentItem(parent);
724         scene.addItem(parent);
725         QCOMPARE(child->scene(), &scene);
726         QGraphicsScene scene2;
727         scene2.addItem(parent);
728         QCOMPARE(child->scene(), &scene2);
729         scene.addItem(parent);
730         QCOMPARE(child->scene(), &scene);
731         scene2.addItem(parent);
732         QCOMPARE(child->scene(), &scene2);
733         delete parent;
734         QCOMPARE(itemDeleted, 9);
735     }
736     {
737         QGraphicsScene scene;
738         QGraphicsItem *parent = new QGraphicsRectItem;
739         Item *child = new Item;
740         child->setParentItem(parent);
741         scene.addItem(parent);
742         QCOMPARE(child->scene(), &scene);
743         QGraphicsScene scene2;
744         scene2.addItem(child);
745         QCOMPARE(child->scene(), &scene2);
746         delete parent;
747         QCOMPARE(itemDeleted, 9);
748         delete child;
749         QCOMPARE(itemDeleted, 10);
750     }
751     {
752         QGraphicsScene scene;
753         QGraphicsItem *root = new QGraphicsRectItem;
754         QGraphicsItem *parent = root;
755         QGraphicsItem *middleItem = 0;
756         for (int i = 0; i < 99; ++i) {
757             Item *child = new Item;
758             child->setParentItem(parent);
759             parent = child;
760             if (i == 50)
761                 middleItem = parent;
762         }
763         scene.addItem(root);
764
765         QCOMPARE(scene.items().size(), 100);
766
767         QGraphicsScene scene2;
768         scene2.addItem(middleItem);
769
770         delete middleItem;
771         QCOMPARE(itemDeleted, 59);
772     }
773     QCOMPARE(itemDeleted, 109);
774     {
775         QGraphicsScene *scene = new QGraphicsScene;
776         QGraphicsRectItem *parent = new QGraphicsRectItem;
777         Item *child = new Item;
778         child->setParentItem(parent);
779         parent->setVisible(false);
780         scene->addItem(parent);
781         QCOMPARE(child->parentItem(), static_cast<QGraphicsItem*>(parent));
782         delete scene;
783         QCOMPARE(itemDeleted, 110);
784     }
785 }
786
787 void tst_QGraphicsItem::deleteChildItem()
788 {
789     QGraphicsScene scene;
790     QGraphicsItem *rect = scene.addRect(QRectF());
791     QGraphicsItem *child1 = new QGraphicsRectItem(rect);
792     QGraphicsItem *child2 = new QGraphicsRectItem(rect);
793     QGraphicsItem *child3 = new QGraphicsRectItem(rect);
794     Q_UNUSED(child3);
795     delete child1;
796     child2->setParentItem(0);
797     delete child2;
798 }
799
800 void tst_QGraphicsItem::scene()
801 {
802     QGraphicsRectItem *item = new QGraphicsRectItem;
803     QCOMPARE(item->scene(), (QGraphicsScene *)0);
804
805     QGraphicsScene scene;
806     scene.addItem(item);
807     QCOMPARE(item->scene(), (QGraphicsScene *)&scene);
808
809     QGraphicsScene scene2;
810     scene2.addItem(item);
811     QCOMPARE(item->scene(), (QGraphicsScene *)&scene2);
812
813     scene2.removeItem(item);
814     QCOMPARE(item->scene(), (QGraphicsScene *)0);
815
816     delete item;
817 }
818
819 void tst_QGraphicsItem::parentItem()
820 {
821     QGraphicsRectItem item;
822     QCOMPARE(item.parentItem(), (QGraphicsItem *)0);
823
824     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
825     QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
826     item2->setParentItem(&item);
827     QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
828     item2->setParentItem(0);
829     QCOMPARE(item2->parentItem(), (QGraphicsItem *)0);
830
831     delete item2;
832 }
833
834 void tst_QGraphicsItem::setParentItem()
835 {
836     QGraphicsScene scene;
837     QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10));
838     QCOMPARE(item->scene(), &scene);
839
840     QGraphicsRectItem *child = new QGraphicsRectItem;
841     QCOMPARE(child->scene(), (QGraphicsScene *)0);
842
843     // This implicitly adds the item to the parent's scene
844     child->setParentItem(item);
845     QCOMPARE(child->scene(), &scene);
846
847     // This just makes it a toplevel
848     child->setParentItem(0);
849     QCOMPARE(child->scene(), &scene);
850
851     // Add the child back to the parent, then remove the parent from the scene
852     child->setParentItem(item);
853     scene.removeItem(item);
854     QCOMPARE(child->scene(), (QGraphicsScene *)0);
855 }
856
857 void tst_QGraphicsItem::children()
858 {
859     QGraphicsRectItem item;
860     QVERIFY(item.children().isEmpty());
861
862     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
863     QCOMPARE(item.children().size(), 1);
864     QCOMPARE(item.children().first(), (QGraphicsItem *)item2);
865     QVERIFY(item2->children().isEmpty());
866
867     delete item2;
868     QVERIFY(item.children().isEmpty());
869 }
870
871 void tst_QGraphicsItem::flags()
872 {
873     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
874     QCOMPARE(item->flags(), 0);
875
876     QGraphicsScene scene;
877     QEvent activate(QEvent::WindowActivate);
878     QApplication::sendEvent(&scene, &activate);
879
880     scene.addItem(item);
881
882     {
883         // Focus
884         item->setFlag(QGraphicsItem::ItemIsFocusable, false);
885         QVERIFY(!item->hasFocus());
886         item->setFocus();
887         QVERIFY(!item->hasFocus());
888
889         item->setFlag(QGraphicsItem::ItemIsFocusable, true);
890         QVERIFY(!item->hasFocus());
891         item->setFocus();
892         QVERIFY(item->hasFocus());
893         QVERIFY(scene.hasFocus());
894
895         item->setFlag(QGraphicsItem::ItemIsFocusable, false);
896         QVERIFY(!item->hasFocus());
897         QVERIFY(scene.hasFocus());
898     }
899     {
900         // Selectable
901         item->setFlag(QGraphicsItem::ItemIsSelectable, false);
902         QVERIFY(!item->isSelected());
903         item->setSelected(true);
904         QVERIFY(!item->isSelected());
905
906         item->setFlag(QGraphicsItem::ItemIsSelectable, true);
907         QVERIFY(!item->isSelected());
908         item->setSelected(true);
909         QVERIFY(item->isSelected());
910         item->setFlag(QGraphicsItem::ItemIsSelectable, false);
911         QVERIFY(!item->isSelected());
912     }
913     {
914         // Movable
915         item->setFlag(QGraphicsItem::ItemIsMovable, false);
916         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
917         event.setScenePos(QPointF(0, 0));
918         event.setButton(Qt::LeftButton);
919         event.setButtons(Qt::LeftButton);
920         QApplication::sendEvent(&scene, &event);
921         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); // mouse grabber is reset
922
923         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
924         event2.setScenePos(QPointF(10, 10));
925         event2.setButton(Qt::LeftButton);
926         event2.setButtons(Qt::LeftButton);
927         QApplication::sendEvent(&scene, &event2);
928         QCOMPARE(item->pos(), QPointF());
929
930         QGraphicsSceneMouseEvent event3(QEvent::GraphicsSceneMouseRelease);
931         event3.setScenePos(QPointF(10, 10));
932         event3.setButtons(0);
933         QApplication::sendEvent(&scene, &event3);
934         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
935
936         item->setFlag(QGraphicsItem::ItemIsMovable, true);
937         QGraphicsSceneMouseEvent event4(QEvent::GraphicsSceneMousePress);
938         event4.setScenePos(QPointF(0, 0));
939         event4.setButton(Qt::LeftButton);
940         event4.setButtons(Qt::LeftButton);
941         QApplication::sendEvent(&scene, &event4);
942         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
943         QGraphicsSceneMouseEvent event5(QEvent::GraphicsSceneMouseMove);
944         event5.setScenePos(QPointF(10, 10));
945         event5.setButton(Qt::LeftButton);
946         event5.setButtons(Qt::LeftButton);
947         QApplication::sendEvent(&scene, &event5);
948         QCOMPARE(item->pos(), QPointF(10, 10));
949     }
950     {
951         QGraphicsItem* clippingParent = new QGraphicsRectItem;
952         clippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
953
954         QGraphicsItem* nonClippingParent = new QGraphicsRectItem;
955         nonClippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
956
957         QGraphicsItem* child = new QGraphicsRectItem(nonClippingParent);
958         QVERIFY(!child->isClipped());
959
960         child->setParentItem(clippingParent);
961         QVERIFY(child->isClipped());
962
963         child->setParentItem(nonClippingParent);
964         QVERIFY(!child->isClipped());
965     }
966 }
967
968 class ImhTester : public QGraphicsItem
969 {
970     QRectF boundingRect() const { return QRectF(); }
971     void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
972 };
973
974 void tst_QGraphicsItem::inputMethodHints()
975 {
976     ImhTester *item = new ImhTester;
977     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
978     item->setFlag(QGraphicsItem::ItemIsFocusable, true);
979     QCOMPARE(item->inputMethodHints(), Qt::ImhNone);
980     ImhTester *item2 = new ImhTester;
981     item2->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
982     item2->setFlag(QGraphicsItem::ItemIsFocusable, true);
983     Qt::InputMethodHints imHints = item2->inputMethodHints();
984     imHints |= Qt::ImhHiddenText;
985     item2->setInputMethodHints(imHints);
986     QGraphicsScene scene;
987     scene.addItem(item);
988     scene.addItem(item2);
989     QGraphicsView view(&scene);
990     QApplication::setActiveWindow(&view);
991     view.show();
992     QVERIFY(QTest::qWaitForWindowActive(&view));
993     item->setFocus();
994     QTRY_VERIFY(item->hasFocus());
995     QCOMPARE(view.inputMethodHints(), item->inputMethodHints());
996     item2->setFocus();
997     QTRY_VERIFY(item2->hasFocus());
998     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
999     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, false);
1000     item->setFocus();
1001     QTRY_VERIFY(item->hasFocus());
1002     //Focus has changed but the new item doesn't accept input method, no hints.
1003     QCOMPARE(view.inputMethodHints(), 0);
1004     item2->setFocus();
1005     QTRY_VERIFY(item2->hasFocus());
1006     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1007     imHints = item2->inputMethodHints();
1008     imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
1009     item2->setInputMethodHints(imHints);
1010     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1011     QGraphicsProxyWidget *widget = new QGraphicsProxyWidget;
1012     QLineEdit *edit = new QLineEdit;
1013     edit->setEchoMode(QLineEdit::Password);
1014     scene.addItem(widget);
1015     widget->setFocus();
1016     QTRY_VERIFY(widget->hasFocus());
1017     //No widget on the proxy, so no hints
1018     QCOMPARE(view.inputMethodHints(), 0);
1019     widget->setWidget(edit);
1020     //View should match with the line edit
1021     QCOMPARE(view.inputMethodHints(), edit->inputMethodHints());
1022 }
1023
1024 void tst_QGraphicsItem::toolTip()
1025 {
1026     QString toolTip = "Qt rocks!";
1027
1028     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
1029     item->setPen(QPen(Qt::red, 1));
1030     item->setBrush(QBrush(Qt::blue));
1031     QVERIFY(item->toolTip().isEmpty());
1032     item->setToolTip(toolTip);
1033     QCOMPARE(item->toolTip(), toolTip);
1034
1035     QGraphicsScene scene;
1036     scene.addItem(item);
1037
1038     QGraphicsView view(&scene);
1039     view.setFixedSize(200, 200);
1040     view.show();
1041     QApplication::setActiveWindow(&view);
1042     QVERIFY(QTest::qWaitForWindowActive(&view));
1043     {
1044         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
1045                              view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
1046         QApplication::sendEvent(view.viewport(), &helpEvent);
1047         QTest::qWait(250);
1048
1049         bool foundView = false;
1050         bool foundTipLabel = false;
1051         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1052             if (widget == &view)
1053                 foundView = true;
1054             if (widget->inherits("QTipLabel"))
1055                 foundTipLabel = true;
1056         }
1057         QVERIFY(foundView);
1058         QVERIFY(!foundTipLabel);
1059     }
1060
1061     {
1062         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().center(),
1063                              view.viewport()->mapToGlobal(view.viewport()->rect().center()));
1064         QApplication::sendEvent(view.viewport(), &helpEvent);
1065         QTest::qWait(250);
1066
1067         bool foundView = false;
1068         bool foundTipLabel = false;
1069         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1070             if (widget == &view)
1071                 foundView = true;
1072             if (widget->inherits("QTipLabel"))
1073                 foundTipLabel = true;
1074         }
1075         QVERIFY(foundView);
1076         QVERIFY(foundTipLabel);
1077     }
1078
1079     {
1080         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
1081                              view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
1082         QApplication::sendEvent(view.viewport(), &helpEvent);
1083         QTest::qWait(1000);
1084
1085         bool foundView = false;
1086         bool foundTipLabel = false;
1087         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1088             if (widget == &view)
1089                 foundView = true;
1090             if (widget->inherits("QTipLabel") && widget->isVisible())
1091                 foundTipLabel = true;
1092         }
1093         QVERIFY(foundView);
1094         QVERIFY(!foundTipLabel);
1095     }
1096 }
1097
1098 void tst_QGraphicsItem::visible()
1099 {
1100     QGraphicsItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
1101     item->setFlag(QGraphicsItem::ItemIsMovable);
1102     QVERIFY(item->isVisible());
1103     item->setVisible(false);
1104     QVERIFY(!item->isVisible());
1105     item->setVisible(true);
1106     QVERIFY(item->isVisible());
1107
1108     QGraphicsScene scene;
1109     QEvent activate(QEvent::WindowActivate);
1110     QApplication::sendEvent(&scene, &activate);
1111
1112     scene.addItem(item);
1113     QVERIFY(item->isVisible());
1114     QCOMPARE(scene.itemAt(0, 0), item);
1115     item->setVisible(false);
1116     QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)0);
1117     item->setVisible(true);
1118     QCOMPARE(scene.itemAt(0, 0), item);
1119
1120     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1121     event.setButton(Qt::LeftButton);
1122     event.setScenePos(QPointF(0, 0));
1123     QApplication::sendEvent(&scene, &event);
1124     QCOMPARE(scene.mouseGrabberItem(), item);
1125     item->setVisible(false);
1126     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1127     item->setVisible(true);
1128     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1129
1130     item->setFlag(QGraphicsItem::ItemIsFocusable);
1131     item->setFocus();
1132     QVERIFY(item->hasFocus());
1133     item->setVisible(false);
1134     QVERIFY(!item->hasFocus());
1135     item->setVisible(true);
1136     QVERIFY(!item->hasFocus());
1137 }
1138
1139 void tst_QGraphicsItem::isVisibleTo()
1140 {
1141     QGraphicsScene scene;
1142     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1143     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1144     QGraphicsItem *grandChild = scene.addRect(QRectF(50, 50, 50, 50));
1145     QGraphicsItem *stranger = scene.addRect(100, 100, 100, 100);
1146
1147     child->setParentItem(parent);
1148     grandChild->setParentItem(child);
1149
1150     QVERIFY(grandChild->isVisible());
1151     QVERIFY(grandChild->isVisibleTo(grandChild));
1152     QVERIFY(grandChild->isVisibleTo(child));
1153     QVERIFY(grandChild->isVisibleTo(parent));
1154     QVERIFY(grandChild->isVisibleTo(0));
1155     QVERIFY(child->isVisible());
1156     QVERIFY(child->isVisibleTo(child));
1157     QVERIFY(child->isVisibleTo(parent));
1158     QVERIFY(child->isVisibleTo(0));
1159     QVERIFY(parent->isVisible());
1160     QVERIFY(parent->isVisibleTo(parent));
1161     QVERIFY(parent->isVisibleTo(0));
1162     QVERIFY(!parent->isVisibleTo(child));
1163     QVERIFY(!child->isVisibleTo(grandChild));
1164     QVERIFY(!grandChild->isVisibleTo(stranger));
1165     QVERIFY(!child->isVisibleTo(stranger));
1166     QVERIFY(!parent->isVisibleTo(stranger));
1167     QVERIFY(!stranger->isVisibleTo(grandChild));
1168     QVERIFY(!stranger->isVisibleTo(child));
1169     QVERIFY(!stranger->isVisibleTo(parent));
1170
1171     // Case 1: only parent is explicitly hidden
1172     parent->hide();
1173
1174     QVERIFY(!grandChild->isVisible());
1175     QVERIFY(grandChild->isVisibleTo(grandChild));
1176     QVERIFY(grandChild->isVisibleTo(child));
1177     QVERIFY(grandChild->isVisibleTo(parent));
1178     QVERIFY(!grandChild->isVisibleTo(0));
1179     QVERIFY(!child->isVisible());
1180     QVERIFY(child->isVisibleTo(child));
1181     QVERIFY(child->isVisibleTo(parent));
1182     QVERIFY(!child->isVisibleTo(0));
1183     QVERIFY(!parent->isVisible());
1184     QVERIFY(!parent->isVisibleTo(parent));
1185     QVERIFY(!parent->isVisibleTo(0));
1186     QVERIFY(!parent->isVisibleTo(child));
1187     QVERIFY(!child->isVisibleTo(grandChild));
1188     QVERIFY(!grandChild->isVisibleTo(stranger));
1189     QVERIFY(!child->isVisibleTo(stranger));
1190     QVERIFY(!parent->isVisibleTo(stranger));
1191     QVERIFY(!stranger->isVisibleTo(grandChild));
1192     QVERIFY(!stranger->isVisibleTo(child));
1193     QVERIFY(!stranger->isVisibleTo(parent));
1194
1195     // Case 2: only child is hidden
1196     parent->show();
1197     child->hide();
1198
1199     QVERIFY(!grandChild->isVisible());
1200     QVERIFY(grandChild->isVisibleTo(grandChild));
1201     QVERIFY(grandChild->isVisibleTo(child));
1202     QVERIFY(!grandChild->isVisibleTo(parent));
1203     QVERIFY(!grandChild->isVisibleTo(0));
1204     QVERIFY(!child->isVisible());
1205     QVERIFY(!child->isVisibleTo(child));
1206     QVERIFY(!child->isVisibleTo(parent));
1207     QVERIFY(!child->isVisibleTo(0));
1208     QVERIFY(parent->isVisible());
1209     QVERIFY(parent->isVisibleTo(parent));
1210     QVERIFY(parent->isVisibleTo(0));
1211     QVERIFY(!parent->isVisibleTo(child));
1212     QVERIFY(!child->isVisibleTo(grandChild));
1213     QVERIFY(!grandChild->isVisibleTo(stranger));
1214     QVERIFY(!child->isVisibleTo(stranger));
1215     QVERIFY(!parent->isVisibleTo(stranger));
1216     QVERIFY(!stranger->isVisibleTo(grandChild));
1217     QVERIFY(!stranger->isVisibleTo(child));
1218     QVERIFY(!stranger->isVisibleTo(parent));
1219
1220     // Case 3: only grand child is hidden
1221     child->show();
1222     grandChild->hide();
1223
1224     QVERIFY(!grandChild->isVisible());
1225     QVERIFY(!grandChild->isVisibleTo(grandChild));
1226     QVERIFY(!grandChild->isVisibleTo(child));
1227     QVERIFY(!grandChild->isVisibleTo(parent));
1228     QVERIFY(!grandChild->isVisibleTo(0));
1229     QVERIFY(child->isVisible());
1230     QVERIFY(child->isVisibleTo(child));
1231     QVERIFY(child->isVisibleTo(parent));
1232     QVERIFY(child->isVisibleTo(0));
1233     QVERIFY(parent->isVisible());
1234     QVERIFY(parent->isVisibleTo(parent));
1235     QVERIFY(parent->isVisibleTo(0));
1236     QVERIFY(!parent->isVisibleTo(child));
1237     QVERIFY(!child->isVisibleTo(grandChild));
1238     QVERIFY(!grandChild->isVisibleTo(stranger));
1239     QVERIFY(!child->isVisibleTo(stranger));
1240     QVERIFY(!parent->isVisibleTo(stranger));
1241     QVERIFY(!stranger->isVisibleTo(grandChild));
1242     QVERIFY(!stranger->isVisibleTo(child));
1243     QVERIFY(!stranger->isVisibleTo(parent));
1244 }
1245
1246 void tst_QGraphicsItem::explicitlyVisible()
1247 {
1248     QGraphicsScene scene;
1249     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1250     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1251     child->setParentItem(parent);
1252
1253     QVERIFY(parent->isVisible());
1254     QVERIFY(child->isVisible());
1255
1256     parent->hide();
1257
1258     QVERIFY(!parent->isVisible());
1259     QVERIFY(!child->isVisible());
1260
1261     parent->show();
1262     child->hide();
1263
1264     QVERIFY(parent->isVisible());
1265     QVERIFY(!child->isVisible());
1266
1267     parent->hide();
1268
1269     QVERIFY(!parent->isVisible());
1270     QVERIFY(!child->isVisible());
1271
1272     parent->show();
1273
1274     QVERIFY(parent->isVisible());
1275     QVERIFY(!child->isVisible()); // <- explicitly hidden
1276
1277     child->show();
1278
1279     QVERIFY(child->isVisible());
1280
1281     parent->hide();
1282
1283     QVERIFY(!parent->isVisible());
1284     QVERIFY(!child->isVisible()); // <- explicit show doesn't work
1285
1286     parent->show();
1287
1288     QVERIFY(parent->isVisible());
1289     QVERIFY(child->isVisible()); // <- no longer explicitly hidden
1290
1291     // ------------------- Reparenting ------------------------------
1292
1293     QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
1294     QVERIFY(parent2->isVisible());
1295
1296     // Reparent implicitly hidden item to a visible parent.
1297     parent->hide();
1298     QVERIFY(!parent->isVisible());
1299     QVERIFY(!child->isVisible());
1300     child->setParentItem(parent2);
1301     QVERIFY(parent2->isVisible());
1302     QVERIFY(child->isVisible());
1303
1304     // Reparent implicitly hidden item to a hidden parent.
1305     child->setParentItem(parent);
1306     parent2->hide();
1307     child->setParentItem(parent2);
1308     QVERIFY(!parent2->isVisible());
1309     QVERIFY(!child->isVisible());
1310
1311     // Reparent explicitly hidden item to a visible parent.
1312     child->hide();
1313     parent->show();
1314     child->setParentItem(parent);
1315     QVERIFY(parent->isVisible());
1316     QVERIFY(!child->isVisible());
1317
1318     // Reparent explicitly hidden item to a hidden parent.
1319     child->setParentItem(parent2);
1320     QVERIFY(!parent2->isVisible());
1321     QVERIFY(!child->isVisible());
1322
1323     // Reparent explicitly hidden item to a visible parent.
1324     parent->show();
1325     child->setParentItem(parent);
1326     QVERIFY(parent->isVisible());
1327     QVERIFY(!child->isVisible());
1328
1329     // Reparent visible item to a hidden parent.
1330     child->show();
1331     parent2->hide();
1332     child->setParentItem(parent2);
1333     QVERIFY(!parent2->isVisible());
1334     QVERIFY(!child->isVisible());
1335     parent2->show();
1336     QVERIFY(parent2->isVisible());
1337     QVERIFY(child->isVisible());
1338
1339     // Reparent implicitly hidden child to root.
1340     parent2->hide();
1341     QVERIFY(!child->isVisible());
1342     child->setParentItem(0);
1343     QVERIFY(child->isVisible());
1344
1345     // Reparent an explicitly hidden child to root.
1346     child->hide();
1347     child->setParentItem(parent2);
1348     parent2->show();
1349     QVERIFY(!child->isVisible());
1350     child->setParentItem(0);
1351     QVERIFY(!child->isVisible());
1352 }
1353
1354 void tst_QGraphicsItem::enabled()
1355 {
1356     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
1357     item->setFlag(QGraphicsItem::ItemIsMovable);
1358     QVERIFY(item->isEnabled());
1359     item->setEnabled(false);
1360     QVERIFY(!item->isEnabled());
1361     item->setEnabled(true);
1362     QVERIFY(item->isEnabled());
1363     item->setEnabled(false);
1364     item->setFlag(QGraphicsItem::ItemIsFocusable);
1365     QGraphicsScene scene;
1366     QEvent activate(QEvent::WindowActivate);
1367     QApplication::sendEvent(&scene, &activate);
1368
1369     scene.addItem(item);
1370     item->setFocus();
1371     QVERIFY(!item->hasFocus());
1372     item->setEnabled(true);
1373     item->setFocus();
1374     QVERIFY(item->hasFocus());
1375     item->setEnabled(false);
1376     QVERIFY(!item->hasFocus());
1377
1378     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1379     event.setButton(Qt::LeftButton);
1380     event.setScenePos(QPointF(0, 0));
1381     QApplication::sendEvent(&scene, &event);
1382     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1383     item->setEnabled(true);
1384     QApplication::sendEvent(&scene, &event);
1385     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
1386     item->setEnabled(false);
1387     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1388 }
1389
1390 void tst_QGraphicsItem::explicitlyEnabled()
1391 {
1392     QGraphicsScene scene;
1393     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1394     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1395     child->setParentItem(parent);
1396
1397     QVERIFY(parent->isEnabled());
1398     QVERIFY(child->isEnabled());
1399
1400     parent->setEnabled(false);
1401
1402     QVERIFY(!parent->isEnabled());
1403     QVERIFY(!child->isEnabled());
1404
1405     parent->setEnabled(true);
1406     child->setEnabled(false);
1407
1408     QVERIFY(parent->isEnabled());
1409     QVERIFY(!child->isEnabled());
1410
1411     parent->setEnabled(false);
1412
1413     QVERIFY(!parent->isEnabled());
1414     QVERIFY(!child->isEnabled());
1415
1416     parent->setEnabled(true);
1417
1418     QVERIFY(parent->isEnabled());
1419     QVERIFY(!child->isEnabled()); // <- explicitly disabled
1420
1421     child->setEnabled(true);
1422
1423     QVERIFY(child->isEnabled());
1424
1425     parent->setEnabled(false);
1426
1427     QVERIFY(!parent->isEnabled());
1428     QVERIFY(!child->isEnabled()); // <- explicit enabled doesn't work
1429
1430     parent->setEnabled(true);
1431
1432     QVERIFY(parent->isEnabled());
1433     QVERIFY(child->isEnabled()); // <- no longer explicitly disabled
1434
1435     // ------------------- Reparenting ------------------------------
1436
1437     QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
1438     QVERIFY(parent2->isEnabled());
1439
1440     // Reparent implicitly hidden item to a enabled parent.
1441     parent->setEnabled(false);
1442     QVERIFY(!parent->isEnabled());
1443     QVERIFY(!child->isEnabled());
1444     child->setParentItem(parent2);
1445     QVERIFY(parent2->isEnabled());
1446     QVERIFY(child->isEnabled());
1447
1448     // Reparent implicitly hidden item to a hidden parent.
1449     child->setParentItem(parent);
1450     parent2->setEnabled(false);
1451     child->setParentItem(parent2);
1452     QVERIFY(!parent2->isEnabled());
1453     QVERIFY(!child->isEnabled());
1454
1455     // Reparent explicitly hidden item to a enabled parent.
1456     child->setEnabled(false);
1457     parent->setEnabled(true);
1458     child->setParentItem(parent);
1459     QVERIFY(parent->isEnabled());
1460     QVERIFY(!child->isEnabled());
1461
1462     // Reparent explicitly hidden item to a hidden parent.
1463     child->setParentItem(parent2);
1464     QVERIFY(!parent2->isEnabled());
1465     QVERIFY(!child->isEnabled());
1466
1467     // Reparent explicitly hidden item to a enabled parent.
1468     parent->setEnabled(true);
1469     child->setParentItem(parent);
1470     QVERIFY(parent->isEnabled());
1471     QVERIFY(!child->isEnabled());
1472
1473     // Reparent enabled item to a hidden parent.
1474     child->setEnabled(true);
1475     parent2->setEnabled(false);
1476     child->setParentItem(parent2);
1477     QVERIFY(!parent2->isEnabled());
1478     QVERIFY(!child->isEnabled());
1479     parent2->setEnabled(true);
1480     QVERIFY(parent2->isEnabled());
1481     QVERIFY(child->isEnabled());
1482
1483     // Reparent implicitly hidden child to root.
1484     parent2->setEnabled(false);
1485     QVERIFY(!child->isEnabled());
1486     child->setParentItem(0);
1487     QVERIFY(child->isEnabled());
1488
1489     // Reparent an explicitly hidden child to root.
1490     child->setEnabled(false);
1491     child->setParentItem(parent2);
1492     parent2->setEnabled(true);
1493     QVERIFY(!child->isEnabled());
1494     child->setParentItem(0);
1495     QVERIFY(!child->isEnabled());
1496 }
1497
1498 class SelectChangeItem : public QGraphicsRectItem
1499 {
1500 public:
1501     SelectChangeItem() : QGraphicsRectItem(-50, -50, 100, 100) { setBrush(Qt::blue); }
1502     QList<bool> values;
1503
1504 protected:
1505     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
1506     {
1507         if (change == ItemSelectedChange)
1508             values << value.toBool();
1509         return QGraphicsRectItem::itemChange(change, value);
1510     }
1511 };
1512
1513 void tst_QGraphicsItem::selected()
1514 {
1515     SelectChangeItem *item = new SelectChangeItem;
1516     item->setFlag(QGraphicsItem::ItemIsSelectable);
1517     QVERIFY(!item->isSelected());
1518     QVERIFY(item->values.isEmpty());
1519     item->setSelected(true);
1520     QCOMPARE(item->values.size(), 1);
1521     QCOMPARE(item->values.last(), true);
1522     QVERIFY(item->isSelected());
1523     item->setSelected(false);
1524     QCOMPARE(item->values.size(), 2);
1525     QCOMPARE(item->values.last(), false);
1526     QVERIFY(!item->isSelected());
1527     item->setSelected(true);
1528     QCOMPARE(item->values.size(), 3);
1529     item->setEnabled(false);
1530     QCOMPARE(item->values.size(), 4);
1531     QCOMPARE(item->values.last(), false);
1532     QVERIFY(!item->isSelected());
1533     item->setEnabled(true);
1534     QCOMPARE(item->values.size(), 4);
1535     item->setSelected(true);
1536     QCOMPARE(item->values.size(), 5);
1537     QCOMPARE(item->values.last(), true);
1538     QVERIFY(item->isSelected());
1539     item->setVisible(false);
1540     QCOMPARE(item->values.size(), 6);
1541     QCOMPARE(item->values.last(), false);
1542     QVERIFY(!item->isSelected());
1543     item->setVisible(true);
1544     QCOMPARE(item->values.size(), 6);
1545     item->setSelected(true);
1546     QCOMPARE(item->values.size(), 7);
1547     QCOMPARE(item->values.last(), true);
1548     QVERIFY(item->isSelected());
1549
1550     QGraphicsScene scene(-100, -100, 200, 200);
1551     scene.addItem(item);
1552     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
1553     item->setSelected(false);
1554     QVERIFY(scene.selectedItems().isEmpty());
1555     item->setSelected(true);
1556     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
1557     item->setSelected(false);
1558     QVERIFY(scene.selectedItems().isEmpty());
1559
1560     // Interactive selection
1561     QGraphicsView view(&scene);
1562     view.setFixedSize(250, 250);
1563     view.show();
1564
1565     QVERIFY(QTest::qWaitForWindowExposed(&view));
1566     qApp->processEvents();
1567     qApp->processEvents();
1568
1569     scene.clearSelection();
1570     QCOMPARE(item->values.size(), 10);
1571     QCOMPARE(item->values.last(), false);
1572     QVERIFY(!item->isSelected());
1573
1574     // Click inside and check that it's selected
1575     QTest::mouseMove(view.viewport());
1576     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
1577     QCOMPARE(item->values.size(), 11);
1578     QCOMPARE(item->values.last(), true);
1579     QVERIFY(item->isSelected());
1580
1581     // Click outside and check that it's not selected
1582     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos() + QPointF(item->boundingRect().width(), item->boundingRect().height())));
1583     QCOMPARE(item->values.size(), 12);
1584     QCOMPARE(item->values.last(), false);
1585     QVERIFY(!item->isSelected());
1586
1587     SelectChangeItem *item2 = new SelectChangeItem;
1588     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1589     item2->setPos(100, 0);
1590     scene.addItem(item2);
1591
1592     // Click inside and check that it's selected
1593     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
1594     QCOMPARE(item->values.size(), 13);
1595     QCOMPARE(item->values.last(), true);
1596     QVERIFY(item->isSelected());
1597
1598     // Click inside item2 and check that it's selected, and item is not
1599     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1600     QCOMPARE(item->values.size(), 14);
1601     QCOMPARE(item->values.last(), false);
1602     QVERIFY(!item->isSelected());
1603     QCOMPARE(item2->values.size(), 1);
1604     QCOMPARE(item2->values.last(), true);
1605     QVERIFY(item2->isSelected());
1606 }
1607
1608 void tst_QGraphicsItem::selected2()
1609 {
1610     // Selecting an item, then moving another previously caused a crash.
1611     QGraphicsScene scene;
1612     QGraphicsItem *line1 = scene.addRect(QRectF(0, 0, 100, 100));
1613     line1->setPos(-105, 0);
1614     line1->setFlag(QGraphicsItem::ItemIsSelectable);
1615
1616     QGraphicsItem *line2 = scene.addRect(QRectF(0, 0, 100, 100));
1617     line2->setFlag(QGraphicsItem::ItemIsMovable);
1618
1619     line1->setSelected(true);
1620
1621     {
1622         QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
1623         mousePress.setScenePos(QPointF(50, 50));
1624         mousePress.setButton(Qt::LeftButton);
1625         QApplication::sendEvent(&scene, &mousePress);
1626         QVERIFY(mousePress.isAccepted());
1627     }
1628     {
1629         QGraphicsSceneMouseEvent mouseMove(QEvent::GraphicsSceneMouseMove);
1630         mouseMove.setScenePos(QPointF(60, 60));
1631         mouseMove.setButton(Qt::LeftButton);
1632         mouseMove.setButtons(Qt::LeftButton);
1633         QApplication::sendEvent(&scene, &mouseMove);
1634         QVERIFY(mouseMove.isAccepted());
1635     }
1636 }
1637
1638 void tst_QGraphicsItem::selected_group()
1639 {
1640     QGraphicsScene scene;
1641     QGraphicsItem *item1 = scene.addRect(QRectF());
1642     QGraphicsItem *item2 = scene.addRect(QRectF());
1643     item1->setFlag(QGraphicsItem::ItemIsSelectable);
1644     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1645     scene.addRect(QRectF())->setParentItem(item1);
1646     QGraphicsItem *leaf = scene.addRect(QRectF());
1647     leaf->setFlag(QGraphicsItem::ItemIsSelectable);
1648     leaf->setParentItem(item2);
1649
1650     QGraphicsItemGroup *group = scene.createItemGroup(QList<QGraphicsItem *>() << item1 << item2);
1651     QCOMPARE(group->scene(), &scene);
1652     group->setFlag(QGraphicsItem::ItemIsSelectable);
1653     foreach (QGraphicsItem *item, scene.items()) {
1654         if (item == group)
1655             QVERIFY(!item->group());
1656         else
1657             QCOMPARE(item->group(), group);
1658     }
1659
1660     QVERIFY(group->handlesChildEvents());
1661     QVERIFY(!group->isSelected());
1662     group->setSelected(false);
1663     QVERIFY(!group->isSelected());
1664     group->setSelected(true);
1665     QVERIFY(group->isSelected());
1666     foreach (QGraphicsItem *item, scene.items())
1667         QVERIFY(item->isSelected());
1668     group->setSelected(false);
1669     QVERIFY(!group->isSelected());
1670     foreach (QGraphicsItem *item, scene.items())
1671         QVERIFY(!item->isSelected());
1672     leaf->setSelected(true);
1673     foreach (QGraphicsItem *item, scene.items())
1674         QVERIFY(item->isSelected());
1675     leaf->setSelected(false);
1676     foreach (QGraphicsItem *item, scene.items())
1677         QVERIFY(!item->isSelected());
1678
1679     leaf->setSelected(true);
1680     QGraphicsScene scene2;
1681     scene2.addItem(item1);
1682     QVERIFY(!item1->isSelected());
1683     QVERIFY(item2->isSelected());
1684 }
1685
1686 void tst_QGraphicsItem::selected_textItem()
1687 {
1688     QGraphicsScene scene;
1689     QGraphicsTextItem *text = scene.addText(QLatin1String("Text"));
1690     text->setFlag(QGraphicsItem::ItemIsSelectable);
1691
1692     QGraphicsView view(&scene);
1693     view.show();
1694     QVERIFY(QTest::qWaitForWindowExposed(&view));
1695     QTest::qWait(20);
1696
1697     QTRY_VERIFY(!text->isSelected());
1698     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
1699                       view.mapFromScene(text->mapToScene(0, 0)));
1700     QTRY_VERIFY(text->isSelected());
1701
1702     text->setSelected(false);
1703     text->setTextInteractionFlags(Qt::TextEditorInteraction);
1704
1705     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
1706                       view.mapFromScene(text->mapToScene(0, 0)));
1707     QTRY_VERIFY(text->isSelected());
1708 }
1709
1710 void tst_QGraphicsItem::selected_multi()
1711 {
1712     // Test multiselection behavior
1713     QGraphicsScene scene;
1714
1715     // Create two disjoint items
1716     QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
1717     QGraphicsItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
1718     item1->setPos(-15, 0);
1719     item2->setPos(15, 20);
1720
1721     // Make both items selectable
1722     item1->setFlag(QGraphicsItem::ItemIsSelectable);
1723     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1724
1725     // Create and show a view
1726     QGraphicsView view(&scene);
1727     view.show();
1728     view.fitInView(scene.sceneRect());
1729     qApp->processEvents();
1730
1731     QVERIFY(!item1->isSelected());
1732     QVERIFY(!item2->isSelected());
1733
1734     // Start clicking
1735     QTest::qWait(200);
1736
1737     // Click on item1
1738     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1739     QTest::qWait(20);
1740     QVERIFY(item1->isSelected());
1741     QVERIFY(!item2->isSelected());
1742
1743     // Click on item2
1744     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1745     QTest::qWait(20);
1746     QVERIFY(item2->isSelected());
1747     QVERIFY(!item1->isSelected());
1748
1749     // Ctrl-click on item1
1750     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1751     QTest::qWait(20);
1752     QVERIFY(item2->isSelected());
1753     QVERIFY(item1->isSelected());
1754
1755     // Ctrl-click on item1 again
1756     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1757     QTest::qWait(20);
1758     QVERIFY(item2->isSelected());
1759     QVERIFY(!item1->isSelected());
1760
1761     // Ctrl-click on item2
1762     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item2->scenePos()));
1763     QTest::qWait(20);
1764     QVERIFY(!item2->isSelected());
1765     QVERIFY(!item1->isSelected());
1766
1767     // Click on item1
1768     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1769     QTest::qWait(20);
1770     QVERIFY(item1->isSelected());
1771     QVERIFY(!item2->isSelected());
1772
1773     // Click on scene
1774     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(0, 0));
1775     QTest::qWait(20);
1776     QVERIFY(!item1->isSelected());
1777     QVERIFY(!item2->isSelected());
1778
1779     // Click on item1
1780     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1781     QTest::qWait(20);
1782     QVERIFY(item1->isSelected());
1783     QVERIFY(!item2->isSelected());
1784
1785     // Ctrl-click on scene
1786     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(0, 0));
1787     QTest::qWait(20);
1788     QVERIFY(!item1->isSelected());
1789     QVERIFY(!item2->isSelected());
1790
1791     // Click on item1
1792     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1793     QTest::qWait(20);
1794     QVERIFY(item1->isSelected());
1795     QVERIFY(!item2->isSelected());
1796
1797     // Press on item2
1798     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1799     QTest::qWait(20);
1800     QVERIFY(!item1->isSelected());
1801     QVERIFY(item2->isSelected());
1802
1803     // Release on item2
1804     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1805     QTest::qWait(20);
1806     QVERIFY(!item1->isSelected());
1807     QVERIFY(item2->isSelected());
1808
1809     // Click on item1
1810     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1811     QTest::qWait(20);
1812     QVERIFY(item1->isSelected());
1813     QVERIFY(!item2->isSelected());
1814
1815     // Ctrl-click on item1
1816     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1817     QTest::qWait(20);
1818     QVERIFY(!item1->isSelected());
1819     QVERIFY(!item2->isSelected());
1820
1821     // Ctrl-press on item1
1822     QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1823     QTest::qWait(20);
1824     QVERIFY(!item1->isSelected());
1825     QVERIFY(!item2->isSelected());
1826
1827     {
1828         // Ctrl-move on item1
1829         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
1830         QApplication::sendEvent(view.viewport(), &event);
1831         QTest::qWait(20);
1832         QVERIFY(!item1->isSelected());
1833         QVERIFY(!item2->isSelected());
1834     }
1835
1836     // Release on item1
1837     QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1838     QTest::qWait(20);
1839     QVERIFY(item1->isSelected());
1840     QVERIFY(!item2->isSelected());
1841
1842     item1->setFlag(QGraphicsItem::ItemIsMovable);
1843     item1->setSelected(false);
1844
1845     // Ctrl-press on item1
1846     QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1847     QTest::qWait(20);
1848     QVERIFY(!item1->isSelected());
1849     QVERIFY(!item2->isSelected());
1850
1851     {
1852         // Ctrl-move on item1
1853         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
1854         QApplication::sendEvent(view.viewport(), &event);
1855         QTest::qWait(20);
1856         QVERIFY(item1->isSelected());
1857         QVERIFY(!item2->isSelected());
1858     }
1859
1860     // Release on item1
1861     QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1862     QTest::qWait(20);
1863     QVERIFY(item1->isSelected());
1864     QVERIFY(!item2->isSelected());
1865 }
1866
1867 void tst_QGraphicsItem::acceptedMouseButtons()
1868 {
1869     QGraphicsScene scene;
1870     QGraphicsRectItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
1871     QGraphicsRectItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
1872     item2->setZValue(1);
1873
1874     item1->setFlag(QGraphicsItem::ItemIsMovable);
1875     item2->setFlag(QGraphicsItem::ItemIsMovable);
1876
1877     QCOMPARE(item1->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
1878     QCOMPARE(item2->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
1879
1880     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1881     event.setButton(Qt::LeftButton);
1882     event.setScenePos(QPointF(0, 0));
1883     QApplication::sendEvent(&scene, &event);
1884     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item2);
1885     item2->setAcceptedMouseButtons(0);
1886     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1887     QApplication::sendEvent(&scene, &event);
1888     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item1);
1889 }
1890
1891 class HoverItem : public QGraphicsRectItem
1892 {
1893 public:
1894     HoverItem(const QRectF &rect)
1895         : QGraphicsRectItem(rect), hoverInCount(0),
1896           hoverMoveCount(0), hoverOutCount(0)
1897     { }
1898
1899     int hoverInCount;
1900     int hoverMoveCount;
1901     int hoverOutCount;
1902 protected:
1903     void hoverEnterEvent(QGraphicsSceneHoverEvent *)
1904     { ++hoverInCount; }
1905
1906     void hoverMoveEvent(QGraphicsSceneHoverEvent *)
1907     { ++hoverMoveCount; }
1908
1909     void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
1910     { ++hoverOutCount; }
1911 };
1912
1913 void tst_QGraphicsItem::acceptsHoverEvents()
1914 {
1915     QGraphicsScene scene;
1916     HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
1917     HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
1918     scene.addItem(item1);
1919     scene.addItem(item2);
1920     item2->setZValue(1);
1921
1922     QVERIFY(!item1->acceptsHoverEvents());
1923     QVERIFY(!item2->acceptsHoverEvents());
1924     item1->setAcceptsHoverEvents(true);
1925     item2->setAcceptsHoverEvents(true);
1926
1927     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
1928     event.setScenePos(QPointF(-100, -100));
1929     QApplication::sendEvent(&scene, &event);
1930     event.setScenePos(QPointF(-2.5, -2.5));
1931     QApplication::sendEvent(&scene, &event);
1932
1933     QCOMPARE(item1->hoverInCount, 0);
1934     QCOMPARE(item2->hoverInCount, 1);
1935
1936     item1->setAcceptsHoverEvents(false);
1937     item2->setAcceptsHoverEvents(false);
1938
1939     event.setScenePos(QPointF(-100, -100));
1940     QApplication::sendEvent(&scene, &event);
1941     event.setScenePos(QPointF(-2.5, -2.5));
1942     QApplication::sendEvent(&scene, &event);
1943
1944     QCOMPARE(item1->hoverInCount, 0);
1945     QCOMPARE(item2->hoverInCount, 1);
1946
1947     item1->setAcceptsHoverEvents(true);
1948     item2->setAcceptsHoverEvents(false);
1949
1950     event.setScenePos(QPointF(-100, -100));
1951     QApplication::sendEvent(&scene, &event);
1952     event.setScenePos(QPointF(-2.5, -2.5));
1953     QApplication::sendEvent(&scene, &event);
1954
1955     QCOMPARE(item1->hoverInCount, 1);
1956     QCOMPARE(item2->hoverInCount, 1);
1957 }
1958
1959 void tst_QGraphicsItem::childAcceptsHoverEvents()
1960 {
1961     QGraphicsScene scene;
1962     HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
1963     HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
1964
1965     scene.addItem(item1);
1966     scene.addItem(item2);
1967     item2->setParentItem(item1);
1968     item2->setAcceptHoverEvents(true);
1969
1970     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
1971     event.setScenePos(QPointF(-100, -100));
1972     QApplication::sendEvent(&scene, &event);
1973     QCOMPARE(item2->hoverInCount, 0);
1974     QCOMPARE(item2->hoverMoveCount, 0);
1975     QCOMPARE(item2->hoverOutCount, 0);
1976     QCOMPARE(item1->hoverInCount, 0);
1977     QCOMPARE(item1->hoverMoveCount, 0);
1978     QCOMPARE(item1->hoverOutCount, 0);
1979
1980     event.setScenePos(QPointF(-2.5, -2.5));
1981     QApplication::sendEvent(&scene, &event);
1982
1983     QCOMPARE(item2->hoverInCount, 1);
1984     QCOMPARE(item2->hoverMoveCount, 1);
1985     QCOMPARE(item2->hoverOutCount, 0);
1986     QCOMPARE(item1->hoverInCount, 0);
1987     QCOMPARE(item1->hoverMoveCount, 0);
1988     QCOMPARE(item1->hoverOutCount, 0);
1989
1990     event.setScenePos(QPointF(0, 0));
1991     QApplication::sendEvent(&scene, &event);
1992
1993     QCOMPARE(item2->hoverInCount, 1);
1994     QCOMPARE(item2->hoverMoveCount, 2);
1995     QCOMPARE(item2->hoverOutCount, 0);
1996     QCOMPARE(item1->hoverInCount, 0);
1997     QCOMPARE(item1->hoverMoveCount, 0);
1998     QCOMPARE(item1->hoverOutCount, 0);
1999
2000     event.setScenePos(QPointF(-7, -7));
2001     QApplication::sendEvent(&scene, &event);
2002
2003     QCOMPARE(item2->hoverInCount, 1);
2004     QCOMPARE(item2->hoverMoveCount, 2);
2005     QCOMPARE(item2->hoverOutCount, 1);
2006     QCOMPARE(item1->hoverInCount, 0);
2007     QCOMPARE(item1->hoverMoveCount, 0);
2008     QCOMPARE(item1->hoverOutCount, 0);
2009
2010     event.setScenePos(QPointF(0, 0));
2011     QApplication::sendEvent(&scene, &event);
2012
2013     QCOMPARE(item2->hoverInCount, 2);
2014     QCOMPARE(item2->hoverMoveCount, 3);
2015     QCOMPARE(item2->hoverOutCount, 1);
2016     QCOMPARE(item1->hoverInCount, 0);
2017     QCOMPARE(item1->hoverMoveCount, 0);
2018     QCOMPARE(item1->hoverOutCount, 0);
2019
2020     HoverItem *item0 = new HoverItem(QRectF(-20, -20, 20, 20));
2021     scene.addItem(item0);
2022     item1->setParentItem(item0);
2023     item0->setAcceptHoverEvents(true);
2024
2025     event.setScenePos(QPointF(-100, -100));
2026     QApplication::sendEvent(&scene, &event);
2027
2028     event.setScenePos(QPointF(-15, -15));
2029     QApplication::sendEvent(&scene, &event);
2030
2031     QCOMPARE(item2->hoverInCount, 2);
2032     QCOMPARE(item2->hoverMoveCount, 3);
2033     QCOMPARE(item2->hoverOutCount, 2);
2034     QCOMPARE(item1->hoverInCount, 0);
2035     QCOMPARE(item1->hoverMoveCount, 0);
2036     QCOMPARE(item1->hoverOutCount, 0);
2037     QCOMPARE(item0->hoverInCount, 1);
2038     QCOMPARE(item0->hoverMoveCount, 1);
2039     QCOMPARE(item0->hoverOutCount, 0);
2040 }
2041
2042 void tst_QGraphicsItem::hasFocus()
2043 {
2044     QGraphicsLineItem *line = new QGraphicsLineItem;
2045     QVERIFY(!line->hasFocus());
2046     line->setFocus();
2047     QVERIFY(!line->hasFocus());
2048
2049     QGraphicsScene scene;
2050     QEvent activate(QEvent::WindowActivate);
2051     QApplication::sendEvent(&scene, &activate);
2052
2053     scene.addItem(line);
2054
2055     line->setFocus();
2056     QVERIFY(!line->hasFocus());
2057     line->setFlag(QGraphicsItem::ItemIsFocusable);
2058     line->setFocus();
2059     QVERIFY(line->hasFocus());
2060
2061     QGraphicsScene scene2;
2062     QApplication::sendEvent(&scene2, &activate);
2063
2064     scene2.addItem(line);
2065     QVERIFY(!line->hasFocus());
2066
2067     QCOMPARE(scene.focusItem(), (QGraphicsItem *)0);
2068     QCOMPARE(scene2.focusItem(), (QGraphicsItem *)0);
2069
2070     line->setFocus();
2071     QVERIFY(line->hasFocus());
2072     line->clearFocus();
2073     QVERIFY(!line->hasFocus());
2074
2075     QGraphicsLineItem *line2 = new QGraphicsLineItem;
2076     line2->setFlag(QGraphicsItem::ItemIsFocusable);
2077     scene2.addItem(line2);
2078
2079     line2->setFocus();
2080     QVERIFY(!line->hasFocus());
2081     QVERIFY(line2->hasFocus());
2082     line->setFocus();
2083     QVERIFY(line->hasFocus());
2084     QVERIFY(!line2->hasFocus());
2085 }
2086
2087 void tst_QGraphicsItem::pos()
2088 {
2089     QGraphicsItem *child = new QGraphicsLineItem;
2090     QGraphicsItem *parent = new QGraphicsLineItem;
2091
2092     QCOMPARE(child->pos(), QPointF());
2093     QCOMPARE(parent->pos(), QPointF());
2094
2095     child->setParentItem(parent);
2096     child->setPos(10, 10);
2097
2098     QCOMPARE(child->pos(), QPointF(10, 10));
2099
2100     parent->setPos(10, 10);
2101
2102     QCOMPARE(parent->pos(), QPointF(10, 10));
2103     QCOMPARE(child->pos(), QPointF(10, 10));
2104
2105     delete child;
2106     delete parent;
2107 }
2108
2109 void tst_QGraphicsItem::scenePos()
2110 {
2111     QGraphicsItem *child = new QGraphicsLineItem;
2112     QGraphicsItem *parent = new QGraphicsLineItem;
2113
2114     QCOMPARE(child->scenePos(), QPointF());
2115     QCOMPARE(parent->scenePos(), QPointF());
2116
2117     child->setParentItem(parent);
2118     child->setPos(10, 10);
2119
2120     QCOMPARE(child->scenePos(), QPointF(10, 10));
2121
2122     parent->setPos(10, 10);
2123
2124     QCOMPARE(parent->scenePos(), QPointF(10, 10));
2125     QCOMPARE(child->scenePos(), QPointF(20, 20));
2126
2127     parent->setPos(20, 20);
2128
2129     QCOMPARE(parent->scenePos(), QPointF(20, 20));
2130     QCOMPARE(child->scenePos(), QPointF(30, 30));
2131
2132     delete child;
2133     delete parent;
2134 }
2135
2136 void tst_QGraphicsItem::matrix()
2137 {
2138     QGraphicsLineItem line;
2139     QCOMPARE(line.matrix(), QMatrix());
2140     line.setMatrix(QMatrix().rotate(90));
2141     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2142     line.setMatrix(QMatrix().rotate(90));
2143     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2144     line.setMatrix(QMatrix().rotate(90), true);
2145     QCOMPARE(line.matrix(), QMatrix().rotate(180));
2146     line.setMatrix(QMatrix().rotate(-90), true);
2147     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2148     line.resetMatrix();
2149     QCOMPARE(line.matrix(), QMatrix());
2150
2151     line.rotate(90);
2152     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2153     line.rotate(90);
2154     QCOMPARE(line.matrix(), QMatrix().rotate(90).rotate(90));
2155     line.resetMatrix();
2156
2157     line.scale(2, 4);
2158     QCOMPARE(line.matrix(), QMatrix().scale(2, 4));
2159     line.scale(2, 4);
2160     QCOMPARE(line.matrix(), QMatrix().scale(2, 4).scale(2, 4));
2161     line.resetMatrix();
2162
2163     line.shear(2, 4);
2164     QCOMPARE(line.matrix(), QMatrix().shear(2, 4));
2165     line.shear(2, 4);
2166     QCOMPARE(line.matrix(), QMatrix().shear(2, 4).shear(2, 4));
2167     line.resetMatrix();
2168
2169     line.translate(10, 10);
2170     QCOMPARE(line.matrix(), QMatrix().translate(10, 10));
2171     line.translate(10, 10);
2172     QCOMPARE(line.matrix(), QMatrix().translate(10, 10).translate(10, 10));
2173     line.resetMatrix();
2174 }
2175
2176 void tst_QGraphicsItem::sceneMatrix()
2177 {
2178     QGraphicsLineItem *parent = new QGraphicsLineItem;
2179     QGraphicsLineItem *child = new QGraphicsLineItem(QLineF(), parent);
2180
2181     QCOMPARE(parent->sceneMatrix(), QMatrix());
2182     QCOMPARE(child->sceneMatrix(), QMatrix());
2183
2184     parent->translate(10, 10);
2185     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
2186     QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10));
2187
2188     child->translate(10, 10);
2189     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
2190     QCOMPARE(child->sceneMatrix(), QMatrix().translate(20, 20));
2191
2192     parent->rotate(90);
2193     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10).rotate(90));
2194     QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10).rotate(90).translate(10, 10));
2195
2196     delete child;
2197     delete parent;
2198 }
2199
2200 void tst_QGraphicsItem::setMatrix()
2201 {
2202     QGraphicsScene scene;
2203     qRegisterMetaType<QList<QRectF> >("QList<QRectF>");
2204     QSignalSpy spy(&scene, SIGNAL(changed(QList<QRectF>)));
2205     QRectF unrotatedRect(-12, -34, 56, 78);
2206     QGraphicsRectItem item(unrotatedRect, 0);
2207     scene.addItem(&item);
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 = qvariant_cast<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     QVERIFY(QTest::qWaitForWindowExposed(&view));
2268
2269     QApplication::processEvents();
2270
2271     QTRY_VERIFY(!_paintedItems.isEmpty());
2272     QVERIFY((_paintedItems.size() % 4) == 0);
2273     for (int i = 0; i < 3; ++i)
2274         QVERIFY(_paintedItems.at(i)->zValue() < _paintedItems.at(i + 1)->zValue());
2275 }
2276
2277 void tst_QGraphicsItem::shape()
2278 {
2279     QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
2280
2281     // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
2282     // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
2283     const qreal penWidthZero = qreal(0.00000001);
2284
2285     QPainterPathStroker ps;
2286     ps.setWidth(penWidthZero);
2287
2288     QPainterPath path(line.line().p1());
2289     path.lineTo(line.line().p2());
2290     QPainterPath p = ps.createStroke(path);
2291     p.addPath(path);
2292     QCOMPARE(line.shape(), p);
2293
2294     QPen linePen;
2295     linePen.setWidthF(5.0);
2296     linePen.setCapStyle(Qt::RoundCap);
2297     line.setPen(linePen);
2298
2299     ps.setCapStyle(line.pen().capStyle());
2300     ps.setWidth(line.pen().widthF());
2301     p = ps.createStroke(path);
2302     p.addPath(path);
2303     QCOMPARE(line.shape(), p);
2304
2305     linePen.setCapStyle(Qt::FlatCap);
2306     line.setPen(linePen);
2307     ps.setCapStyle(line.pen().capStyle());
2308     p = ps.createStroke(path);
2309     p.addPath(path);
2310     QCOMPARE(line.shape(), p);
2311
2312     linePen.setCapStyle(Qt::SquareCap);
2313     line.setPen(linePen);
2314     ps.setCapStyle(line.pen().capStyle());
2315     p = ps.createStroke(path);
2316     p.addPath(path);
2317     QCOMPARE(line.shape(), p);
2318
2319     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2320     QPainterPathStroker ps1;
2321     ps1.setWidth(penWidthZero);
2322     path = QPainterPath();
2323     path.addRect(rect.rect());
2324     p = ps1.createStroke(path);
2325     p.addPath(path);
2326     QCOMPARE(rect.shape(), p);
2327
2328     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2329     QPainterPathStroker ps2;
2330     ps2.setWidth(ellipse.pen().widthF() <= 0.0 ? penWidthZero : ellipse.pen().widthF());
2331     path = QPainterPath();
2332     path.addEllipse(ellipse.rect());
2333     p = ps2.createStroke(path);
2334     p.addPath(path);
2335     QCOMPARE(ellipse.shape(), p);
2336
2337     QPainterPathStroker ps3;
2338     ps3.setWidth(penWidthZero);
2339     p = ps3.createStroke(path);
2340     p.addPath(path);
2341     QGraphicsPathItem pathItem(path);
2342     QCOMPARE(pathItem.shape(), p);
2343
2344     QRegion region(QRect(0, 0, 300, 200));
2345     region = region.subtracted(QRect(50, 50, 200, 100));
2346
2347     QImage image(300, 200, QImage::Format_ARGB32_Premultiplied);
2348     image.fill(0);
2349     QPainter painter(&image);
2350     painter.setClipRegion(region);
2351     painter.fillRect(0, 0, 300, 200, Qt::green);
2352     painter.end();
2353     QPixmap pixmap = QPixmap::fromImage(image);
2354
2355     QGraphicsPixmapItem pixmapItem(pixmap);
2356     path = QPainterPath();
2357     path.addRegion(region);
2358
2359     {
2360         QBitmap bitmap(300, 200);
2361         bitmap.clear();
2362         QPainter painter(&bitmap);
2363         painter.setClipRegion(region);
2364         painter.fillRect(0, 0, 300, 200, Qt::color1);
2365         painter.end();
2366
2367         QBitmap bitmap2(300, 200);
2368         bitmap2.clear();
2369         painter.begin(&bitmap2);
2370         painter.setClipPath(pixmapItem.shape());
2371         painter.fillRect(0, 0, 300, 200, Qt::color1);
2372         painter.end();
2373
2374         QCOMPARE(bitmap.toImage(), bitmap2.toImage());
2375     }
2376
2377     QPolygonF poly;
2378     poly << QPointF(0, 0) << QPointF(10, 0) << QPointF(0, 10);
2379     QGraphicsPolygonItem polygon(poly);
2380     path = QPainterPath();
2381     path.addPolygon(poly);
2382
2383     QPainterPathStroker ps4;
2384     ps4.setWidth(penWidthZero);
2385     p = ps4.createStroke(path);
2386     p.addPath(path);
2387     QCOMPARE(polygon.shape(), p);
2388 }
2389
2390 void tst_QGraphicsItem::contains()
2391 {
2392     if (sizeof(qreal) != sizeof(double))
2393         QSKIP("Skipped due to rounding errors");
2394
2395     // Rect
2396     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2397     QVERIFY(!rect.contains(QPointF(-11, -10)));
2398     QVERIFY(rect.contains(QPointF(-10, -10)));
2399     QVERIFY(!rect.contains(QPointF(-11, 0)));
2400     QVERIFY(rect.contains(QPointF(-10, 0)));
2401     QVERIFY(rect.contains(QPointF(0, -10)));
2402     QVERIFY(rect.contains(QPointF(0, 0)));
2403     QVERIFY(rect.contains(QPointF(9, 9)));
2404
2405     // Ellipse
2406     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2407     QVERIFY(!ellipse.contains(QPointF(-10, -10)));
2408     QVERIFY(ellipse.contains(QPointF(-9, 0)));
2409     QVERIFY(ellipse.contains(QPointF(0, -9)));
2410     QVERIFY(ellipse.contains(QPointF(0, 0)));
2411     QVERIFY(!ellipse.contains(QPointF(9, 9)));
2412
2413     // Line
2414     QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
2415     QVERIFY(!line.contains(QPointF(-10, 0)));
2416     QVERIFY(!line.contains(QPointF(0, -10)));
2417     QVERIFY(!line.contains(QPointF(10, 0)));
2418     QVERIFY(!line.contains(QPointF(0, 10)));
2419     QVERIFY(line.contains(QPointF(0, 0)));
2420     QVERIFY(line.contains(QPointF(-9, -9)));
2421     QVERIFY(line.contains(QPointF(9, 9)));
2422
2423     // Polygon
2424     QGraphicsPolygonItem polygon(QPolygonF()
2425                                  << QPointF(0, 0)
2426                                  << QPointF(10, 0)
2427                                  << QPointF(0, 10));
2428     QVERIFY(polygon.contains(QPointF(1, 1)));
2429     QVERIFY(polygon.contains(QPointF(4, 4)));
2430     QVERIFY(polygon.contains(QPointF(1, 4)));
2431     QVERIFY(polygon.contains(QPointF(4, 1)));
2432     QVERIFY(!polygon.contains(QPointF(8, 8)));
2433     QVERIFY(polygon.contains(QPointF(1, 8)));
2434     QVERIFY(polygon.contains(QPointF(8, 1)));
2435 }
2436
2437 void tst_QGraphicsItem::collidesWith_item()
2438 {
2439     // Rectangle
2440     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2441     QGraphicsRectItem rect2(QRectF(-10, -10, 20, 20));
2442     QVERIFY(rect.collidesWithItem(&rect2));
2443     QVERIFY(rect2.collidesWithItem(&rect));
2444     rect2.setPos(21, 21);
2445     QVERIFY(!rect.collidesWithItem(&rect2));
2446     QVERIFY(!rect2.collidesWithItem(&rect));
2447     rect2.setPos(-21, -21);
2448     QVERIFY(!rect.collidesWithItem(&rect2));
2449     QVERIFY(!rect2.collidesWithItem(&rect));
2450     rect2.setPos(-17, -17);
2451     QVERIFY(rect.collidesWithItem(&rect2));
2452     QVERIFY(rect2.collidesWithItem(&rect));
2453
2454     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2455     QGraphicsEllipseItem ellipse2(QRectF(-10, -10, 20, 20));
2456     QVERIFY(ellipse.collidesWithItem(&ellipse2));
2457     QVERIFY(ellipse2.collidesWithItem(&ellipse));
2458     ellipse2.setPos(21, 21);
2459     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2460     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2461     ellipse2.setPos(-21, -21);
2462     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2463     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2464
2465     ellipse2.setPos(-17, -17);
2466     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2467     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2468
2469     {
2470         QGraphicsScene scene;
2471         QGraphicsRectItem rect(20, 20, 100, 100, 0);
2472         scene.addItem(&rect);
2473         QGraphicsRectItem rect2(40, 40, 50, 50, 0);
2474         scene.addItem(&rect2);
2475         rect2.setZValue(1);
2476         QGraphicsLineItem line(0, 0, 200, 200, 0);
2477         scene.addItem(&line);
2478         line.setZValue(2);
2479
2480         QCOMPARE(scene.items().size(), 3);
2481
2482         QList<QGraphicsItem *> col1 = rect.collidingItems();
2483         QCOMPARE(col1.size(), 2);
2484         QCOMPARE(col1.first(), static_cast<QGraphicsItem *>(&line));
2485         QCOMPARE(col1.last(), static_cast<QGraphicsItem *>(&rect2));
2486
2487         QList<QGraphicsItem *> col2 = rect2.collidingItems();
2488         QCOMPARE(col2.size(), 2);
2489         QCOMPARE(col2.first(), static_cast<QGraphicsItem *>(&line));
2490         QCOMPARE(col2.last(), static_cast<QGraphicsItem *>(&rect));
2491
2492         QList<QGraphicsItem *> col3 = line.collidingItems();
2493         QCOMPARE(col3.size(), 2);
2494         QCOMPARE(col3.first(), static_cast<QGraphicsItem *>(&rect2));
2495         QCOMPARE(col3.last(), static_cast<QGraphicsItem *>(&rect));
2496     }
2497 }
2498
2499 void tst_QGraphicsItem::collidesWith_path_data()
2500 {
2501     QTest::addColumn<QPointF>("pos");
2502     QTest::addColumn<QMatrix>("matrix");
2503     QTest::addColumn<QPainterPath>("shape");
2504     QTest::addColumn<bool>("rectCollides");
2505     QTest::addColumn<bool>("ellipseCollides");
2506
2507     QTest::newRow("nothing") << QPointF(0, 0) << QMatrix() << QPainterPath() << false << false;
2508
2509     QPainterPath rect;
2510     rect.addRect(0, 0, 20, 20);
2511
2512     QTest::newRow("rect1") << QPointF(0, 0) << QMatrix() << rect << true << true;
2513     QTest::newRow("rect2") << QPointF(0, 0) << QMatrix().translate(21, 21) << rect << false << false;
2514     QTest::newRow("rect3") << QPointF(21, 21) << QMatrix() << rect << false << false;
2515 }
2516
2517 void tst_QGraphicsItem::collidesWith_path()
2518 {
2519     QFETCH(QPointF, pos);
2520     QFETCH(QMatrix, matrix);
2521     QFETCH(QPainterPath, shape);
2522     QFETCH(bool, rectCollides);
2523     QFETCH(bool, ellipseCollides);
2524
2525     QGraphicsRectItem rect(QRectF(0, 0, 20, 20));
2526     QGraphicsEllipseItem ellipse(QRectF(0, 0, 20, 20));
2527
2528     rect.setPos(pos);
2529     rect.setMatrix(matrix);
2530
2531     ellipse.setPos(pos);
2532     ellipse.setMatrix(matrix);
2533
2534     QPainterPath mappedShape = rect.sceneMatrix().inverted().map(shape);
2535
2536     if (rectCollides)
2537         QVERIFY(rect.collidesWithPath(mappedShape));
2538     else
2539         QVERIFY(!rect.collidesWithPath(mappedShape));
2540
2541     if (ellipseCollides)
2542         QVERIFY(ellipse.collidesWithPath(mappedShape));
2543     else
2544         QVERIFY(!ellipse.collidesWithPath(mappedShape));
2545 }
2546
2547 void tst_QGraphicsItem::collidesWithItemWithClip()
2548 {
2549     QGraphicsScene scene;
2550
2551     QGraphicsEllipseItem *ellipse = scene.addEllipse(0, 0, 100, 100);
2552     ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
2553     QGraphicsEllipseItem *ellipse2 = scene.addEllipse(0, 0, 10, 10);
2554     ellipse2->setParentItem(ellipse);
2555     QGraphicsEllipseItem *ellipse3 = scene.addEllipse(0, 0, 10, 10);
2556     ellipse3->setParentItem(ellipse);
2557     QGraphicsEllipseItem *ellipse5 = scene.addEllipse(50, 50, 10, 10);
2558     ellipse5->setParentItem(ellipse);
2559     QGraphicsEllipseItem *ellipse4 = scene.addEllipse(0, 0, 10, 10);
2560
2561     QVERIFY(ellipse2->collidesWithItem(ellipse3));
2562     QVERIFY(ellipse3->collidesWithItem(ellipse2));
2563     QVERIFY(!ellipse2->collidesWithItem(ellipse));
2564     QVERIFY(!ellipse->collidesWithItem(ellipse2));
2565     QVERIFY(!ellipse4->collidesWithItem(ellipse));
2566     QVERIFY(!ellipse4->collidesWithItem(ellipse2));
2567     QVERIFY(!ellipse4->collidesWithItem(ellipse3));
2568     QVERIFY(!ellipse->collidesWithItem(ellipse4));
2569     QVERIFY(!ellipse2->collidesWithItem(ellipse4));
2570     QVERIFY(!ellipse3->collidesWithItem(ellipse4));
2571     QVERIFY(ellipse->collidesWithItem(ellipse5));
2572     QVERIFY(ellipse5->collidesWithItem(ellipse));
2573 }
2574
2575 class MyItem : public QGraphicsEllipseItem
2576 {
2577 public:
2578     bool isObscuredBy(const QGraphicsItem *item) const
2579     {
2580         const MyItem *myItem = qgraphicsitem_cast<const MyItem *>(item);
2581         if (myItem) {
2582             if (item->zValue() > zValue()) {
2583                 QRectF r = rect();
2584                 QPointF topMid = (r.topRight()+r.topLeft())/2;
2585                 QPointF botMid = (r.bottomRight()+r.bottomLeft())/2;
2586                 QPointF leftMid = (r.topLeft()+r.bottomLeft())/2;
2587                 QPointF rightMid = (r.topRight()+r.bottomRight())/2;
2588
2589                 QPainterPath mappedShape = item->mapToItem(this, item->opaqueArea());
2590
2591                 if (mappedShape.contains(topMid) &&
2592                     mappedShape.contains(botMid) &&
2593                     mappedShape.contains(leftMid) &&
2594                     mappedShape.contains(rightMid))
2595                     return true;
2596                 else
2597                     return false;
2598             }
2599             else return false;
2600         }
2601         else
2602             return QGraphicsItem::isObscuredBy(item);
2603     }
2604
2605     QPainterPath opaqueArea() const
2606     {
2607         return shape();
2608     }
2609
2610     enum {
2611         Type = UserType+1
2612     };
2613     int type() const { return Type; }
2614 };
2615
2616 void tst_QGraphicsItem::isObscuredBy()
2617 {
2618     QGraphicsScene scene;
2619
2620     MyItem myitem1, myitem2;
2621
2622     myitem1.setRect(QRectF(50, 50, 40, 200));
2623     myitem1.rotate(67);
2624
2625     myitem2.setRect(QRectF(25, 25, 20, 20));
2626     myitem2.setZValue(-1.0);
2627     scene.addItem(&myitem1);
2628     scene.addItem(&myitem2);
2629
2630     QVERIFY(!myitem2.isObscuredBy(&myitem1));
2631     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2632
2633     myitem2.setRect(QRectF(-50, 85, 20, 20));
2634     QVERIFY(myitem2.isObscuredBy(&myitem1));
2635     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2636
2637     myitem2.setRect(QRectF(-30, 70, 20, 20));
2638     QVERIFY(!myitem2.isObscuredBy(&myitem1));
2639     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2640
2641     QGraphicsRectItem rect1, rect2;
2642
2643     rect1.setRect(QRectF(-40, -40, 50, 50));
2644     rect1.setBrush(QBrush(Qt::red));
2645     rect2.setRect(QRectF(-30, -20, 20, 20));
2646     rect2.setZValue(-1.0);
2647     rect2.setBrush(QBrush(Qt::blue));
2648
2649     QVERIFY(rect2.isObscuredBy(&rect1));
2650     QVERIFY(!rect1.isObscuredBy(&rect2));
2651
2652     rect2.setPos(QPointF(-20, -25));
2653
2654     QVERIFY(!rect2.isObscuredBy(&rect1));
2655     QVERIFY(!rect1.isObscuredBy(&rect2));
2656
2657     rect2.setPos(QPointF(-100, -100));
2658
2659     QVERIFY(!rect2.isObscuredBy(&rect1));
2660     QVERIFY(!rect1.isObscuredBy(&rect2));
2661 }
2662
2663 class OpaqueItem : public QGraphicsRectItem
2664 {
2665 protected:
2666     QPainterPath opaqueArea() const
2667     {
2668         return shape();
2669     }
2670 };
2671
2672 void tst_QGraphicsItem::isObscured()
2673 {
2674     if (sizeof(qreal) != sizeof(double))
2675         QSKIP("Skipped due to rounding errors");
2676
2677     OpaqueItem *item1 = new OpaqueItem;
2678     item1->setRect(0, 0, 100, 100);
2679     item1->setZValue(0);
2680
2681     OpaqueItem *item2 = new OpaqueItem;
2682     item2->setZValue(1);
2683     item2->setRect(0, 0, 100, 100);
2684
2685     QGraphicsScene scene;
2686     scene.addItem(item1);
2687     scene.addItem(item2);
2688
2689     QVERIFY(item1->isObscured());
2690     QVERIFY(item1->isObscuredBy(item2));
2691     QVERIFY(item1->isObscured(QRectF(0, 0, 50, 50)));
2692     QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
2693     QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
2694     QVERIFY(item1->isObscured(QRectF(0, 50, 50, 50)));
2695     QVERIFY(item1->isObscured(0, 0, 50, 50));
2696     QVERIFY(item1->isObscured(50, 0, 50, 50));
2697     QVERIFY(item1->isObscured(50, 50, 50, 50));
2698     QVERIFY(item1->isObscured(0, 50, 50, 50));
2699     QVERIFY(!item2->isObscured());
2700     QVERIFY(!item2->isObscuredBy(item1));
2701     QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
2702     QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
2703     QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
2704     QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
2705     QVERIFY(!item2->isObscured(0, 0, 50, 50));
2706     QVERIFY(!item2->isObscured(50, 0, 50, 50));
2707     QVERIFY(!item2->isObscured(50, 50, 50, 50));
2708     QVERIFY(!item2->isObscured(0, 50, 50, 50));
2709
2710     item2->moveBy(50, 0);
2711
2712     QVERIFY(!item1->isObscured());
2713     QVERIFY(!item1->isObscuredBy(item2));
2714     QVERIFY(!item1->isObscured(QRectF(0, 0, 50, 50)));
2715     QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
2716     QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
2717     QVERIFY(!item1->isObscured(QRectF(0, 50, 50, 50)));
2718     QVERIFY(!item1->isObscured(0, 0, 50, 50));
2719     QVERIFY(item1->isObscured(50, 0, 50, 50));
2720     QVERIFY(item1->isObscured(50, 50, 50, 50));
2721     QVERIFY(!item1->isObscured(0, 50, 50, 50));
2722     QVERIFY(!item2->isObscured());
2723     QVERIFY(!item2->isObscuredBy(item1));
2724     QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
2725     QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
2726     QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
2727     QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
2728     QVERIFY(!item2->isObscured(0, 0, 50, 50));
2729     QVERIFY(!item2->isObscured(50, 0, 50, 50));
2730     QVERIFY(!item2->isObscured(50, 50, 50, 50));
2731     QVERIFY(!item2->isObscured(0, 50, 50, 50));
2732 }
2733
2734 void tst_QGraphicsItem::mapFromToParent()
2735 {
2736     QPainterPath path1;
2737     path1.addRect(0, 0, 200, 200);
2738
2739     QPainterPath path2;
2740     path2.addRect(0, 0, 100, 100);
2741
2742     QPainterPath path3;
2743     path3.addRect(0, 0, 50, 50);
2744
2745     QPainterPath path4;
2746     path4.addRect(0, 0, 25, 25);
2747
2748     QGraphicsItem *item1 = new QGraphicsPathItem(path1);
2749     QGraphicsItem *item2 = new QGraphicsPathItem(path2, item1);
2750     QGraphicsItem *item3 = new QGraphicsPathItem(path3, item2);
2751     QGraphicsItem *item4 = new QGraphicsPathItem(path4, item3);
2752
2753     item1->setPos(10, 10);
2754     item2->setPos(10, 10);
2755     item3->setPos(10, 10);
2756     item4->setPos(10, 10);
2757
2758     for (int i = 0; i < 4; ++i) {
2759         QMatrix matrix;
2760         matrix.rotate(i * 90);
2761         matrix.translate(i * 100, -i * 100);
2762         matrix.scale(2, 4);
2763         item1->setMatrix(matrix);
2764
2765         QCOMPARE(item1->mapToParent(QPointF(0, 0)), item1->pos() + matrix.map(QPointF(0, 0)));
2766         QCOMPARE(item2->mapToParent(QPointF(0, 0)), item2->pos());
2767         QCOMPARE(item3->mapToParent(QPointF(0, 0)), item3->pos());
2768         QCOMPARE(item4->mapToParent(QPointF(0, 0)), item4->pos());
2769         QCOMPARE(item1->mapToParent(QPointF(10, -10)), item1->pos() + matrix.map(QPointF(10, -10)));
2770         QCOMPARE(item2->mapToParent(QPointF(10, -10)), item2->pos() + QPointF(10, -10));
2771         QCOMPARE(item3->mapToParent(QPointF(10, -10)), item3->pos() + QPointF(10, -10));
2772         QCOMPARE(item4->mapToParent(QPointF(10, -10)), item4->pos() + QPointF(10, -10));
2773         QCOMPARE(item1->mapToParent(QPointF(-10, 10)), item1->pos() + matrix.map(QPointF(-10, 10)));
2774         QCOMPARE(item2->mapToParent(QPointF(-10, 10)), item2->pos() + QPointF(-10, 10));
2775         QCOMPARE(item3->mapToParent(QPointF(-10, 10)), item3->pos() + QPointF(-10, 10));
2776         QCOMPARE(item4->mapToParent(QPointF(-10, 10)), item4->pos() + QPointF(-10, 10));
2777         QCOMPARE(item1->mapFromParent(item1->pos()), matrix.inverted().map(QPointF(0, 0)));
2778         QCOMPARE(item2->mapFromParent(item2->pos()), QPointF(0, 0));
2779         QCOMPARE(item3->mapFromParent(item3->pos()), QPointF(0, 0));
2780         QCOMPARE(item4->mapFromParent(item4->pos()), QPointF(0, 0));
2781         QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(10, -10)),
2782                  matrix.inverted().map(QPointF(10, -10)));
2783         QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(10, -10)), QPointF(10, -10));
2784         QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(10, -10)), QPointF(10, -10));
2785         QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(10, -10)), QPointF(10, -10));
2786         QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(-10, 10)),
2787                  matrix.inverted().map(QPointF(-10, 10)));
2788         QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2789         QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2790         QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2791     }
2792
2793     delete item1;
2794 }
2795
2796 void tst_QGraphicsItem::mapFromToScene()
2797 {
2798     QGraphicsItem *item1 = new QGraphicsPathItem(QPainterPath());
2799     QGraphicsItem *item2 = new QGraphicsPathItem(QPainterPath(), item1);
2800     QGraphicsItem *item3 = new QGraphicsPathItem(QPainterPath(), item2);
2801     QGraphicsItem *item4 = new QGraphicsPathItem(QPainterPath(), item3);
2802
2803     item1->setPos(100, 100);
2804     item2->setPos(100, 100);
2805     item3->setPos(100, 100);
2806     item4->setPos(100, 100);
2807     QCOMPARE(item1->pos(), QPointF(100, 100));
2808     QCOMPARE(item2->pos(), QPointF(100, 100));
2809     QCOMPARE(item3->pos(), QPointF(100, 100));
2810     QCOMPARE(item4->pos(), QPointF(100, 100));
2811     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2812     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2813     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2814     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2815     QCOMPARE(item1->mapToParent(10, 10), QPointF(110, 110));
2816     QCOMPARE(item2->mapToParent(10, 10), QPointF(110, 110));
2817     QCOMPARE(item3->mapToParent(10, 10), QPointF(110, 110));
2818     QCOMPARE(item4->mapToParent(10, 10), QPointF(110, 110));
2819     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2820     QCOMPARE(item2->mapToScene(0, 0), QPointF(200, 200));
2821     QCOMPARE(item3->mapToScene(0, 0), QPointF(300, 300));
2822     QCOMPARE(item4->mapToScene(0, 0), QPointF(400, 400));
2823     QCOMPARE(item1->mapToScene(10, 0), QPointF(110, 100));
2824     QCOMPARE(item2->mapToScene(10, 0), QPointF(210, 200));
2825     QCOMPARE(item3->mapToScene(10, 0), QPointF(310, 300));
2826     QCOMPARE(item4->mapToScene(10, 0), QPointF(410, 400));
2827     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2828     QCOMPARE(item2->mapFromScene(200, 200), QPointF(0, 0));
2829     QCOMPARE(item3->mapFromScene(300, 300), QPointF(0, 0));
2830     QCOMPARE(item4->mapFromScene(400, 400), QPointF(0, 0));
2831     QCOMPARE(item1->mapFromScene(110, 100), QPointF(10, 0));
2832     QCOMPARE(item2->mapFromScene(210, 200), QPointF(10, 0));
2833     QCOMPARE(item3->mapFromScene(310, 300), QPointF(10, 0));
2834     QCOMPARE(item4->mapFromScene(410, 400), QPointF(10, 0));
2835
2836     // Rotate item1 90 degrees clockwise
2837     QMatrix matrix; matrix.rotate(90);
2838     item1->setMatrix(matrix);
2839     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2840     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2841     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2842     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2843     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2844     QCOMPARE(item2->mapToParent(10, 0), QPointF(110, 100));
2845     QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
2846     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2847     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2848     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2849     QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 300));
2850     QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 400));
2851     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2852     QCOMPARE(item2->mapToScene(10, 0), QPointF(0, 210));
2853     QCOMPARE(item3->mapToScene(10, 0), QPointF(-100, 310));
2854     QCOMPARE(item4->mapToScene(10, 0), QPointF(-200, 410));
2855     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2856     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2857     QCOMPARE(item3->mapFromScene(-100, 300), QPointF(0, 0));
2858     QCOMPARE(item4->mapFromScene(-200, 400), QPointF(0, 0));
2859     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2860     QCOMPARE(item2->mapFromScene(0, 210), QPointF(10, 0));
2861     QCOMPARE(item3->mapFromScene(-100, 310), QPointF(10, 0));
2862     QCOMPARE(item4->mapFromScene(-200, 410), QPointF(10, 0));
2863
2864     // Rotate item2 90 degrees clockwise
2865     item2->setMatrix(matrix);
2866     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2867     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2868     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2869     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2870     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2871     QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
2872     QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
2873     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2874     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2875     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2876     QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 100));
2877     QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 0));
2878     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2879     QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
2880     QCOMPARE(item3->mapToScene(10, 0), QPointF(-110, 100));
2881     QCOMPARE(item4->mapToScene(10, 0), QPointF(-210, 0));
2882     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2883     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2884     QCOMPARE(item3->mapFromScene(-100, 100), QPointF(0, 0));
2885     QCOMPARE(item4->mapFromScene(-200, 0), QPointF(0, 0));
2886     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2887     QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
2888     QCOMPARE(item3->mapFromScene(-110, 100), QPointF(10, 0));
2889     QCOMPARE(item4->mapFromScene(-210, 0), QPointF(10, 0));
2890
2891     // Translate item3 50 points, then rotate 90 degrees counterclockwise
2892     QMatrix matrix2;
2893     matrix2.translate(50, 0);
2894     matrix2.rotate(-90);
2895     item3->setMatrix(matrix2);
2896     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2897     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2898     QCOMPARE(item3->pos(), item3->mapToParent(0, 0) - QPointF(50, 0));
2899     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2900     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2901     QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
2902     QCOMPARE(item3->mapToParent(10, 0), QPointF(150, 90));
2903     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2904     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2905     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2906     QCOMPARE(item3->mapToScene(0, 0), QPointF(-150, 100));
2907     QCOMPARE(item4->mapToScene(0, 0), QPointF(-250, 200));
2908     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2909     QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
2910     QCOMPARE(item3->mapToScene(10, 0), QPointF(-150, 110));
2911     QCOMPARE(item4->mapToScene(10, 0), QPointF(-250, 210));
2912     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2913     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2914     QCOMPARE(item3->mapFromScene(-150, 100), QPointF(0, 0));
2915     QCOMPARE(item4->mapFromScene(-250, 200), QPointF(0, 0));
2916     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2917     QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
2918     QCOMPARE(item3->mapFromScene(-150, 110), QPointF(10, 0));
2919     QCOMPARE(item4->mapFromScene(-250, 210), QPointF(10, 0));
2920
2921     delete item1;
2922 }
2923
2924 void tst_QGraphicsItem::mapFromToItem()
2925 {
2926     QGraphicsItem *item1 = new QGraphicsPathItem;
2927     QGraphicsItem *item2 = new QGraphicsPathItem;
2928     QGraphicsItem *item3 = new QGraphicsPathItem;
2929     QGraphicsItem *item4 = new QGraphicsPathItem;
2930
2931     item1->setPos(-100, -100);
2932     item2->setPos(100, -100);
2933     item3->setPos(100, 100);
2934     item4->setPos(-100, 100);
2935
2936     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(200, 0));
2937     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200));
2938     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0));
2939     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(0, -200));
2940     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(0, 200));
2941     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-200, 0));
2942     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
2943     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
2944
2945     QMatrix matrix;
2946     matrix.translate(100, 100);
2947     item1->setMatrix(matrix);
2948
2949     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(100, -100));
2950     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200));
2951     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0));
2952     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(100, -100));
2953     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(-100, 100));
2954     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-100, 100));
2955     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
2956     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
2957
2958     matrix.rotate(90);
2959     item1->setMatrix(matrix);
2960     item2->setMatrix(matrix);
2961     item3->setMatrix(matrix);
2962     item4->setMatrix(matrix);
2963
2964     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(0, -200));
2965     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(200, 0));
2966     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(0, 200));
2967     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(-200, 0));
2968     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(200, 0));
2969     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(0, 200));
2970     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(-200, 0));
2971     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(0, -200));
2972     QCOMPARE(item1->mapFromItem(item2, 10, -5), QPointF(10, -205));
2973     QCOMPARE(item2->mapFromItem(item3, 10, -5), QPointF(210, -5));
2974     QCOMPARE(item3->mapFromItem(item4, 10, -5), QPointF(10, 195));
2975     QCOMPARE(item4->mapFromItem(item1, 10, -5), QPointF(-190, -5));
2976     QCOMPARE(item1->mapFromItem(item4, 10, -5), QPointF(210, -5));
2977     QCOMPARE(item2->mapFromItem(item1, 10, -5), QPointF(10, 195));
2978     QCOMPARE(item3->mapFromItem(item2, 10, -5), QPointF(-190, -5));
2979     QCOMPARE(item4->mapFromItem(item3, 10, -5), QPointF(10, -205));
2980
2981     QCOMPARE(item1->mapFromItem(0, 10, -5), item1->mapFromScene(10, -5));
2982     QCOMPARE(item2->mapFromItem(0, 10, -5), item2->mapFromScene(10, -5));
2983     QCOMPARE(item3->mapFromItem(0, 10, -5), item3->mapFromScene(10, -5));
2984     QCOMPARE(item4->mapFromItem(0, 10, -5), item4->mapFromScene(10, -5));
2985     QCOMPARE(item1->mapToItem(0, 10, -5), item1->mapToScene(10, -5));
2986     QCOMPARE(item2->mapToItem(0, 10, -5), item2->mapToScene(10, -5));
2987     QCOMPARE(item3->mapToItem(0, 10, -5), item3->mapToScene(10, -5));
2988     QCOMPARE(item4->mapToItem(0, 10, -5), item4->mapToScene(10, -5));
2989
2990     delete item1;
2991     delete item2;
2992     delete item3;
2993     delete item4;
2994 }
2995
2996 void tst_QGraphicsItem::mapRectFromToParent_data()
2997 {
2998     QTest::addColumn<bool>("parent");
2999     QTest::addColumn<QPointF>("parentPos");
3000     QTest::addColumn<QTransform>("parentTransform");
3001     QTest::addColumn<QPointF>("pos");
3002     QTest::addColumn<QTransform>("transform");
3003     QTest::addColumn<QRectF>("inputRect");
3004     QTest::addColumn<QRectF>("outputRect");
3005
3006     QTest::newRow("nil") << false << QPointF() << QTransform() << QPointF() << QTransform() << QRectF() << QRectF();
3007     QTest::newRow("simple") << false << QPointF() << QTransform() << QPointF() << QTransform()
3008                             << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3009     QTest::newRow("simple w/parent") << true
3010                                      << QPointF() << QTransform()
3011                                      << QPointF() << QTransform()
3012                                      << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3013     QTest::newRow("simple w/parent parentPos") << true
3014                                                << QPointF(50, 50) << QTransform()
3015                                                << QPointF() << QTransform()
3016                                                << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3017     QTest::newRow("simple w/parent parentPos parentRotation") << true
3018                                                               << QPointF(50, 50) << QTransform().rotate(45)
3019                                                               << QPointF() << QTransform()
3020                                                               << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3021     QTest::newRow("pos w/parent") << true
3022                                   << QPointF() << QTransform()
3023                                   << QPointF(50, 50) << QTransform()
3024                                   << QRectF(0, 0, 10, 10) << QRectF(50, 50, 10, 10);
3025     QTest::newRow("rotation w/parent") << true
3026                                        << QPointF() << QTransform()
3027                                        << QPointF() << QTransform().rotate(90)
3028                                        << QRectF(0, 0, 10, 10) << QRectF(-10, 0, 10, 10);
3029     QTest::newRow("pos rotation w/parent") << true
3030                                            << QPointF() << QTransform()
3031                                            << QPointF(50, 50) << QTransform().rotate(90)
3032                                            << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
3033     QTest::newRow("pos rotation w/parent parentPos parentRotation") << true
3034                                                                     << QPointF(-170, -190) << QTransform().rotate(90)
3035                                                                     << QPointF(50, 50) << QTransform().rotate(90)
3036                                                                     << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
3037 }
3038
3039 void tst_QGraphicsItem::mapRectFromToParent()
3040 {
3041     QFETCH(bool, parent);
3042     QFETCH(QPointF, parentPos);
3043     QFETCH(QTransform, parentTransform);
3044     QFETCH(QPointF, pos);
3045     QFETCH(QTransform, transform);
3046     QFETCH(QRectF, inputRect);
3047     QFETCH(QRectF, outputRect);
3048
3049     QGraphicsRectItem *rect = new QGraphicsRectItem;
3050     rect->setPos(pos);
3051     rect->setTransform(transform);
3052
3053     if (parent) {
3054         QGraphicsRectItem *rectParent = new QGraphicsRectItem;
3055         rect->setParentItem(rectParent);
3056         rectParent->setPos(parentPos);
3057         rectParent->setTransform(parentTransform);
3058     }
3059
3060     // Make sure we use non-destructive transform operations (e.g., 90 degree
3061     // rotations).
3062     QCOMPARE(rect->mapRectToParent(inputRect), outputRect);
3063     QCOMPARE(rect->mapRectFromParent(outputRect), inputRect);
3064     QCOMPARE(rect->itemTransform(rect->parentItem()).mapRect(inputRect), outputRect);
3065     QCOMPARE(rect->mapToParent(inputRect).boundingRect(), outputRect);
3066     QCOMPARE(rect->mapToParent(QPolygonF(inputRect)).boundingRect(), outputRect);
3067     QCOMPARE(rect->mapFromParent(outputRect).boundingRect(), inputRect);
3068     QCOMPARE(rect->mapFromParent(QPolygonF(outputRect)).boundingRect(), inputRect);
3069     QPainterPath inputPath;
3070     inputPath.addRect(inputRect);
3071     QPainterPath outputPath;
3072     outputPath.addRect(outputRect);
3073     QCOMPARE(rect->mapToParent(inputPath).boundingRect(), outputPath.boundingRect());
3074     QCOMPARE(rect->mapFromParent(outputPath).boundingRect(), inputPath.boundingRect());
3075 }
3076
3077 void tst_QGraphicsItem::isAncestorOf()
3078 {
3079     QGraphicsItem *grandPa = new QGraphicsRectItem;
3080     QGraphicsItem *parent = new QGraphicsRectItem;
3081     QGraphicsItem *child = new QGraphicsRectItem;
3082
3083     QVERIFY(!parent->isAncestorOf(0));
3084     QVERIFY(!child->isAncestorOf(0));
3085     QVERIFY(!parent->isAncestorOf(child));
3086     QVERIFY(!child->isAncestorOf(parent));
3087     QVERIFY(!parent->isAncestorOf(parent));
3088
3089     child->setParentItem(parent);
3090     parent->setParentItem(grandPa);
3091
3092     QVERIFY(parent->isAncestorOf(child));
3093     QVERIFY(grandPa->isAncestorOf(parent));
3094     QVERIFY(grandPa->isAncestorOf(child));
3095     QVERIFY(!child->isAncestorOf(parent));
3096     QVERIFY(!parent->isAncestorOf(grandPa));
3097     QVERIFY(!child->isAncestorOf(grandPa));
3098     QVERIFY(!child->isAncestorOf(child));
3099     QVERIFY(!parent->isAncestorOf(parent));
3100     QVERIFY(!grandPa->isAncestorOf(grandPa));
3101
3102     parent->setParentItem(0);
3103
3104     delete child;
3105     delete parent;
3106     delete grandPa;
3107 }
3108
3109 void tst_QGraphicsItem::commonAncestorItem()
3110 {
3111     QGraphicsItem *ancestor = new QGraphicsRectItem;
3112     QGraphicsItem *grandMa = new QGraphicsRectItem;
3113     QGraphicsItem *grandPa = new QGraphicsRectItem;
3114     QGraphicsItem *brotherInLaw = new QGraphicsRectItem;
3115     QGraphicsItem *cousin = new QGraphicsRectItem;
3116     QGraphicsItem *husband = new QGraphicsRectItem;
3117     QGraphicsItem *child = new QGraphicsRectItem;
3118     QGraphicsItem *wife = new QGraphicsRectItem;
3119
3120     child->setParentItem(husband);
3121     husband->setParentItem(grandPa);
3122     brotherInLaw->setParentItem(grandPa);
3123     cousin->setParentItem(brotherInLaw);
3124     wife->setParentItem(grandMa);
3125     grandMa->setParentItem(ancestor);
3126     grandPa->setParentItem(ancestor);
3127
3128     QCOMPARE(grandMa->commonAncestorItem(grandMa), grandMa);
3129     QCOMPARE(grandMa->commonAncestorItem(0), (QGraphicsItem *)0);
3130     QCOMPARE(grandMa->commonAncestorItem(grandPa), ancestor);
3131     QCOMPARE(grandPa->commonAncestorItem(grandMa), ancestor);
3132     QCOMPARE(grandPa->commonAncestorItem(husband), grandPa);
3133     QCOMPARE(grandPa->commonAncestorItem(wife), ancestor);
3134     QCOMPARE(grandMa->commonAncestorItem(husband), ancestor);
3135     QCOMPARE(grandMa->commonAncestorItem(wife), grandMa);
3136     QCOMPARE(wife->commonAncestorItem(grandMa), grandMa);
3137     QCOMPARE(child->commonAncestorItem(cousin), grandPa);
3138     QCOMPARE(cousin->commonAncestorItem(child), grandPa);
3139     QCOMPARE(wife->commonAncestorItem(child), ancestor);
3140     QCOMPARE(child->commonAncestorItem(wife), ancestor);
3141 }
3142
3143 void tst_QGraphicsItem::data()
3144 {
3145     QGraphicsTextItem text;
3146
3147     QCOMPARE(text.data(0), QVariant());
3148     text.setData(0, "TextItem");
3149     QCOMPARE(text.data(0), QVariant(QString("TextItem")));
3150     text.setData(0, QVariant());
3151     QCOMPARE(text.data(0), QVariant());
3152 }
3153
3154 void tst_QGraphicsItem::type()
3155 {
3156     QCOMPARE(int(QGraphicsItem::Type), 1);
3157     QCOMPARE(int(QGraphicsPathItem::Type), 2);
3158     QCOMPARE(int(QGraphicsRectItem::Type), 3);
3159     QCOMPARE(int(QGraphicsEllipseItem::Type), 4);
3160     QCOMPARE(int(QGraphicsPolygonItem::Type), 5);
3161     QCOMPARE(int(QGraphicsLineItem::Type), 6);
3162     QCOMPARE(int(QGraphicsPixmapItem::Type), 7);
3163     QCOMPARE(int(QGraphicsTextItem::Type), 8);
3164
3165     QCOMPARE(QGraphicsPathItem().type(), 2);
3166     QCOMPARE(QGraphicsRectItem().type(), 3);
3167     QCOMPARE(QGraphicsEllipseItem().type(), 4);
3168     QCOMPARE(QGraphicsPolygonItem().type(), 5);
3169     QCOMPARE(QGraphicsLineItem().type(), 6);
3170     QCOMPARE(QGraphicsPixmapItem().type(), 7);
3171     QCOMPARE(QGraphicsTextItem().type(), 8);
3172 }
3173
3174 void tst_QGraphicsItem::graphicsitem_cast()
3175 {
3176     QGraphicsPathItem pathItem;
3177     const QGraphicsPathItem *pPathItem = &pathItem;
3178     QGraphicsRectItem rectItem;
3179     const QGraphicsRectItem *pRectItem = &rectItem;
3180     QGraphicsEllipseItem ellipseItem;
3181     const QGraphicsEllipseItem *pEllipseItem = &ellipseItem;
3182     QGraphicsPolygonItem polygonItem;
3183     const QGraphicsPolygonItem *pPolygonItem = &polygonItem;
3184     QGraphicsLineItem lineItem;
3185     const QGraphicsLineItem *pLineItem = &lineItem;
3186     QGraphicsPixmapItem pixmapItem;
3187     const QGraphicsPixmapItem *pPixmapItem = &pixmapItem;
3188     QGraphicsTextItem textItem;
3189     const QGraphicsTextItem *pTextItem = &textItem;
3190
3191     QVERIFY(qgraphicsitem_cast<QGraphicsPathItem *>(&pathItem));
3192     //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&pathItem));
3193     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pathItem));
3194     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPathItem));
3195     QVERIFY(qgraphicsitem_cast<const QGraphicsPathItem *>(pPathItem));
3196
3197     QVERIFY(qgraphicsitem_cast<QGraphicsRectItem *>(&rectItem));
3198     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&rectItem));
3199     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pRectItem));
3200     QVERIFY(qgraphicsitem_cast<const QGraphicsRectItem *>(pRectItem));
3201
3202     QVERIFY(qgraphicsitem_cast<QGraphicsEllipseItem *>(&ellipseItem));
3203     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&ellipseItem));
3204     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pEllipseItem));
3205     QVERIFY(qgraphicsitem_cast<const QGraphicsEllipseItem *>(pEllipseItem));
3206
3207     QVERIFY(qgraphicsitem_cast<QGraphicsPolygonItem *>(&polygonItem));
3208     //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&polygonItem));
3209     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&polygonItem));
3210     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPolygonItem));
3211     QVERIFY(qgraphicsitem_cast<const QGraphicsPolygonItem *>(pPolygonItem));
3212
3213     QVERIFY(qgraphicsitem_cast<QGraphicsLineItem *>(&lineItem));
3214     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&lineItem));
3215     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pLineItem));
3216     QVERIFY(qgraphicsitem_cast<const QGraphicsLineItem *>(pLineItem));
3217
3218     QVERIFY(qgraphicsitem_cast<QGraphicsPixmapItem *>(&pixmapItem));
3219     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pixmapItem));
3220     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPixmapItem));
3221     QVERIFY(qgraphicsitem_cast<const QGraphicsPixmapItem *>(pPixmapItem));
3222
3223     QVERIFY(qgraphicsitem_cast<QGraphicsTextItem *>(&textItem));
3224     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&textItem));
3225     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pTextItem));
3226     QVERIFY(qgraphicsitem_cast<const QGraphicsTextItem *>(pTextItem));
3227
3228     // and some casts that _should_ fail:
3229     QVERIFY(!qgraphicsitem_cast<QGraphicsEllipseItem *>(&pathItem));
3230     QVERIFY(!qgraphicsitem_cast<const QGraphicsTextItem *>(pPolygonItem));
3231
3232     // and this shouldn't crash
3233     QGraphicsItem *ptr = 0;
3234     QVERIFY(!qgraphicsitem_cast<QGraphicsTextItem *>(ptr));
3235     QVERIFY(!qgraphicsitem_cast<QGraphicsItem *>(ptr));
3236 }
3237
3238 void tst_QGraphicsItem::hoverEventsGenerateRepaints()
3239 {
3240     Q_CHECK_PAINTEVENTS
3241
3242     QGraphicsScene scene;
3243     QGraphicsView view(&scene);
3244     view.show();
3245     QVERIFY(QTest::qWaitForWindowActive(&view));
3246
3247     EventTester *tester = new EventTester;
3248     scene.addItem(tester);
3249     tester->setAcceptsHoverEvents(true);
3250
3251     QTRY_COMPARE(tester->repaints, 1);
3252
3253     // Send a hover enter event
3254     QGraphicsSceneHoverEvent hoverEnterEvent(QEvent::GraphicsSceneHoverEnter);
3255     hoverEnterEvent.setScenePos(QPointF(0, 0));
3256     hoverEnterEvent.setPos(QPointF(0, 0));
3257     QApplication::sendEvent(&scene, &hoverEnterEvent);
3258
3259     // Check that we get a repaint
3260     int npaints = tester->repaints;
3261     qApp->processEvents();
3262     qApp->processEvents();
3263     QCOMPARE(tester->events.size(), 2); //  enter + move
3264     QCOMPARE(tester->repaints, npaints + 1);
3265     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
3266
3267     // Send a hover move event
3268     QGraphicsSceneHoverEvent hoverMoveEvent(QEvent::GraphicsSceneHoverMove);
3269     hoverMoveEvent.setScenePos(QPointF(0, 0));
3270     hoverMoveEvent.setPos(QPointF(0, 0));
3271     QApplication::sendEvent(&scene, &hoverMoveEvent);
3272
3273     // Check that we don't get a repaint
3274     qApp->processEvents();
3275     qApp->processEvents();
3276
3277     QCOMPARE(tester->events.size(), 3);
3278     QCOMPARE(tester->repaints, npaints + 1);
3279     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
3280
3281     // Send a hover leave event
3282     QGraphicsSceneHoverEvent hoverLeaveEvent(QEvent::GraphicsSceneHoverLeave);
3283     hoverLeaveEvent.setScenePos(QPointF(-100, -100));
3284     hoverLeaveEvent.setPos(QPointF(0, 0));
3285     QApplication::sendEvent(&scene, &hoverLeaveEvent);
3286
3287     // Check that we get a repaint
3288     qApp->processEvents();
3289     qApp->processEvents();
3290
3291     QCOMPARE(tester->events.size(), 4);
3292     QCOMPARE(tester->repaints, npaints + 2);
3293     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverLeave);
3294 }
3295
3296 void tst_QGraphicsItem::boundingRects_data()
3297 {
3298     QTest::addColumn<QGraphicsItem *>("item");
3299     QTest::addColumn<QRectF>("boundingRect");
3300
3301     QRectF rect(0, 0, 100, 100);
3302     QPainterPath path;
3303     path.addRect(rect);
3304
3305     QRectF adjustedRect(-0.5, -0.5, 101, 101);
3306
3307     QTest::newRow("path") << (QGraphicsItem *)new QGraphicsPathItem(path) << adjustedRect;
3308     QTest::newRow("rect") << (QGraphicsItem *)new QGraphicsRectItem(rect) << adjustedRect;
3309     QTest::newRow("ellipse") << (QGraphicsItem *)new QGraphicsEllipseItem(rect) << adjustedRect;
3310     QTest::newRow("polygon") << (QGraphicsItem *)new QGraphicsPolygonItem(rect) << adjustedRect;
3311 }
3312
3313 void tst_QGraphicsItem::boundingRects()
3314 {
3315     QFETCH(QGraphicsItem *, item);
3316     QFETCH(QRectF, boundingRect);
3317
3318     ((QAbstractGraphicsShapeItem *)item)->setPen(QPen(Qt::black, 1));
3319     QCOMPARE(item->boundingRect(), boundingRect);
3320 }
3321
3322 void tst_QGraphicsItem::boundingRects2()
3323 {
3324     QGraphicsPixmapItem pixmap(QPixmap::fromImage(QImage(100, 100, QImage::Format_ARGB32_Premultiplied)));
3325     QCOMPARE(pixmap.boundingRect(), QRectF(0, 0, 100, 100));
3326
3327     QGraphicsLineItem line(0, 0, 100, 0);
3328     line.setPen(QPen(Qt::black, 1));
3329     QCOMPARE(line.boundingRect(), QRectF(-0.5, -0.5, 101, 1));
3330 }
3331
3332 void tst_QGraphicsItem::sceneBoundingRect()
3333 {
3334     QGraphicsScene scene;
3335     QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3336     item->setPos(100, 100);
3337
3338     QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
3339     QCOMPARE(item->sceneBoundingRect(), QRectF(100, 100, 100, 100));
3340
3341     item->rotate(90);
3342
3343     QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
3344     QCOMPARE(item->sceneBoundingRect(), QRectF(0, 100, 100, 100));
3345 }
3346
3347 void tst_QGraphicsItem::childrenBoundingRect()
3348 {
3349     QGraphicsScene scene;
3350     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3351     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3352     child->setParentItem(parent);
3353     parent->setPos(100, 100);
3354     child->setPos(100, 100);
3355
3356     QCOMPARE(parent->boundingRect(), QRectF(0, 0, 100, 100));
3357     QCOMPARE(child->boundingRect(), QRectF(0, 0, 100, 100));
3358     QCOMPARE(child->childrenBoundingRect(), QRectF());
3359     QCOMPARE(parent->childrenBoundingRect(), QRectF(100, 100, 100, 100));
3360
3361     QGraphicsRectItem *child2 = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3362     child2->setParentItem(parent);
3363     child2->setPos(-100, -100);
3364     QCOMPARE(parent->childrenBoundingRect(), QRectF(-100, -100, 300, 300));
3365
3366     QGraphicsRectItem *childChild = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3367     childChild->setParentItem(child);
3368     childChild->setPos(500, 500);
3369     child->rotate(90);
3370
3371     scene.addPolygon(parent->mapToScene(parent->boundingRect() | parent->childrenBoundingRect()))->setPen(QPen(Qt::red));;
3372
3373     QGraphicsView view(&scene);
3374     view.show();
3375
3376     QVERIFY(QTest::qWaitForWindowExposed(&view));
3377     QTest::qWait(30);
3378
3379     QCOMPARE(parent->childrenBoundingRect(), QRectF(-500, -100, 600, 800));
3380 }
3381
3382 void tst_QGraphicsItem::childrenBoundingRectTransformed()
3383 {
3384     QGraphicsScene scene;
3385
3386     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
3387     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
3388     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
3389     QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
3390     QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
3391     rect2->setParentItem(rect);
3392     rect3->setParentItem(rect2);
3393     rect4->setParentItem(rect3);
3394     rect5->setParentItem(rect4);
3395
3396     rect2->setTransform(QTransform().translate(50, 50).rotate(45));
3397     rect2->setPos(25, 25);
3398     rect3->setTransform(QTransform().translate(50, 50).rotate(45));
3399     rect3->setPos(25, 25);
3400     rect4->setTransform(QTransform().translate(50, 50).rotate(45));
3401     rect4->setPos(25, 25);
3402     rect5->setTransform(QTransform().translate(50, 50).rotate(45));
3403     rect5->setPos(25, 25);
3404
3405     QRectF subTreeRect = rect->childrenBoundingRect();
3406     QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
3407     QCOMPARE(subTreeRect.top(), qreal(75.0));
3408     QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
3409     QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
3410
3411     rect->rotate(45);
3412     rect2->rotate(-45);
3413     rect3->rotate(45);
3414     rect4->rotate(-45);
3415     rect5->rotate(45);
3416
3417     subTreeRect = rect->childrenBoundingRect();
3418     QCOMPARE(rect->childrenBoundingRect(), QRectF(-100, 75, 275, 250));
3419 }
3420
3421 void tst_QGraphicsItem::childrenBoundingRect2()
3422 {
3423     QGraphicsItemGroup box;
3424     QGraphicsLineItem l1(0, 0, 100, 0, &box);
3425     QGraphicsLineItem l2(100, 0, 100, 100, &box);
3426     QGraphicsLineItem l3(0, 0, 0, 100, &box);
3427     // Make sure lines (zero with/height) are included in the childrenBoundingRect.
3428     QCOMPARE(box.childrenBoundingRect(), QRectF(0, 0, 100, 100));
3429 }
3430
3431 void tst_QGraphicsItem::childrenBoundingRect3()
3432 {
3433     QGraphicsScene scene;
3434
3435     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
3436     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
3437     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
3438     QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
3439     QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
3440     rect2->setParentItem(rect);
3441     rect3->setParentItem(rect2);
3442     rect4->setParentItem(rect3);
3443     rect5->setParentItem(rect4);
3444
3445     rect2->setTransform(QTransform().translate(50, 50).rotate(45));
3446     rect2->setPos(25, 25);
3447     rect3->setTransform(QTransform().translate(50, 50).rotate(45));
3448     rect3->setPos(25, 25);
3449     rect4->setTransform(QTransform().translate(50, 50).rotate(45));
3450     rect4->setPos(25, 25);
3451     rect5->setTransform(QTransform().translate(50, 50).rotate(45));
3452     rect5->setPos(25, 25);
3453
3454     // Try to mess up the cached bounding rect.
3455     (void)rect2->childrenBoundingRect();
3456
3457     QRectF subTreeRect = rect->childrenBoundingRect();
3458     QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
3459     QCOMPARE(subTreeRect.top(), qreal(75.0));
3460     QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
3461     QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
3462 }
3463
3464 void tst_QGraphicsItem::childrenBoundingRect4()
3465 {
3466     QGraphicsScene scene;
3467
3468     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 10, 10));
3469     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 20, 20));
3470     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 30, 30));
3471     rect2->setParentItem(rect);
3472     rect3->setParentItem(rect);
3473
3474     QGraphicsView view(&scene);
3475     view.show();
3476
3477     QVERIFY(QTest::qWaitForWindowExposed(&view));
3478
3479     // Try to mess up the cached bounding rect.
3480     rect->childrenBoundingRect();
3481     rect2->childrenBoundingRect();
3482
3483     rect3->setOpacity(0.0);
3484     rect3->setParentItem(rect2);
3485
3486     QCOMPARE(rect->childrenBoundingRect(), rect3->boundingRect());
3487     QCOMPARE(rect2->childrenBoundingRect(), rect3->boundingRect());
3488 }
3489
3490 void tst_QGraphicsItem::childrenBoundingRect5()
3491 {
3492     QGraphicsScene scene;
3493
3494     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
3495     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100));
3496     child->setParentItem(parent);
3497
3498     QGraphicsView view(&scene);
3499     view.show();
3500
3501     QVERIFY(QTest::qWaitForWindowExposed(&view));
3502
3503     // Try to mess up the cached bounding rect.
3504     QRectF expectedChildrenBoundingRect = parent->boundingRect();
3505     QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect);
3506
3507     // Apply some effects.
3508     QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect;
3509     dropShadow->setOffset(25, 25);
3510     child->setGraphicsEffect(dropShadow);
3511     parent->setGraphicsEffect(new QGraphicsOpacityEffect);
3512
3513     QVERIFY(parent->childrenBoundingRect() != expectedChildrenBoundingRect);
3514     expectedChildrenBoundingRect |= dropShadow->boundingRect();
3515     QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect);
3516 }
3517
3518 void tst_QGraphicsItem::group()
3519 {
3520     QGraphicsScene scene;
3521     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::green));
3522     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::blue));
3523     QGraphicsRectItem *parent2 = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::red));
3524     parent2->setPos(-50, 50);
3525     child->rotate(45);
3526     child->setParentItem(parent);
3527     parent->setPos(25, 25);
3528     child->setPos(25, 25);
3529
3530     QCOMPARE(parent->group(), (QGraphicsItemGroup *)0);
3531     QCOMPARE(parent2->group(), (QGraphicsItemGroup *)0);
3532     QCOMPARE(child->group(), (QGraphicsItemGroup *)0);
3533
3534     QGraphicsView view(&scene);
3535     view.show();
3536     QVERIFY(QTest::qWaitForWindowExposed(&view));
3537
3538     QGraphicsItemGroup *group = new QGraphicsItemGroup;
3539     group->setSelected(true);
3540     scene.addItem(group);
3541
3542     QRectF parentSceneBoundingRect = parent->sceneBoundingRect();
3543     group->addToGroup(parent);
3544     QCOMPARE(parent->group(), group);
3545     QCOMPARE(parent->sceneBoundingRect(), parentSceneBoundingRect);
3546
3547     QCOMPARE(parent->parentItem(), (QGraphicsItem *)group);
3548     QCOMPARE(group->children().size(), 1);
3549     QCOMPARE(scene.items().size(), 4);
3550     QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 3);
3551
3552     QTest::qWait(25);
3553
3554     QRectF parent2SceneBoundingRect = parent2->sceneBoundingRect();
3555     group->addToGroup(parent2);
3556     QCOMPARE(parent2->group(), group);
3557     QCOMPARE(parent2->sceneBoundingRect(), parent2SceneBoundingRect);
3558
3559     QCOMPARE(parent2->parentItem(), (QGraphicsItem *)group);
3560     QCOMPARE(group->children().size(), 2);
3561     QCOMPARE(scene.items().size(), 4);
3562     QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 4);
3563
3564     QTest::qWait(25);
3565
3566     QList<QGraphicsItem *> newItems;
3567     for (int i = 0; i < 100; ++i) {
3568         QGraphicsItem *item = scene.addRect(QRectF(-25, -25, 50, 50), QPen(Qt::black, 0),
3569                                             QBrush(QColor(rand() % 255, rand() % 255,
3570                                                           rand() % 255, rand() % 255)));
3571         newItems << item;
3572         item->setPos(-1000 + rand() % 2000,
3573                      -1000 + rand() % 2000);
3574         item->rotate(rand() % 90);
3575     }
3576
3577     view.fitInView(scene.itemsBoundingRect());
3578
3579     int n = 0;
3580     foreach (QGraphicsItem *item, newItems) {
3581         group->addToGroup(item);
3582         QCOMPARE(item->group(), group);
3583         if ((n++ % 100) == 0)
3584             QTest::qWait(10);
3585     }
3586 }
3587
3588 void tst_QGraphicsItem::setGroup()
3589 {
3590     QGraphicsItemGroup group1;
3591     QGraphicsItemGroup group2;
3592
3593     QGraphicsRectItem *rect = new QGraphicsRectItem;
3594     QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
3595     QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
3596     rect->setGroup(&group1);
3597     QCOMPARE(rect->group(), &group1);
3598     QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group1);
3599     rect->setGroup(&group2);
3600     QCOMPARE(rect->group(), &group2);
3601     QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group2);
3602     rect->setGroup(0);
3603     QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
3604     QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
3605 }
3606
3607 void tst_QGraphicsItem::setGroup2()
3608 {
3609     QGraphicsScene scene;
3610     QGraphicsItemGroup group;
3611     scene.addItem(&group);
3612
3613     QGraphicsRectItem *rect = scene.addRect(50,50,50,50,Qt::NoPen,Qt::black);
3614     rect->setTransformOriginPoint(50,50);
3615     rect->setRotation(45);
3616     rect->setScale(1.5);
3617     rect->translate(20,20);
3618     group.translate(-30,-40);
3619     group.setRotation(180);
3620     group.setScale(0.5);
3621
3622     QTransform oldSceneTransform = rect->sceneTransform();
3623     rect->setGroup(&group);
3624     QCOMPARE(rect->sceneTransform(), oldSceneTransform);
3625
3626     group.setRotation(20);
3627     group.setScale(2);
3628     rect->setRotation(90);
3629     rect->setScale(0.8);
3630
3631     oldSceneTransform = rect->sceneTransform();
3632     rect->setGroup(0);
3633     QCOMPARE(rect->sceneTransform(), oldSceneTransform);
3634 }
3635
3636 void tst_QGraphicsItem::nestedGroups()
3637 {
3638     QGraphicsItemGroup *group1 = new QGraphicsItemGroup;
3639     QGraphicsItemGroup *group2 = new QGraphicsItemGroup;
3640
3641     QGraphicsRectItem *rect = new QGraphicsRectItem;
3642     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
3643     rect2->setParentItem(rect);
3644
3645     group1->addToGroup(rect);
3646     QCOMPARE(rect->group(), group1);
3647     QCOMPARE(rect2->group(), group1);
3648
3649     group2->addToGroup(group1);
3650     QCOMPARE(rect->group(), group1);
3651     QCOMPARE(rect2->group(), group1);
3652     QCOMPARE(group1->group(), group2);
3653     QCOMPARE(group2->group(), (QGraphicsItemGroup *)0);
3654
3655     QGraphicsScene scene;
3656     scene.addItem(group1);
3657
3658     QCOMPARE(rect->group(), group1);
3659     QCOMPARE(rect2->group(), group1);
3660     QCOMPARE(group1->group(), (QGraphicsItemGroup *)0);
3661     QVERIFY(group2->children().isEmpty());
3662
3663     delete group2;
3664 }
3665
3666 void tst_QGraphicsItem::warpChildrenIntoGroup()
3667 {
3668     QGraphicsScene scene;
3669     QGraphicsRectItem *parentRectItem = scene.addRect(QRectF(0, 0, 100, 100));
3670     QGraphicsRectItem *childRectItem = scene.addRect(QRectF(0, 0, 100, 100));
3671     parentRectItem->rotate(90);
3672     childRectItem->setPos(-50, -25);
3673     childRectItem->setParentItem(parentRectItem);
3674
3675     QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
3676     QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
3677
3678     QGraphicsRectItem *parentOfGroup = scene.addRect(QRectF(0, 0, 100, 100));
3679     parentOfGroup->setPos(-200, -200);
3680     parentOfGroup->scale(2, 2);
3681
3682     QGraphicsItemGroup *group = new QGraphicsItemGroup;
3683     group->setPos(50, 50);
3684     group->setParentItem(parentOfGroup);
3685
3686     QCOMPARE(group->scenePos(), QPointF(-100, -100));
3687
3688     group->addToGroup(childRectItem);
3689
3690     QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
3691     QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
3692 }
3693
3694 void tst_QGraphicsItem::removeFromGroup()
3695 {
3696     QGraphicsScene scene;
3697     QGraphicsRectItem *rect1 = scene.addRect(QRectF(-100, -100, 200, 200));
3698     QGraphicsRectItem *rect2 = scene.addRect(QRectF(100, 100, 200, 200));
3699     rect1->setFlag(QGraphicsItem::ItemIsSelectable);
3700     rect2->setFlag(QGraphicsItem::ItemIsSelectable);
3701     rect1->setSelected(true);
3702     rect2->setSelected(true);
3703
3704     QGraphicsView view(&scene);
3705     view.show();
3706
3707     qApp->processEvents(); // index items
3708     qApp->processEvents(); // emit changed
3709
3710     QGraphicsItemGroup *group = scene.createItemGroup(scene.selectedItems());
3711     QVERIFY(group);
3712     QCOMPARE(group->children().size(), 2);
3713     qApp->processEvents(); // index items
3714     qApp->processEvents(); // emit changed
3715
3716     scene.destroyItemGroup(group); // calls removeFromGroup.
3717
3718     qApp->processEvents(); // index items
3719     qApp->processEvents(); // emit changed
3720
3721     QCOMPARE(scene.items().size(), 2);
3722     QVERIFY(!rect1->group());
3723     QVERIFY(!rect2->group());
3724 }
3725
3726 class ChildEventTester : public QGraphicsRectItem
3727 {
3728 public:
3729     ChildEventTester(const QRectF &rect, QGraphicsItem *parent = 0)
3730         : QGraphicsRectItem(rect, parent), counter(0)
3731     { }
3732
3733     int counter;
3734
3735 protected:
3736     void focusInEvent(QFocusEvent *event)
3737     { ++counter; QGraphicsRectItem::focusInEvent(event); }
3738     void mousePressEvent(QGraphicsSceneMouseEvent *)
3739     { ++counter; }
3740     void mouseMoveEvent(QGraphicsSceneMouseEvent *)
3741     { ++counter; }
3742     void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
3743     { ++counter; }
3744 };
3745
3746 void tst_QGraphicsItem::handlesChildEvents()
3747 {
3748     ChildEventTester *blue = new ChildEventTester(QRectF(0, 0, 100, 100));
3749     ChildEventTester *red = new ChildEventTester(QRectF(0, 0, 50, 50));
3750     ChildEventTester *green = new ChildEventTester(QRectF(0, 0, 25, 25));
3751     ChildEventTester *gray = new ChildEventTester(QRectF(0, 0, 25, 25));
3752     ChildEventTester *yellow = new ChildEventTester(QRectF(0, 0, 50, 50));
3753
3754     blue->setBrush(QBrush(Qt::blue));
3755     red->setBrush(QBrush(Qt::red));
3756     yellow->setBrush(QBrush(Qt::yellow));
3757     green->setBrush(QBrush(Qt::green));
3758     gray->setBrush(QBrush(Qt::gray));
3759     red->setPos(50, 0);
3760     yellow->setPos(50, 50);
3761     green->setPos(25, 0);
3762     gray->setPos(25, 25);
3763     red->setParentItem(blue);
3764     yellow->setParentItem(blue);
3765     green->setParentItem(red);
3766     gray->setParentItem(red);
3767
3768     QGraphicsScene scene;
3769     scene.addItem(blue);
3770
3771     QGraphicsView view(&scene);
3772     view.show();
3773     QVERIFY(QTest::qWaitForWindowExposed(&view));
3774     QTest::qWait(20);
3775
3776     // Pull out the items, closest item first
3777     QList<QGraphicsItem *> items = scene.items(scene.itemsBoundingRect());
3778     QCOMPARE(items.at(0), (QGraphicsItem *)yellow);
3779     QCOMPARE(items.at(1), (QGraphicsItem *)gray);
3780     QCOMPARE(items.at(2), (QGraphicsItem *)green);
3781     QCOMPARE(items.at(3), (QGraphicsItem *)red);
3782     QCOMPARE(items.at(4), (QGraphicsItem *)blue);
3783
3784     QCOMPARE(blue->counter, 0);
3785
3786     // Send events to the toplevel item
3787     QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
3788     QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
3789
3790     pressEvent.setButton(Qt::LeftButton);
3791     pressEvent.setScenePos(blue->mapToScene(5, 5));
3792     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3793     releaseEvent.setButton(Qt::LeftButton);
3794     releaseEvent.setScenePos(blue->mapToScene(5, 5));
3795     releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3796     QApplication::sendEvent(&scene, &pressEvent);
3797     QApplication::sendEvent(&scene, &releaseEvent);
3798
3799     QCOMPARE(blue->counter, 2);
3800
3801     // Send events to a level1 item
3802     pressEvent.setScenePos(red->mapToScene(5, 5));
3803     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3804     releaseEvent.setScenePos(red->mapToScene(5, 5));
3805     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3806     QApplication::sendEvent(&scene, &pressEvent);
3807     QApplication::sendEvent(&scene, &releaseEvent);
3808
3809     QCOMPARE(blue->counter, 2);
3810     QCOMPARE(red->counter, 2);
3811
3812     // Send events to a level2 item
3813     pressEvent.setScenePos(green->mapToScene(5, 5));
3814     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3815     releaseEvent.setScenePos(green->mapToScene(5, 5));
3816     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3817     QApplication::sendEvent(&scene, &pressEvent);
3818     QApplication::sendEvent(&scene, &releaseEvent);
3819
3820     QCOMPARE(blue->counter, 2);
3821     QCOMPARE(red->counter, 2);
3822     QCOMPARE(green->counter, 2);
3823
3824     blue->setHandlesChildEvents(true);
3825
3826     // Send events to a level1 item
3827     pressEvent.setScenePos(red->mapToScene(5, 5));
3828     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3829     releaseEvent.setScenePos(red->mapToScene(5, 5));
3830     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3831     QApplication::sendEvent(&scene, &pressEvent);
3832     QApplication::sendEvent(&scene, &releaseEvent);
3833
3834     QCOMPARE(blue->counter, 4);
3835     QCOMPARE(red->counter, 2);
3836
3837     // Send events to a level2 item
3838     pressEvent.setScenePos(green->mapToScene(5, 5));
3839     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3840     releaseEvent.setScenePos(green->mapToScene(5, 5));
3841     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3842     QApplication::sendEvent(&scene, &pressEvent);
3843     QApplication::sendEvent(&scene, &releaseEvent);
3844
3845     QCOMPARE(blue->counter, 6);
3846     QCOMPARE(red->counter, 2);
3847     QCOMPARE(green->counter, 2);
3848
3849     blue->setHandlesChildEvents(false);
3850
3851     // Send events to a level1 item
3852     pressEvent.setScenePos(red->mapToScene(5, 5));
3853     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3854     releaseEvent.setScenePos(red->mapToScene(5, 5));
3855     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3856     QApplication::sendEvent(&scene, &pressEvent);
3857     QApplication::sendEvent(&scene, &releaseEvent);
3858
3859     QCOMPARE(blue->counter, 6);
3860     QCOMPARE(red->counter, 4);
3861
3862     // Send events to a level2 item
3863     pressEvent.setScenePos(green->mapToScene(5, 5));
3864     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3865     releaseEvent.setScenePos(green->mapToScene(5, 5));
3866     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3867     QApplication::sendEvent(&scene, &pressEvent);
3868     QApplication::sendEvent(&scene, &releaseEvent);
3869
3870     QCOMPARE(blue->counter, 6);
3871     QCOMPARE(red->counter, 4);
3872     QCOMPARE(green->counter, 4);
3873 }
3874
3875 void tst_QGraphicsItem::handlesChildEvents2()
3876 {
3877     ChildEventTester *root = new ChildEventTester(QRectF(0, 0, 10, 10));
3878     root->setHandlesChildEvents(true);
3879     QVERIFY(root->handlesChildEvents());
3880
3881     ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
3882     QVERIFY(!child->handlesChildEvents());
3883
3884     ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10));
3885     ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2);
3886     ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3);
3887     child2->setParentItem(root);
3888     QVERIFY(!child2->handlesChildEvents());
3889     QVERIFY(!child3->handlesChildEvents());
3890     QVERIFY(!child4->handlesChildEvents());
3891
3892     QGraphicsScene scene;
3893     scene.addItem(root);
3894
3895     QGraphicsView view(&scene);
3896     view.show();
3897     QVERIFY(QTest::qWaitForWindowExposed(&view));
3898     QApplication::processEvents();
3899
3900     QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
3901                       view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
3902     QApplication::sendEvent(view.viewport(), &event);
3903
3904     QTRY_COMPARE(root->counter, 1);
3905 }
3906
3907 void tst_QGraphicsItem::handlesChildEvents3()
3908 {
3909     QGraphicsScene scene;
3910     QEvent activate(QEvent::WindowActivate);
3911     QApplication::sendEvent(&scene, &activate);
3912
3913     ChildEventTester *group2 = new ChildEventTester(QRectF(), 0);
3914     ChildEventTester *group1 = new ChildEventTester(QRectF(), group2);
3915     ChildEventTester *leaf = new ChildEventTester(QRectF(), group1);
3916     scene.addItem(group2);
3917
3918     leaf->setFlag(QGraphicsItem::ItemIsFocusable);
3919     group1->setFlag(QGraphicsItem::ItemIsFocusable);
3920     group1->setHandlesChildEvents(true);
3921     group2->setFlag(QGraphicsItem::ItemIsFocusable);
3922     group2->setHandlesChildEvents(true);
3923
3924     leaf->setFocus();
3925     QVERIFY(leaf->hasFocus()); // group2 stole the event, but leaf still got focus
3926     QVERIFY(!group1->hasFocus());
3927     QVERIFY(!group2->hasFocus());
3928     QCOMPARE(leaf->counter, 0);
3929     QCOMPARE(group1->counter, 0);
3930     QCOMPARE(group2->counter, 1);
3931
3932     group1->setFocus();
3933     QVERIFY(group1->hasFocus()); // group2 stole the event, but group1 still got focus
3934     QVERIFY(!leaf->hasFocus());
3935     QVERIFY(!group2->hasFocus());
3936     QCOMPARE(leaf->counter, 0);
3937     QCOMPARE(group1->counter, 0);
3938     QCOMPARE(group2->counter, 2);
3939
3940     group2->setFocus();
3941     QVERIFY(group2->hasFocus()); // group2 stole the event, and now group2 also has focus
3942     QVERIFY(!leaf->hasFocus());
3943     QVERIFY(!group1->hasFocus());
3944     QCOMPARE(leaf->counter, 0);
3945     QCOMPARE(group1->counter, 0);
3946     QCOMPARE(group2->counter, 3);
3947 }
3948
3949
3950 class ChildEventFilterTester : public ChildEventTester
3951 {
3952 public:
3953     ChildEventFilterTester(const QRectF &rect, QGraphicsItem *parent = 0)
3954         : ChildEventTester(rect, parent), filter(QEvent::None)
3955     { }
3956
3957     QEvent::Type filter;
3958
3959 protected:
3960     bool sceneEventFilter(QGraphicsItem *item, QEvent *event)
3961     {
3962         Q_UNUSED(item);
3963         if (event->type() == filter) {
3964             ++counter;
3965             return true;
3966         }
3967         return false;
3968     }
3969 };
3970
3971 void tst_QGraphicsItem::filtersChildEvents()
3972 {
3973     QGraphicsScene scene;
3974     ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
3975     ChildEventFilterTester *filter = new ChildEventFilterTester(QRectF(10, 10, 10, 10), root);
3976     ChildEventTester *child = new ChildEventTester(QRectF(20, 20, 10, 10), filter);
3977
3978     // setup filter
3979     filter->setFiltersChildEvents(true);
3980     filter->filter = QEvent::GraphicsSceneMousePress;
3981
3982     scene.addItem(root);
3983
3984     QGraphicsView view(&scene);
3985     view.show();
3986     QVERIFY(QTest::qWaitForWindowExposed(&view));
3987     QTest::qWait(20);
3988
3989     QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
3990     QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
3991
3992     // send event to child
3993     pressEvent.setButton(Qt::LeftButton);
3994     pressEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
3995     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3996     releaseEvent.setButton(Qt::LeftButton);
3997     releaseEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
3998     releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3999     QApplication::sendEvent(&scene, &pressEvent);
4000     QApplication::sendEvent(&scene, &releaseEvent);
4001
4002     QTRY_COMPARE(child->counter, 1);  // mouse release is not filtered
4003     QCOMPARE(filter->counter, 1); // mouse press is filtered
4004     QCOMPARE(root->counter, 0);
4005
4006     // add another filter
4007     root->setFiltersChildEvents(true);
4008     root->filter = QEvent::GraphicsSceneMouseRelease;
4009
4010     // send event to child
4011     QApplication::sendEvent(&scene, &pressEvent);
4012     QApplication::sendEvent(&scene, &releaseEvent);
4013
4014     QCOMPARE(child->counter, 1);
4015     QCOMPARE(filter->counter, 2); // mouse press is filtered
4016     QCOMPARE(root->counter, 1); // mouse release is filtered
4017
4018     // reparent to another sub-graph
4019     ChildEventTester *parent = new ChildEventTester(QRectF(10, 10, 10, 10), root);
4020     child->setParentItem(parent);
4021
4022     // send event to child
4023     QApplication::sendEvent(&scene, &pressEvent);
4024     QApplication::sendEvent(&scene, &releaseEvent);
4025
4026     QCOMPARE(child->counter, 2); // mouse press is _not_ filtered
4027     QCOMPARE(parent->counter, 0);
4028     QCOMPARE(filter->counter, 2);
4029     QCOMPARE(root->counter, 2); // mouse release is filtered
4030 }
4031
4032 void tst_QGraphicsItem::filtersChildEvents2()
4033 {
4034     ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
4035     root->setFiltersChildEvents(true);
4036     root->filter = QEvent::GraphicsSceneMousePress;
4037     QVERIFY(root->filtersChildEvents());
4038
4039     ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
4040     QVERIFY(!child->filtersChildEvents());
4041
4042     ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10));
4043     ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2);
4044     ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3);
4045
4046     child2->setParentItem(root);
4047     QVERIFY(!child2->filtersChildEvents());
4048     QVERIFY(!child3->filtersChildEvents());
4049     QVERIFY(!child4->filtersChildEvents());
4050
4051     QGraphicsScene scene;
4052     scene.addItem(root);
4053
4054     QGraphicsView view(&scene);
4055     view.show();
4056
4057     QVERIFY(QTest::qWaitForWindowExposed(&view));
4058     QApplication::processEvents();
4059
4060     QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
4061                       view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
4062     QApplication::sendEvent(view.viewport(), &event);
4063
4064     QTRY_COMPARE(root->counter, 1);
4065     QCOMPARE(child->counter, 0);
4066     QCOMPARE(child2->counter, 0);
4067     QCOMPARE(child3->counter, 0);
4068     QCOMPARE(child4->counter, 0);
4069 }
4070
4071 class CustomItem : public QGraphicsItem
4072 {
4073 public:
4074     QRectF boundingRect() const
4075     { return QRectF(-110, -110, 220, 220); }
4076
4077     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
4078     {
4079         for (int x = -100; x <= 100; x += 25)
4080             painter->drawLine(x, -100, x, 100);
4081         for (int y = -100; y <= 100; y += 25)
4082             painter->drawLine(-100, y, 100, y);
4083
4084         QFont font = painter->font();
4085         font.setPointSize(4);
4086         painter->setFont(font);
4087         for (int x = -100; x < 100; x += 25) {
4088             for (int y = -100; y < 100; y += 25) {
4089                 painter->drawText(QRectF(x, y, 25, 25), Qt::AlignCenter, QString("%1x%2").arg(x).arg(y));
4090             }
4091         }
4092     }
4093 };
4094
4095 void tst_QGraphicsItem::ensureVisible()
4096 {
4097     QGraphicsScene scene;
4098     scene.setSceneRect(-200, -200, 400, 400);
4099     QGraphicsItem *item = new CustomItem;
4100     scene.addItem(item);
4101
4102     QGraphicsView view(&scene);
4103     view.setFixedSize(300, 300);
4104     view.show();
4105     QVERIFY(QTest::qWaitForWindowExposed(&view));
4106
4107     for (int i = 0; i < 25; ++i) {
4108         view.scale(qreal(1.06), qreal(1.06));
4109         QApplication::processEvents();
4110     }
4111
4112     item->ensureVisible(-100, -100, 25, 25);
4113     QTest::qWait(25);
4114
4115     for (int x = -100; x < 100; x += 25) {
4116         for (int y = -100; y < 100; y += 25) {
4117             int xmargin = rand() % 75;
4118             int ymargin = rand() % 75;
4119             item->ensureVisible(x, y, 25, 25, xmargin, ymargin);
4120             QApplication::processEvents();
4121
4122             QPolygonF viewScenePoly;
4123             viewScenePoly << view.mapToScene(view.rect().topLeft())
4124                           << view.mapToScene(view.rect().topRight())
4125                           << view.mapToScene(view.rect().bottomRight())
4126                           << view.mapToScene(view.rect().bottomLeft());
4127
4128             QVERIFY(scene.items(viewScenePoly).contains(item));
4129
4130             QPainterPath path;
4131             path.addPolygon(viewScenePoly);
4132             QVERIFY(path.contains(item->mapToScene(x + 12, y + 12)));
4133
4134             QPolygonF viewScenePolyMinusMargins;
4135             viewScenePolyMinusMargins << view.mapToScene(view.rect().topLeft() + QPoint(xmargin, ymargin))
4136                           << view.mapToScene(view.rect().topRight() + QPoint(-xmargin, ymargin))
4137                           << view.mapToScene(view.rect().bottomRight() + QPoint(-xmargin, -ymargin))
4138                           << view.mapToScene(view.rect().bottomLeft() + QPoint(xmargin, -ymargin));
4139
4140             QPainterPath path2;
4141             path2.addPolygon(viewScenePolyMinusMargins);
4142             QVERIFY(path2.contains(item->mapToScene(x + 12, y + 12)));
4143         }
4144     }
4145
4146     item->ensureVisible(100, 100, 25, 25);
4147     QTest::qWait(25);
4148 }
4149
4150 #ifndef QTEST_NO_CURSOR
4151 void tst_QGraphicsItem::cursor()
4152 {
4153     QGraphicsScene scene;
4154     QGraphicsRectItem *item1 = scene.addRect(QRectF(0, 0, 50, 50));
4155     QGraphicsRectItem *item2 = scene.addRect(QRectF(0, 0, 50, 50));
4156     item1->setPos(-100, 0);
4157     item2->setPos(50, 0);
4158
4159     QVERIFY(!item1->hasCursor());
4160     QVERIFY(!item2->hasCursor());
4161
4162     item1->setCursor(Qt::IBeamCursor);
4163     item2->setCursor(Qt::PointingHandCursor);
4164
4165     QVERIFY(item1->hasCursor());
4166     QVERIFY(item2->hasCursor());
4167
4168     item1->setCursor(QCursor());
4169     item2->setCursor(QCursor());
4170
4171     QVERIFY(item1->hasCursor());
4172     QVERIFY(item2->hasCursor());
4173
4174     item1->unsetCursor();
4175     item2->unsetCursor();
4176
4177     QVERIFY(!item1->hasCursor());
4178     QVERIFY(!item2->hasCursor());
4179
4180     item1->setCursor(Qt::IBeamCursor);
4181     item2->setCursor(Qt::PointingHandCursor);
4182
4183     QWidget topLevel;
4184     QGraphicsView view(&scene,&topLevel);
4185     view.setFixedSize(200, 100);
4186     topLevel.show();
4187     QTest::mouseMove(&view, view.rect().center());
4188
4189     QTest::qWait(25);
4190
4191     QCursor cursor = view.viewport()->cursor();
4192
4193     {
4194         QMouseEvent event(QEvent::MouseMove, QPoint(100, 50), Qt::NoButton, 0, 0);
4195         QApplication::sendEvent(view.viewport(), &event);
4196     }
4197
4198     QTest::qWait(25);
4199
4200     QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
4201
4202     {
4203         QTest::mouseMove(view.viewport(), view.mapFromScene(item1->sceneBoundingRect().center()));
4204         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
4205         QApplication::sendEvent(view.viewport(), &event);
4206     }
4207
4208     QCOMPARE(view.viewport()->cursor().shape(), item1->cursor().shape());
4209
4210     {
4211         QTest::mouseMove(view.viewport(), view.mapFromScene(item2->sceneBoundingRect().center()));
4212         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item2->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
4213         QApplication::sendEvent(view.viewport(), &event);
4214     }
4215
4216     QTest::qWait(25);
4217
4218     QCOMPARE(view.viewport()->cursor().shape(), item2->cursor().shape());
4219
4220     {
4221         QTest::mouseMove(view.viewport(), view.rect().center());
4222         QMouseEvent event(QEvent::MouseMove, QPoint(100, 25), Qt::NoButton, 0, 0);
4223         QApplication::sendEvent(view.viewport(), &event);
4224     }
4225
4226     QTest::qWait(25);
4227
4228     QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
4229 }
4230 #endif
4231 /*
4232 void tst_QGraphicsItem::textControlGetterSetter()
4233 {
4234     QGraphicsTextItem *item = new QGraphicsTextItem;
4235     QVERIFY(item->textControl()->parent() == item);
4236     QPointer<QWidgetTextControl> control = item->textControl();
4237     delete item;
4238     QVERIFY(!control);
4239
4240     item = new QGraphicsTextItem;
4241
4242     QPointer<QWidgetTextControl> oldControl = control;
4243     control = new QWidgetTextControl;
4244
4245     item->setTextControl(control);
4246     QVERIFY(item->textControl() == control);
4247     QVERIFY(!control->parent());
4248     QVERIFY(!oldControl);
4249
4250     // set some text to give it a size, to test that
4251     // setTextControl (re)connects signals
4252     const QRectF oldBoundingRect = item->boundingRect();
4253     QVERIFY(oldBoundingRect.isValid());
4254     item->setPlainText("Some text");
4255     item->adjustSize();
4256     QVERIFY(item->boundingRect().isValid());
4257     QVERIFY(item->boundingRect() != oldBoundingRect);
4258
4259     // test that on setting a control the item size
4260     // is adjusted
4261     oldControl = control;
4262     control = new QWidgetTextControl;
4263     control->setPlainText("foo!");
4264     item->setTextControl(control);
4265     QCOMPARE(item->boundingRect().size(), control->document()->documentLayout()->documentSize());
4266
4267     QVERIFY(oldControl);
4268     delete oldControl;
4269
4270     delete item;
4271     QVERIFY(control);
4272     delete control;
4273 }
4274 */
4275
4276 void tst_QGraphicsItem::defaultItemTest_QGraphicsLineItem()
4277 {
4278     QGraphicsLineItem item;
4279     QCOMPARE(item.line(), QLineF());
4280     QCOMPARE(item.pen(), QPen());
4281     QCOMPARE(item.shape(), QPainterPath());
4282
4283     item.setPen(QPen(Qt::black, 1));
4284     QCOMPARE(item.pen(), QPen(Qt::black, 1));
4285     item.setLine(QLineF(0, 0, 10, 0));
4286     QCOMPARE(item.line(), QLineF(0, 0, 10, 0));
4287     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 11, 1));
4288     QCOMPARE(item.shape().elementCount(), 11);
4289
4290     QPainterPath path;
4291     path.moveTo(0, -0.5);
4292     path.lineTo(10, -0.5);
4293     path.lineTo(10.5, -0.5);
4294     path.lineTo(10.5, 0.5);
4295     path.lineTo(10, 0.5);
4296     path.lineTo(0, 0.5);
4297     path.lineTo(-0.5, 0.5);
4298     path.lineTo(-0.5, -0.5);
4299     path.lineTo(0, -0.5);
4300     path.lineTo(0, 0);
4301     path.lineTo(10, 0);
4302     path.closeSubpath();
4303
4304     for (int i = 0; i < 11; ++i)
4305         QCOMPARE(QPointF(item.shape().elementAt(i)), QPointF(path.elementAt(i)));
4306 }
4307
4308 void tst_QGraphicsItem::defaultItemTest_QGraphicsPixmapItem()
4309 {
4310     QGraphicsPixmapItem item;
4311     QVERIFY(item.pixmap().isNull());
4312     QCOMPARE(item.offset(), QPointF());
4313     QCOMPARE(item.transformationMode(), Qt::FastTransformation);
4314
4315     QPixmap pixmap(300, 200);
4316     pixmap.fill(Qt::red);
4317     item.setPixmap(pixmap);
4318     QCOMPARE(item.pixmap(), pixmap);
4319
4320     item.setTransformationMode(Qt::FastTransformation);
4321     QCOMPARE(item.transformationMode(), Qt::FastTransformation);
4322     item.setTransformationMode(Qt::SmoothTransformation);
4323     QCOMPARE(item.transformationMode(), Qt::SmoothTransformation);
4324
4325     item.setOffset(-15, -15);
4326     QCOMPARE(item.offset(), QPointF(-15, -15));
4327     item.setOffset(QPointF(-10, -10));
4328     QCOMPARE(item.offset(), QPointF(-10, -10));
4329
4330     QCOMPARE(item.boundingRect(), QRectF(-10, -10, 300, 200));
4331 }
4332
4333 void tst_QGraphicsItem::defaultItemTest_QGraphicsTextItem()
4334 {
4335     QGraphicsTextItem *text = new QGraphicsTextItem;
4336     QVERIFY(!text->openExternalLinks());
4337     QVERIFY(text->textCursor().isNull());
4338     QCOMPARE(text->defaultTextColor(), QPalette().color(QPalette::Text));
4339     QVERIFY(text->document() != 0);
4340     QCOMPARE(text->font(), QApplication::font());
4341     QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::NoTextInteraction));
4342     QCOMPARE(text->textWidth(), -1.0);
4343     QCOMPARE(text->toPlainText(), QString(""));
4344
4345     QGraphicsScene scene;
4346     scene.addItem(text);
4347     text->setPlainText("Hello world");
4348     text->setFlag(QGraphicsItem::ItemIsMovable);
4349
4350     {
4351         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
4352         event.setScenePos(QPointF(1, 1));
4353         event.setButton(Qt::LeftButton);
4354         event.setButtons(Qt::LeftButton);
4355         QApplication::sendEvent(&scene, &event);
4356         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
4357         event2.setScenePos(QPointF(11, 11));
4358         event2.setButton(Qt::LeftButton);
4359         event2.setButtons(Qt::LeftButton);
4360         QApplication::sendEvent(&scene, &event2);
4361     }
4362
4363     QCOMPARE(text->pos(), QPointF(10, 10));
4364
4365     text->setTextInteractionFlags(Qt::NoTextInteraction);
4366     QVERIFY(!(text->flags() & QGraphicsItem::ItemAcceptsInputMethod));
4367     text->setTextInteractionFlags(Qt::TextEditorInteraction);
4368     QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::TextEditorInteraction));
4369     QVERIFY(text->flags() & QGraphicsItem::ItemAcceptsInputMethod);
4370
4371     {
4372         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
4373         event2.setScenePos(QPointF(21, 21));
4374         event2.setButton(Qt::LeftButton);
4375         event2.setButtons(Qt::LeftButton);
4376         QApplication::sendEvent(&scene, &event2);
4377     }
4378
4379     QCOMPARE(text->pos(), QPointF(20, 20)); // clicked on edge, item moved
4380 }
4381
4382 void tst_QGraphicsItem::defaultItemTest_QGraphicsEllipseItem()
4383 {
4384     QGraphicsEllipseItem item;
4385     QVERIFY(item.rect().isNull());
4386     QVERIFY(item.boundingRect().isNull());
4387     QVERIFY(item.shape().isEmpty());
4388     QCOMPARE(item.spanAngle(), 360 * 16);
4389     QCOMPARE(item.startAngle(), 0);
4390
4391     item.setRect(0, 0, 100, 100);
4392     QCOMPARE(item.boundingRect(), QRectF(0, 0, 100, 100));
4393
4394     item.setSpanAngle(90 * 16);
4395     qFuzzyCompare(item.boundingRect().left(), qreal(50.0));
4396     qFuzzyCompare(item.boundingRect().top(), qreal(0.0));
4397     qFuzzyCompare(item.boundingRect().width(), qreal(50.0));
4398     qFuzzyCompare(item.boundingRect().height(), qreal(50.0));
4399
4400     item.setPen(QPen(Qt::black, 1));
4401     QCOMPARE(item.boundingRect(), QRectF(49.5, -0.5, 51, 51));
4402
4403     item.setSpanAngle(180 * 16);
4404     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 51));
4405
4406     item.setSpanAngle(360 * 16);
4407     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 101));
4408 }
4409
4410 class ItemChangeTester : public QGraphicsRectItem
4411 {
4412 public:
4413     ItemChangeTester()
4414     { setFlag(ItemSendsGeometryChanges); clear(); }
4415     ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent)
4416     { setFlag(ItemSendsGeometryChanges); clear(); }
4417
4418     void clear()
4419     {
4420         itemChangeReturnValue = QVariant();
4421         itemSceneChangeTargetScene = 0;
4422         changes.clear();
4423         values.clear();
4424         oldValues.clear();
4425     }
4426
4427     QVariant itemChangeReturnValue;
4428     QGraphicsScene *itemSceneChangeTargetScene;
4429
4430     QList<GraphicsItemChange> changes;
4431     QList<QVariant> values;
4432     QList<QVariant> oldValues;
4433 protected:
4434     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
4435     {
4436         changes << change;
4437         values << value;
4438         switch (change) {
4439         case QGraphicsItem::ItemPositionChange:
4440             oldValues << pos();
4441             break;
4442         case QGraphicsItem::ItemPositionHasChanged:
4443             break;
4444         case QGraphicsItem::ItemMatrixChange: {
4445             QVariant variant;
4446             variant.setValue<QMatrix>(matrix());
4447             oldValues << variant;
4448         }
4449             break;
4450         case QGraphicsItem::ItemTransformChange: {
4451             QVariant variant;
4452             variant.setValue<QTransform>(transform());
4453             oldValues << variant;
4454         }
4455             break;
4456         case QGraphicsItem::ItemTransformHasChanged:
4457             break;
4458         case QGraphicsItem::ItemVisibleChange:
4459             oldValues << isVisible();
4460             break;
4461         case QGraphicsItem::ItemVisibleHasChanged:
4462             break;
4463         case QGraphicsItem::ItemEnabledChange:
4464             oldValues << isEnabled();
4465             break;
4466         case QGraphicsItem::ItemEnabledHasChanged:
4467             break;
4468         case QGraphicsItem::ItemSelectedChange:
4469             oldValues << isSelected();
4470             break;
4471         case QGraphicsItem::ItemSelectedHasChanged:
4472             break;
4473         case QGraphicsItem::ItemParentChange:
4474             oldValues << QVariant::fromValue<void *>(parentItem());
4475             break;
4476         case QGraphicsItem::ItemParentHasChanged:
4477             break;
4478         case QGraphicsItem::ItemChildAddedChange:
4479             oldValues << children().size();
4480             break;
4481         case QGraphicsItem::ItemChildRemovedChange:
4482             oldValues << children().size();
4483             break;
4484         case QGraphicsItem::ItemSceneChange:
4485             oldValues << QVariant::fromValue<QGraphicsScene *>(scene());
4486             if (itemSceneChangeTargetScene
4487                 && qvariant_cast<QGraphicsScene *>(value)
4488                 && itemSceneChangeTargetScene != qvariant_cast<QGraphicsScene *>(value)) {
4489                 return QVariant::fromValue<QGraphicsScene *>(itemSceneChangeTargetScene);
4490             }
4491             return value;
4492         case QGraphicsItem::ItemSceneHasChanged:
4493             break;
4494         case QGraphicsItem::ItemCursorChange:
4495 #ifndef QTEST_NO_CURSOR
4496             oldValues << cursor();
4497 #endif
4498             break;
4499         case QGraphicsItem::ItemCursorHasChanged:
4500             break;
4501         case QGraphicsItem::ItemToolTipChange:
4502             oldValues << toolTip();
4503             break;
4504         case QGraphicsItem::ItemToolTipHasChanged:
4505             break;
4506         case QGraphicsItem::ItemFlagsChange:
4507             oldValues << quint32(flags());
4508             break;
4509         case QGraphicsItem::ItemFlagsHaveChanged:
4510             break;
4511         case QGraphicsItem::ItemZValueChange:
4512             oldValues << zValue();
4513             break;
4514         case QGraphicsItem::ItemZValueHasChanged:
4515             break;
4516         case QGraphicsItem::ItemOpacityChange:
4517             oldValues << opacity();
4518             break;
4519         case QGraphicsItem::ItemOpacityHasChanged:
4520             break;
4521         case QGraphicsItem::ItemScenePositionHasChanged:
4522             break;
4523         case QGraphicsItem::ItemRotationChange:
4524             oldValues << rotation();
4525             break;
4526         case QGraphicsItem::ItemRotationHasChanged:
4527             break;
4528         case QGraphicsItem::ItemScaleChange:
4529             oldValues << scale();
4530             break;
4531         case QGraphicsItem::ItemScaleHasChanged:
4532             break;
4533         case QGraphicsItem::ItemTransformOriginPointChange:
4534             oldValues << transformOriginPoint();
4535             break;
4536         case QGraphicsItem::ItemTransformOriginPointHasChanged:
4537             break;
4538         }
4539         return itemChangeReturnValue.isValid() ? itemChangeReturnValue : value;
4540     }
4541 };
4542
4543 void tst_QGraphicsItem::itemChange()
4544 {
4545     ItemChangeTester tester;
4546     tester.itemSceneChangeTargetScene = 0;
4547
4548     ItemChangeTester testerHelper;
4549     QVERIFY(tester.changes.isEmpty());
4550     QVERIFY(tester.values.isEmpty());
4551
4552     int changeCount = 0;
4553     {
4554         // ItemEnabledChange
4555         tester.itemChangeReturnValue = true;
4556         tester.setEnabled(false);
4557         ++changeCount;
4558         ++changeCount; // HasChanged
4559         QCOMPARE(tester.changes.size(), changeCount);
4560         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemEnabledChange);
4561         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemEnabledHasChanged);
4562         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
4563         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
4564         QCOMPARE(tester.oldValues.last(), QVariant(true));
4565         QCOMPARE(tester.isEnabled(), true);
4566     }
4567     {
4568         // ItemMatrixChange / ItemTransformHasChanged
4569         tester.itemChangeReturnValue.setValue<QMatrix>(QMatrix().rotate(90));
4570         tester.setMatrix(QMatrix().translate(50, 0), true);
4571         ++changeCount; // notification sent too
4572         QCOMPARE(tester.changes.size(), ++changeCount);
4573         QCOMPARE(int(tester.changes.at(tester.changes.size() - 2)), int(QGraphicsItem::ItemMatrixChange));
4574         QCOMPARE(int(tester.changes.last()), int(QGraphicsItem::ItemTransformHasChanged));
4575         QCOMPARE(qvariant_cast<QMatrix>(tester.values.at(tester.values.size() - 2)),
4576                  QMatrix().translate(50, 0));
4577         QCOMPARE(tester.values.last(), QVariant(QTransform(QMatrix().rotate(90))));
4578         QVariant variant;
4579         variant.setValue<QMatrix>(QMatrix());
4580         QCOMPARE(tester.oldValues.last(), variant);
4581         QCOMPARE(tester.matrix(), QMatrix().rotate(90));
4582     }
4583     {
4584         tester.resetTransform();
4585         ++changeCount;
4586         ++changeCount; // notification sent too
4587
4588         // ItemTransformChange / ItemTransformHasChanged
4589         tester.itemChangeReturnValue.setValue<QTransform>(QTransform().rotate(90));
4590         tester.translate(50, 0);
4591         ++changeCount; // notification sent too
4592         ++changeCount;
4593         QCOMPARE(tester.changes.size(), changeCount);
4594         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformChange);
4595         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformHasChanged);
4596         QCOMPARE(qvariant_cast<QTransform>(tester.values.at(tester.values.size() - 2)),
4597                  QTransform().translate(50, 0));
4598         QCOMPARE(qvariant_cast<QTransform>(tester.values.at(tester.values.size() - 1)),
4599                  QTransform().rotate(90));
4600         QVariant variant;
4601         variant.setValue<QTransform>(QTransform());
4602         QCOMPARE(tester.oldValues.last(), variant);
4603         QCOMPARE(tester.transform(), QTransform().rotate(90));
4604     }
4605     {
4606         // ItemPositionChange / ItemPositionHasChanged
4607         tester.itemChangeReturnValue = QPointF(42, 0);
4608         tester.setPos(0, 42);
4609         ++changeCount; // notification sent too
4610         ++changeCount;
4611         QCOMPARE(tester.changes.size(), changeCount);
4612         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemPositionChange);
4613         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemPositionHasChanged);
4614         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(0, 42)));
4615         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(42, 0)));
4616         QCOMPARE(tester.oldValues.last(), QVariant(QPointF()));
4617         QCOMPARE(tester.pos(), QPointF(42, 0));
4618     }
4619     {
4620         // ItemZValueChange / ItemZValueHasChanged
4621         tester.itemChangeReturnValue = qreal(2.0);
4622         tester.setZValue(1.0);
4623         ++changeCount; // notification sent too
4624         ++changeCount;
4625         QCOMPARE(tester.changes.size(), changeCount);
4626         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemZValueChange);
4627         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemZValueHasChanged);
4628         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.0)));
4629         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0)));
4630         QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0)));
4631         QCOMPARE(tester.zValue(), qreal(2.0));
4632     }
4633     {
4634         // ItemRotationChange / ItemRotationHasChanged
4635         tester.itemChangeReturnValue = qreal(15.0);
4636         tester.setRotation(10.0);
4637         ++changeCount; // notification sent too
4638         ++changeCount;
4639         QCOMPARE(tester.changes.size(), changeCount);
4640         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemRotationChange);
4641         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemRotationHasChanged);
4642         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(10.0)));
4643         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(15.0)));
4644         QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0)));
4645         QCOMPARE(tester.rotation(), qreal(15.0));
4646     }
4647     {
4648         // ItemScaleChange / ItemScaleHasChanged
4649         tester.itemChangeReturnValue = qreal(2.0);
4650         tester.setScale(1.5);
4651         ++changeCount; // notification sent too
4652         ++changeCount;
4653         QCOMPARE(tester.changes.size(), changeCount);
4654         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemScaleChange);
4655         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemScaleHasChanged);
4656         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.5)));
4657         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0)));
4658         QCOMPARE(tester.oldValues.last(), QVariant(qreal(1.0)));
4659         QCOMPARE(tester.scale(), qreal(2.0));
4660     }
4661     {
4662         // ItemTransformOriginPointChange / ItemTransformOriginPointHasChanged
4663         tester.itemChangeReturnValue = QPointF(2.0, 2.0);
4664         tester.setTransformOriginPoint(1.0, 1.0);
4665         ++changeCount; // notification sent too
4666         ++changeCount;
4667         QCOMPARE(tester.changes.size(), changeCount);
4668         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformOriginPointChange);
4669         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformOriginPointHasChanged);
4670         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(1.0, 1.0)));
4671         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(2.0, 2.0)));
4672         QCOMPARE(tester.oldValues.last(), QVariant(QPointF(0.0, 0.0)));
4673         QCOMPARE(tester.transformOriginPoint(), QPointF(2.0, 2.0));
4674     }
4675     {
4676         // ItemFlagsChange
4677         tester.itemChangeReturnValue = QGraphicsItem::ItemIsSelectable;
4678         tester.setFlag(QGraphicsItem::ItemIsSelectable, false);
4679         QCOMPARE(tester.changes.size(), changeCount);  // No change
4680         tester.setFlag(QGraphicsItem::ItemIsSelectable, true);
4681         ++changeCount;
4682         ++changeCount; // ItemFlagsHasChanged
4683         QCOMPARE(tester.changes.size(), changeCount);
4684         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemFlagsChange);
4685         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemFlagsHaveChanged);
4686         QVariant expectedFlags = QVariant::fromValue<quint32>(QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges));
4687         QCOMPARE(tester.values.at(tester.values.size() - 2), expectedFlags);
4688         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant::fromValue<quint32>((quint32)QGraphicsItem::ItemIsSelectable));
4689     }
4690     {
4691         // ItemSelectedChange
4692         tester.setSelected(false);
4693         QCOMPARE(tester.changes.size(), changeCount); // No change :-)
4694         tester.itemChangeReturnValue = true;
4695         tester.setSelected(true);
4696         ++changeCount;
4697         ++changeCount; // ItemSelectedHasChanged
4698         QCOMPARE(tester.changes.size(), changeCount);
4699         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedChange);
4700         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSelectedHasChanged);
4701         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(true));
4702         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
4703         QCOMPARE(tester.oldValues.last(), QVariant(false));
4704         QCOMPARE(tester.isSelected(), true);
4705
4706         tester.itemChangeReturnValue = false;
4707         tester.setSelected(true);
4708
4709         // the value hasn't changed to the itemChange return value
4710         // bacause itemChange is never called (true -> true is a noop).
4711         QCOMPARE(tester.isSelected(), true);
4712     }
4713     {
4714         // ItemVisibleChange
4715         tester.itemChangeReturnValue = false;
4716         QVERIFY(tester.isVisible());
4717         tester.setVisible(false);
4718         ++changeCount; // ItemVisibleChange
4719         ++changeCount; // ItemSelectedChange
4720         ++changeCount; // ItemSelectedHasChanged
4721         ++changeCount; // ItemVisibleHasChanged
4722         QCOMPARE(tester.changes.size(), changeCount);
4723         QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemVisibleChange);
4724         QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSelectedChange);
4725         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedHasChanged);
4726         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemVisibleHasChanged);
4727         QCOMPARE(tester.values.at(tester.values.size() - 4), QVariant(false));
4728         QCOMPARE(tester.values.at(tester.values.size() - 3), QVariant(false));
4729         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
4730         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(false));
4731         QCOMPARE(tester.isVisible(), false);
4732     }
4733     {
4734         // ItemParentChange
4735         tester.itemChangeReturnValue.setValue<QGraphicsItem *>(0);
4736         tester.setParentItem(&testerHelper);
4737         QCOMPARE(tester.changes.size(), ++changeCount);
4738         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemParentChange);
4739         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4740         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.oldValues.last()), (QGraphicsItem *)0);
4741         QCOMPARE(tester.parentItem(), (QGraphicsItem *)0);
4742     }
4743     {
4744         // ItemOpacityChange
4745         tester.itemChangeReturnValue = 1.0;
4746         tester.setOpacity(0.7);
4747         QCOMPARE(tester.changes.size(), ++changeCount);
4748         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemOpacityChange);
4749         QVERIFY(qFuzzyCompare(qreal(tester.values.last().toDouble()), qreal(0.7)));
4750         QCOMPARE(tester.oldValues.last().toDouble(), double(1.0));
4751         QCOMPARE(tester.opacity(), qreal(1.0));
4752         tester.itemChangeReturnValue = 0.7;
4753         tester.setOpacity(0.7);
4754         ++changeCount; // ItemOpacityChange
4755         ++changeCount; // ItemOpacityHasChanged
4756         QCOMPARE(tester.changes.size(), changeCount);
4757         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemOpacityChange);
4758         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemOpacityHasChanged);
4759         QCOMPARE(tester.opacity(), qreal(0.7));
4760     }
4761     {
4762         // ItemChildAddedChange
4763         tester.itemChangeReturnValue.clear();
4764         testerHelper.setParentItem(&tester);
4765         QCOMPARE(tester.changes.size(), ++changeCount);
4766         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildAddedChange);
4767         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4768     }
4769     {
4770         // ItemChildRemovedChange 1
4771         testerHelper.setParentItem(0);
4772         QCOMPARE(tester.changes.size(), ++changeCount);
4773         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildRemovedChange);
4774         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4775
4776         // ItemChildRemovedChange 1
4777         ItemChangeTester *test = new ItemChangeTester;
4778         test->itemSceneChangeTargetScene = 0;
4779         int count = 0;
4780         QGraphicsScene *scene = new QGraphicsScene;
4781         scene->addItem(test);
4782         count = test->changes.size();
4783         //We test here the fact that when a child is deleted the parent receive only one ItemChildRemovedChange
4784         QGraphicsRectItem *child = new QGraphicsRectItem(test);
4785         //We received ItemChildAddedChange
4786         QCOMPARE(test->changes.size(), ++count);
4787         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildAddedChange);
4788         delete child;
4789         child = 0;
4790         QCOMPARE(test->changes.size(), ++count);
4791         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
4792
4793         ItemChangeTester *childTester = new ItemChangeTester(test);
4794         //Changes contains all sceneHasChanged and so on, we don't want to test that
4795         int childCount = childTester->changes.size();
4796         //We received ItemChildAddedChange
4797         QCOMPARE(test->changes.size(), ++count);
4798         child = new QGraphicsRectItem(childTester);
4799         //We received ItemChildAddedChange
4800         QCOMPARE(childTester->changes.size(), ++childCount);
4801         QCOMPARE(childTester->changes.last(), QGraphicsItem::ItemChildAddedChange);
4802         //Delete the child of the top level with all its children
4803         delete childTester;
4804         //Only one removal
4805         QCOMPARE(test->changes.size(), ++count);
4806         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
4807         delete scene;
4808     }
4809     {
4810         // ItemChildRemovedChange 2
4811         ItemChangeTester parent;
4812         ItemChangeTester *child = new ItemChangeTester;
4813         child->setParentItem(&parent);
4814         QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildAddedChange);
4815         QCOMPARE(qvariant_cast<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
4816         delete child;
4817         QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildRemovedChange);
4818         QCOMPARE(qvariant_cast<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
4819     }
4820     {
4821         // !!! Note: If this test crashes because of double-deletion, there's
4822         // a bug somewhere in QGraphicsScene or QGraphicsItem.
4823
4824         // ItemSceneChange
4825         QGraphicsScene scene;
4826         QGraphicsScene scene2;
4827         scene.addItem(&tester);
4828         ++changeCount; // ItemSceneChange (scene)
4829         ++changeCount; // ItemSceneHasChanged (scene)
4830         QCOMPARE(tester.changes.size(), changeCount);
4831
4832         QCOMPARE(tester.scene(), &scene);
4833         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4834         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4835         // Item's old value was 0
4836         // Item's current value is scene
4837         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
4838         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene);
4839         scene2.addItem(&tester);
4840         ++changeCount; // ItemSceneChange (0) was: (scene)
4841         ++changeCount; // ItemSceneHasChanged (0)
4842         ++changeCount; // ItemSceneChange (scene2) was: (0)
4843         ++changeCount; // ItemSceneHasChanged (scene2)
4844         QCOMPARE(tester.changes.size(), changeCount);
4845
4846         QCOMPARE(tester.scene(), &scene2);
4847         QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemSceneChange);
4848         QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSceneHasChanged);
4849         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4850         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4851         // Item's last old value was scene
4852         // Item's last current value is 0
4853
4854         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 2)), (QGraphicsScene *)&scene);
4855         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 1)), (QGraphicsScene *)0);
4856         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 4)), (QGraphicsScene *)0);
4857         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)0);
4858         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene2);
4859         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene2);
4860         // Item's last old value was 0
4861         // Item's last current value is scene2
4862         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
4863         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene2);
4864
4865         scene2.removeItem(&tester);
4866         ++changeCount; // ItemSceneChange (0) was: (scene2)
4867         ++changeCount; // ItemSceneHasChanged (0)
4868         QCOMPARE(tester.changes.size(), changeCount);
4869
4870         QCOMPARE(tester.scene(), (QGraphicsScene *)0);
4871         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4872         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4873         // Item's last old value was scene2
4874         // Item's last current value is 0
4875         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)&scene2);
4876         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)0);
4877         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)0);
4878
4879         tester.itemSceneChangeTargetScene = &scene;
4880         scene2.addItem(&tester);
4881         ++changeCount; // ItemSceneChange (scene2) was: (0)
4882         ++changeCount; // ItemSceneChange (scene) was: (0)
4883         ++changeCount; // ItemSceneHasChanged (scene)
4884         QCOMPARE(tester.values.size(), changeCount);
4885
4886         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)&scene2);
4887         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene);
4888         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene);
4889
4890         QCOMPARE(tester.scene(), &scene);
4891         tester.itemSceneChangeTargetScene = 0;
4892         tester.itemChangeReturnValue = QVariant();
4893         scene.removeItem(&tester);
4894         ++changeCount; // ItemSceneChange
4895         ++changeCount; // ItemSceneHasChanged
4896         QCOMPARE(tester.scene(), (QGraphicsScene *)0);
4897     }
4898     {
4899         // ItemToolTipChange/ItemToolTipHasChanged
4900         const QString toolTip(QLatin1String("I'm soo cool"));
4901         const QString overridenToolTip(QLatin1String("No, you are not soo cool"));
4902         tester.itemChangeReturnValue = overridenToolTip;
4903         tester.setToolTip(toolTip);
4904         ++changeCount; // ItemToolTipChange
4905         ++changeCount; // ItemToolTipHasChanged
4906         QCOMPARE(tester.changes.size(), changeCount);
4907         QCOMPARE(tester.changes.at(changeCount - 2), QGraphicsItem::ItemToolTipChange);
4908         QCOMPARE(tester.values.at(changeCount - 2).toString(), toolTip);
4909         QCOMPARE(tester.changes.at(changeCount - 1), QGraphicsItem::ItemToolTipHasChanged);
4910         QCOMPARE(tester.values.at(changeCount - 1).toString(), overridenToolTip);
4911         QCOMPARE(tester.toolTip(), overridenToolTip);
4912         tester.itemChangeReturnValue = QVariant();
4913     }
4914 }
4915
4916 class EventFilterTesterItem : public QGraphicsLineItem
4917 {
4918 public:
4919     QList<QEvent::Type> filteredEvents;
4920     QList<QGraphicsItem *> filteredEventReceivers;
4921     bool handlesSceneEvents;
4922
4923     QList<QEvent::Type> receivedEvents;
4924
4925     EventFilterTesterItem() : handlesSceneEvents(false) {}
4926
4927 protected:
4928     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
4929     {
4930         filteredEvents << event->type();
4931         filteredEventReceivers << watched;
4932         return handlesSceneEvents;
4933     }
4934
4935     bool sceneEvent(QEvent *event)
4936     {
4937         return QGraphicsLineItem::sceneEvent(event);
4938     }
4939 };
4940
4941 void tst_QGraphicsItem::sceneEventFilter()
4942 {
4943     QGraphicsScene scene;
4944
4945     QGraphicsView view(&scene);
4946     view.show();
4947     QApplication::setActiveWindow(&view);
4948     QVERIFY(QTest::qWaitForWindowActive(&view));
4949
4950     QGraphicsTextItem *text1 = scene.addText(QLatin1String("Text1"));
4951     QGraphicsTextItem *text2 = scene.addText(QLatin1String("Text2"));
4952     QGraphicsTextItem *text3 = scene.addText(QLatin1String("Text3"));
4953     text1->setFlag(QGraphicsItem::ItemIsFocusable);
4954     text2->setFlag(QGraphicsItem::ItemIsFocusable);
4955     text3->setFlag(QGraphicsItem::ItemIsFocusable);
4956
4957     EventFilterTesterItem *tester = new EventFilterTesterItem;
4958     scene.addItem(tester);
4959
4960     QTRY_VERIFY(!text1->hasFocus());
4961     text1->installSceneEventFilter(tester);
4962     text1->setFocus();
4963     QTRY_VERIFY(text1->hasFocus());
4964
4965     QCOMPARE(tester->filteredEvents.size(), 1);
4966     QCOMPARE(tester->filteredEvents.at(0), QEvent::FocusIn);
4967     QCOMPARE(tester->filteredEventReceivers.at(0), static_cast<QGraphicsItem *>(text1));
4968
4969     text2->installSceneEventFilter(tester);
4970     text3->installSceneEventFilter(tester);
4971
4972     text2->setFocus();
4973     text3->setFocus();
4974
4975     QCOMPARE(tester->filteredEvents.size(), 5);
4976     QCOMPARE(tester->filteredEvents.at(1), QEvent::FocusOut);
4977     QCOMPARE(tester->filteredEventReceivers.at(1), static_cast<QGraphicsItem *>(text1));
4978     QCOMPARE(tester->filteredEvents.at(2), QEvent::FocusIn);
4979     QCOMPARE(tester->filteredEventReceivers.at(2), static_cast<QGraphicsItem *>(text2));
4980     QCOMPARE(tester->filteredEvents.at(3), QEvent::FocusOut);
4981     QCOMPARE(tester->filteredEventReceivers.at(3), static_cast<QGraphicsItem *>(text2));
4982     QCOMPARE(tester->filteredEvents.at(4), QEvent::FocusIn);
4983     QCOMPARE(tester->filteredEventReceivers.at(4), static_cast<QGraphicsItem *>(text3));
4984
4985     text1->removeSceneEventFilter(tester);
4986     text1->setFocus();
4987
4988     QCOMPARE(tester->filteredEvents.size(), 6);
4989     QCOMPARE(tester->filteredEvents.at(5), QEvent::FocusOut);
4990     QCOMPARE(tester->filteredEventReceivers.at(5), static_cast<QGraphicsItem *>(text3));
4991
4992     tester->handlesSceneEvents = true;
4993     text2->setFocus();
4994
4995     QCOMPARE(tester->filteredEvents.size(), 7);
4996     QCOMPARE(tester->filteredEvents.at(6), QEvent::FocusIn);
4997     QCOMPARE(tester->filteredEventReceivers.at(6), static_cast<QGraphicsItem *>(text2));
4998
4999     QVERIFY(text2->hasFocus());
5000
5001     //Let check if the items are correctly removed from the sceneEventFilters array
5002     //to avoid stale pointers.
5003     QGraphicsView gv;
5004     QGraphicsScene *anotherScene = new QGraphicsScene;
5005     QGraphicsTextItem *ti = anotherScene->addText("This is a test #1");
5006     ti->moveBy(50, 50);
5007     QGraphicsTextItem *ti2 = anotherScene->addText("This is a test #2");
5008     QGraphicsTextItem *ti3 = anotherScene->addText("This is a test #3");
5009     gv.setScene(anotherScene);
5010     gv.show();
5011     QVERIFY(QTest::qWaitForWindowExposed(&gv));
5012     QTest::qWait(25);
5013     ti->installSceneEventFilter(ti2);
5014     ti3->installSceneEventFilter(ti);
5015     delete ti2;
5016     //we souldn't crash
5017     QTest::mouseMove(gv.viewport(), gv.mapFromScene(ti->scenePos()));
5018     QTest::qWait(30);
5019     delete ti;
5020 }
5021
5022 class GeometryChanger : public QGraphicsItem
5023 {
5024 public:
5025     void changeGeometry()
5026     { prepareGeometryChange(); }
5027 };
5028
5029 void tst_QGraphicsItem::prepareGeometryChange()
5030 {
5031     {
5032         QGraphicsScene scene;
5033         QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
5034         QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
5035         ((GeometryChanger *)item)->changeGeometry();
5036         QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
5037     }
5038 }
5039
5040
5041 class PaintTester : public QGraphicsRectItem
5042 {
5043 public:
5044     PaintTester() : widget(NULL), painted(0) { setRect(QRectF(10, 10, 20, 20));}
5045
5046     void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *w)
5047     {
5048         widget = w;
5049         painted++;
5050     }
5051
5052     QWidget*  widget;
5053     int painted;
5054 };
5055
5056 void tst_QGraphicsItem::paint()
5057 {
5058     QGraphicsScene scene;
5059
5060     PaintTester paintTester;
5061     scene.addItem(&paintTester);
5062
5063     QGraphicsView view(&scene);
5064     view.show();
5065     QVERIFY(QTest::qWaitForWindowExposed(&view));
5066     QApplication::processEvents();
5067 #ifdef Q_OS_WIN32
5068     //we try to switch the desktop: if it fails, we skip the test
5069     if (::SwitchDesktop( ::GetThreadDesktop( ::GetCurrentThreadId() ) ) == 0) {
5070         QSKIP("The Graphics View doesn't get the paint events");
5071     }
5072 #endif
5073
5074     QTRY_COMPARE(paintTester.widget, view.viewport());
5075
5076     view.hide();
5077
5078     QGraphicsScene scene2;
5079     QGraphicsView view2(&scene2);
5080     view2.show();
5081     QVERIFY(QTest::qWaitForWindowExposed(&view2));
5082     QTest::qWait(25);
5083
5084     PaintTester tester2;
5085     scene2.addItem(&tester2);
5086     qApp->processEvents();
5087
5088     //First show one paint
5089     QTRY_COMPARE(tester2.painted, 1);
5090
5091     //nominal case, update call paint
5092     tester2.update();
5093     qApp->processEvents();
5094     QTRY_VERIFY(tester2.painted == 2);
5095
5096     //we remove the item from the scene, number of updates is still the same
5097     tester2.update();
5098     scene2.removeItem(&tester2);
5099     qApp->processEvents();
5100     QTRY_VERIFY(tester2.painted == 2);
5101
5102     //We re-add the item, the number of paint should increase
5103     scene2.addItem(&tester2);
5104     tester2.update();
5105     qApp->processEvents();
5106     QTRY_VERIFY(tester2.painted == 3);
5107 }
5108
5109 class HarakiriItem : public QGraphicsRectItem
5110 {
5111 public:
5112     HarakiriItem(int harakiriPoint)
5113         : QGraphicsRectItem(QRectF(0, 0, 100, 100)), harakiri(harakiriPoint)
5114     { dead = 0; }
5115
5116     static int dead;
5117
5118     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
5119     {
5120         QGraphicsRectItem::paint(painter, option, widget);
5121         if (harakiri == 0) {
5122             // delete unsupported since 4.5
5123             /*
5124             dead = 1;
5125             delete this;
5126             */
5127         }
5128     }
5129
5130     void advance(int n)
5131     {
5132         if (harakiri == 1 && n == 0) {
5133             // delete unsupported
5134             /*
5135             dead = 1;
5136             delete this;
5137             */
5138         }
5139         if (harakiri == 2 && n == 1) {
5140             dead = 1;
5141             delete this;
5142         }
5143     }
5144
5145 protected:
5146     void contextMenuEvent(QGraphicsSceneContextMenuEvent *)
5147     {
5148         if (harakiri == 3) {
5149             dead = 1;
5150             delete this;
5151         }
5152     }
5153
5154     void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
5155     {
5156         // ??
5157         QGraphicsRectItem::dragEnterEvent(event);
5158     }
5159
5160     void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
5161     {
5162         // ??
5163         QGraphicsRectItem::dragLeaveEvent(event);
5164     }
5165
5166     void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
5167     {
5168         // ??
5169         QGraphicsRectItem::dragMoveEvent(event);
5170     }
5171
5172     void dropEvent(QGraphicsSceneDragDropEvent *event)
5173     {
5174         // ??
5175         QGraphicsRectItem::dropEvent(event);
5176     }
5177
5178     void focusInEvent(QFocusEvent *)
5179     {
5180         if (harakiri == 4) {
5181             dead = 1;
5182             delete this;
5183         }
5184     }
5185
5186     void focusOutEvent(QFocusEvent *)
5187     {
5188         if (harakiri == 5) {
5189             dead = 1;
5190             delete this;
5191         }
5192     }
5193
5194     void hoverEnterEvent(QGraphicsSceneHoverEvent *)
5195     {
5196         if (harakiri == 6) {
5197             dead = 1;
5198             delete this;
5199         }
5200     }
5201
5202     void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
5203     {
5204         if (harakiri == 7) {
5205             dead = 1;
5206             delete this;
5207         }
5208     }
5209
5210     void hoverMoveEvent(QGraphicsSceneHoverEvent *)
5211     {
5212         if (harakiri == 8) {
5213             dead = 1;
5214             delete this;
5215         }
5216     }
5217
5218     void inputMethodEvent(QInputMethodEvent *event)
5219     {
5220         // ??
5221         QGraphicsRectItem::inputMethodEvent(event);
5222     }
5223
5224     QVariant inputMethodQuery(Qt::InputMethodQuery query) const
5225     {
5226         // ??
5227         return QGraphicsRectItem::inputMethodQuery(query);
5228     }
5229
5230     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
5231     {
5232         // deletion not supported
5233         return QGraphicsRectItem::itemChange(change, value);
5234     }
5235
5236     void keyPressEvent(QKeyEvent *)
5237     {
5238         if (harakiri == 9) {
5239             dead = 1;
5240             delete this;
5241         }
5242     }
5243
5244     void keyReleaseEvent(QKeyEvent *)
5245     {
5246         if (harakiri == 10) {
5247             dead = 1;
5248             delete this;
5249         }
5250     }
5251
5252     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *)
5253     {
5254         if (harakiri == 11) {
5255             dead = 1;
5256             delete this;
5257         }
5258     }
5259
5260     void mouseMoveEvent(QGraphicsSceneMouseEvent *)
5261     {
5262         if (harakiri == 12) {
5263             dead = 1;
5264             delete this;
5265         }
5266     }
5267
5268     void mousePressEvent(QGraphicsSceneMouseEvent *)
5269     {
5270         if (harakiri == 13) {
5271             dead = 1;
5272             delete this;
5273         }
5274     }
5275
5276     void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
5277     {
5278         if (harakiri == 14) {
5279             dead = 1;
5280             delete this;
5281         }
5282     }
5283
5284     bool sceneEvent(QEvent *event)
5285     {
5286         // deletion not supported
5287         return QGraphicsRectItem::sceneEvent(event);
5288     }
5289
5290     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
5291     {
5292         // deletion not supported
5293         return QGraphicsRectItem::sceneEventFilter(watched, event);
5294     }
5295
5296     void wheelEvent(QGraphicsSceneWheelEvent *)
5297     {
5298         if (harakiri == 16) {
5299             dead = 1;
5300             delete this;
5301         }
5302     }
5303
5304 private:
5305     int harakiri;
5306 };
5307
5308 int HarakiriItem::dead;
5309
5310 void tst_QGraphicsItem::deleteItemInEventHandlers()
5311 {
5312     for (int i = 0; i < 17; ++i) {
5313         QGraphicsScene scene;
5314         HarakiriItem *item = new HarakiriItem(i);
5315         item->setAcceptsHoverEvents(true);
5316         item->setFlag(QGraphicsItem::ItemIsFocusable);
5317
5318         scene.addItem(item);
5319
5320         item->installSceneEventFilter(item); // <- ehey!
5321
5322         QGraphicsView view(&scene);
5323         view.show();
5324
5325         qApp->processEvents();
5326         qApp->processEvents();
5327
5328         if (!item->dead)
5329             scene.advance();
5330
5331         if (!item->dead) {
5332             QContextMenuEvent event(QContextMenuEvent::Other,
5333                                     view.mapFromScene(item->scenePos()));
5334             QCoreApplication::sendEvent(view.viewport(), &event);
5335         }
5336         if (!item->dead)
5337             QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos()));
5338         if (!item->dead)
5339             QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
5340         if (!item->dead)
5341             QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
5342         if (!item->dead)
5343             QTest::mouseClick(view.viewport(), Qt::RightButton, 0, view.mapFromScene(item->scenePos()));
5344         if (!item->dead)
5345             QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos() + QPointF(20, -20)));
5346         if (!item->dead)
5347             item->setFocus();
5348         if (!item->dead)
5349             item->clearFocus();
5350         if (!item->dead)
5351             item->setFocus();
5352         if (!item->dead)
5353             QTest::keyPress(view.viewport(), Qt::Key_A);
5354         if (!item->dead)
5355             QTest::keyRelease(view.viewport(), Qt::Key_A);
5356         if (!item->dead)
5357             QTest::keyPress(view.viewport(), Qt::Key_A);
5358         if (!item->dead)
5359             QTest::keyRelease(view.viewport(), Qt::Key_A);
5360     }
5361 }
5362
5363 class ItemPaintsOutsideShape : public QGraphicsItem
5364 {
5365 public:
5366     QRectF boundingRect() const
5367     {
5368         return QRectF(0, 0, 100, 100);
5369     }
5370
5371     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
5372     {
5373         painter->fillRect(-50, -50, 200, 200, Qt::red);
5374         painter->fillRect(0, 0, 100, 100, Qt::blue);
5375     }
5376 };
5377
5378 void tst_QGraphicsItem::itemClipsToShape()
5379 {
5380     QGraphicsItem *clippedItem = new ItemPaintsOutsideShape;
5381     clippedItem->setFlag(QGraphicsItem::ItemClipsToShape);
5382
5383     QGraphicsItem *unclippedItem = new ItemPaintsOutsideShape;
5384     unclippedItem->setPos(200, 0);
5385
5386     QGraphicsScene scene(-50, -50, 400, 200);
5387     scene.addItem(clippedItem);
5388     scene.addItem(unclippedItem);
5389
5390     QImage image(400, 200, QImage::Format_ARGB32_Premultiplied);
5391     image.fill(0);
5392     QPainter painter(&image);
5393     painter.setRenderHint(QPainter::Antialiasing);
5394     scene.render(&painter);
5395     painter.end();
5396
5397     QCOMPARE(image.pixel(45, 100), QRgb(0));
5398     QCOMPARE(image.pixel(100, 45), QRgb(0));
5399     QCOMPARE(image.pixel(155, 100), QRgb(0));
5400     QCOMPARE(image.pixel(45, 155), QRgb(0));
5401     QCOMPARE(image.pixel(55, 100), QColor(Qt::blue).rgba());
5402     QCOMPARE(image.pixel(100, 55), QColor(Qt::blue).rgba());
5403     QCOMPARE(image.pixel(145, 100), QColor(Qt::blue).rgba());
5404     QCOMPARE(image.pixel(55, 145), QColor(Qt::blue).rgba());
5405     QCOMPARE(image.pixel(245, 100), QColor(Qt::red).rgba());
5406     QCOMPARE(image.pixel(300, 45), QColor(Qt::red).rgba());
5407     QCOMPARE(image.pixel(355, 100), QColor(Qt::red).rgba());
5408     QCOMPARE(image.pixel(245, 155), QColor(Qt::red).rgba());
5409     QCOMPARE(image.pixel(255, 100), QColor(Qt::blue).rgba());
5410     QCOMPARE(image.pixel(300, 55), QColor(Qt::blue).rgba());
5411     QCOMPARE(image.pixel(345, 100), QColor(Qt::blue).rgba());
5412     QCOMPARE(image.pixel(255, 145), QColor(Qt::blue).rgba());
5413 }
5414
5415 void tst_QGraphicsItem::itemClipsChildrenToShape()
5416 {
5417     QGraphicsScene scene;
5418     QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::yellow));
5419
5420     QGraphicsItem *ellipse = scene.addEllipse(0, 0, 100, 100, QPen(Qt::NoPen), QBrush(Qt::green));
5421     ellipse->setParentItem(rect);
5422
5423     QGraphicsItem *clippedEllipse = scene.addEllipse(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::blue));
5424     clippedEllipse->setParentItem(ellipse);
5425
5426     QGraphicsItem *clippedEllipse2 = scene.addEllipse(0, 0, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
5427     clippedEllipse2->setParentItem(clippedEllipse);
5428
5429     QGraphicsItem *clippedEllipse3 = scene.addEllipse(50, 50, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
5430     clippedEllipse3->setParentItem(clippedEllipse);
5431
5432     QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
5433     ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5434     QVERIFY((ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
5435
5436     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
5437     image.fill(0);
5438     QPainter painter(&image);
5439     painter.setRenderHint(QPainter::Antialiasing);
5440     scene.render(&painter);
5441     painter.end();
5442
5443     QCOMPARE(image.pixel(16, 16), QColor(255, 0, 0).rgba());
5444     QCOMPARE(image.pixel(32, 32), QColor(0, 0, 255).rgba());
5445     QCOMPARE(image.pixel(50, 50), QColor(0, 255, 0).rgba());
5446     QCOMPARE(image.pixel(12, 12), QColor(255, 255, 0).rgba());
5447     QCOMPARE(image.pixel(60, 60), QColor(255, 0, 0).rgba());
5448 }
5449
5450 void tst_QGraphicsItem::itemClipsChildrenToShape2()
5451 {
5452     QGraphicsRectItem *parent = new QGraphicsRectItem(QRectF(0, 0, 10, 10));
5453     QGraphicsEllipseItem *child1 = new QGraphicsEllipseItem(QRectF(50, 50, 100, 100));
5454     QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(15, 15, 80, 80));
5455
5456     child1->setParentItem(parent);
5457     child1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5458     child2->setParentItem(child1);
5459
5460     parent->setBrush(Qt::blue);
5461     child1->setBrush(Qt::green);
5462     child2->setBrush(Qt::red);
5463
5464     QGraphicsScene scene;
5465     scene.addItem(parent);
5466
5467     QCOMPARE(scene.itemAt(5, 5), (QGraphicsItem *)parent);
5468     QCOMPARE(scene.itemAt(15, 5), (QGraphicsItem *)0);
5469     QCOMPARE(scene.itemAt(5, 15), (QGraphicsItem *)0);
5470     QCOMPARE(scene.itemAt(60, 60), (QGraphicsItem *)0);
5471     QCOMPARE(scene.itemAt(140, 60), (QGraphicsItem *)0);
5472     QCOMPARE(scene.itemAt(60, 140), (QGraphicsItem *)0);
5473     QCOMPARE(scene.itemAt(140, 140), (QGraphicsItem *)0);
5474     QCOMPARE(scene.itemAt(75, 75), (QGraphicsItem *)child2);
5475     QCOMPARE(scene.itemAt(75, 100), (QGraphicsItem *)child1);
5476     QCOMPARE(scene.itemAt(100, 75), (QGraphicsItem *)child1);
5477
5478     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
5479     image.fill(0);
5480     QPainter painter(&image);
5481     scene.render(&painter);
5482     painter.end();
5483
5484     QCOMPARE(image.pixel(5, 5), QColor(0, 0, 255).rgba());
5485     QCOMPARE(image.pixel(5, 10), QRgb(0));
5486     QCOMPARE(image.pixel(10, 5), QRgb(0));
5487     QCOMPARE(image.pixel(40, 40), QRgb(0));
5488     QCOMPARE(image.pixel(90, 40), QRgb(0));
5489     QCOMPARE(image.pixel(40, 90), QRgb(0));
5490     QCOMPARE(image.pixel(95, 95), QRgb(0));
5491     QCOMPARE(image.pixel(50, 70), QColor(0, 255, 0).rgba());
5492     QCOMPARE(image.pixel(70, 50), QColor(0, 255, 0).rgba());
5493     QCOMPARE(image.pixel(50, 60), QColor(255, 0, 0).rgba());
5494     QCOMPARE(image.pixel(60, 50), QColor(255, 0, 0).rgba());
5495 }
5496
5497 void tst_QGraphicsItem::itemClipsChildrenToShape3()
5498 {
5499     // Construct a scene with nested children, each 50 pixels offset from the elder.
5500     // Set a top-level clipping flag
5501     QGraphicsScene scene;
5502     QGraphicsRectItem *parent = scene.addRect( 0, 0, 150, 150 );
5503     QGraphicsRectItem *child = scene.addRect( 0, 0, 150, 150 );
5504     QGraphicsRectItem *grandchild = scene.addRect( 0, 0, 150, 150 );
5505     child->setParentItem(parent);
5506     grandchild->setParentItem(child);
5507     child->setPos( 50, 50 );
5508     grandchild->setPos( 50, 50 );
5509     parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5510
5511     QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)parent);
5512     QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)child);
5513     QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
5514     QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
5515
5516     // Move child to fully overlap the parent.  The grandchild should
5517     // now occupy two-thirds of the scene
5518     child->prepareGeometryChange();
5519     child->setPos( 0, 0 );
5520
5521     QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)child);
5522     QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)grandchild);
5523     QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
5524     QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
5525 }
5526
5527 class MyProxyWidget : public QGraphicsProxyWidget
5528 {
5529 public:
5530     MyProxyWidget(QGraphicsItem *parent) : QGraphicsProxyWidget(parent)
5531     {
5532         painted = false;
5533     }
5534
5535     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
5536     {
5537         QGraphicsProxyWidget::paint(painter, option, widget);
5538         painted = true;
5539     }
5540     bool painted;
5541 };
5542
5543 void tst_QGraphicsItem::itemClipsChildrenToShape4()
5544 {
5545     QGraphicsScene scene;
5546     QGraphicsView view(&scene);
5547
5548     QGraphicsWidget * outerWidget = new QGraphicsWidget();
5549     outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
5550     MyProxyWidget * innerWidget = new MyProxyWidget(outerWidget);
5551     QLabel * label = new QLabel();
5552     label->setText("Welcome back my friends to the show that never ends...");
5553     innerWidget->setWidget(label);
5554     view.resize(300, 300);
5555     scene.addItem(outerWidget);
5556     outerWidget->resize( 200, 100 );
5557     scene.addEllipse( 100, 100, 100, 50 );   // <-- this is important to trigger the right codepath*
5558     //now the label is shown
5559     outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false );
5560     QApplication::setActiveWindow(&view);
5561     view.show();
5562     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
5563     QTRY_COMPARE(innerWidget->painted, true);
5564 }
5565
5566 //#define DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
5567 static inline void renderSceneToImage(QGraphicsScene *scene, QImage *image, const QString &filename)
5568 {
5569     image->fill(0);
5570     QPainter painter(image);
5571     scene->render(&painter);
5572     painter.end();
5573 #ifdef DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
5574     image->save(filename);
5575 #else
5576     Q_UNUSED(filename);
5577 #endif
5578 }
5579
5580 void tst_QGraphicsItem::itemClipsChildrenToShape5()
5581 {
5582     class ParentItem : public QGraphicsRectItem
5583     {
5584     public:
5585         ParentItem(qreal x, qreal y, qreal width, qreal height)
5586             : QGraphicsRectItem(x, y, width, height) {}
5587
5588         QPainterPath shape() const
5589         {
5590             QPainterPath path;
5591             path.addRect(50, 50, 200, 200);
5592             return path;
5593         }
5594     };
5595
5596     ParentItem *parent = new ParentItem(0, 0, 300, 300);
5597     parent->setBrush(Qt::blue);
5598     parent->setOpacity(0.5);
5599
5600     const QRegion parentRegion(0, 0, 300, 300);
5601     const QRegion clippedParentRegion = parentRegion & QRect(50, 50, 200, 200);
5602     QRegion childRegion;
5603     QRegion grandChildRegion;
5604
5605     QGraphicsRectItem *topLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
5606     topLeftChild->setBrush(Qt::red);
5607     topLeftChild->setParentItem(parent);
5608     childRegion += QRect(0, 0, 100, 100);
5609
5610     QGraphicsRectItem *topRightChild = new QGraphicsRectItem(0, 0, 100, 100);
5611     topRightChild->setBrush(Qt::red);
5612     topRightChild->setParentItem(parent);
5613     topRightChild->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5614     topRightChild->setPos(200, 0);
5615     childRegion += QRect(200, 0, 100, 100);
5616
5617     QGraphicsRectItem *topRightGrandChild = new QGraphicsRectItem(0, 0, 100, 100);
5618     topRightGrandChild->setBrush(Qt::green);
5619     topRightGrandChild->setParentItem(topRightChild);
5620     topRightGrandChild->setPos(-40, 40);
5621     grandChildRegion += QRect(200 - 40, 0 + 40, 100, 100) & QRect(200, 0, 100, 100);
5622
5623     QGraphicsRectItem *bottomLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
5624     bottomLeftChild->setBrush(Qt::red);
5625     bottomLeftChild->setParentItem(parent);
5626     bottomLeftChild->setFlag(QGraphicsItem::ItemClipsToShape);
5627     bottomLeftChild->setPos(0, 200);
5628     childRegion += QRect(0, 200, 100, 100);
5629
5630     QGraphicsRectItem *bottomLeftGrandChild = new QGraphicsRectItem(0, 0, 160, 160);
5631     bottomLeftGrandChild->setBrush(Qt::green);
5632     bottomLeftGrandChild->setParentItem(bottomLeftChild);
5633     bottomLeftGrandChild->setFlag(QGraphicsItem::ItemClipsToShape);
5634     bottomLeftGrandChild->setPos(0, -60);
5635     grandChildRegion += QRect(0, 200 - 60, 160, 160);
5636
5637     QGraphicsRectItem *bottomRightChild = new QGraphicsRectItem(0, 0, 100, 100);
5638     bottomRightChild->setBrush(Qt::red);
5639     bottomRightChild->setParentItem(parent);
5640     bottomRightChild->setPos(200, 200);
5641     childRegion += QRect(200, 200, 100, 100);
5642
5643     QPoint controlPoints[17] = {
5644         QPoint(5, 5)  , QPoint(95, 5)  , QPoint(205, 5)  , QPoint(295, 5)  ,
5645         QPoint(5, 95) , QPoint(95, 95) , QPoint(205, 95) , QPoint(295, 95) ,
5646                              QPoint(150, 150),
5647         QPoint(5, 205), QPoint(95, 205), QPoint(205, 205), QPoint(295, 205),
5648         QPoint(5, 295), QPoint(95, 295), QPoint(205, 295), QPoint(295, 295),
5649     };
5650
5651     const QRegion clippedChildRegion = childRegion & QRect(50, 50, 200, 200);
5652     const QRegion clippedGrandChildRegion = grandChildRegion & QRect(50, 50, 200, 200);
5653
5654     QGraphicsScene scene;
5655     scene.addItem(parent);
5656     QImage sceneImage(300, 300, QImage::Format_ARGB32);
5657
5658 #define VERIFY_CONTROL_POINTS(pRegion, cRegion, gRegion) \
5659     for (int i = 0; i < 17; ++i) { \
5660         QPoint controlPoint = controlPoints[i]; \
5661         QRgb pixel = sceneImage.pixel(controlPoint.x(), controlPoint.y()); \
5662         if (pRegion.contains(controlPoint)) \
5663             QVERIFY(qBlue(pixel) != 0); \
5664         else \
5665             QVERIFY(qBlue(pixel) == 0); \
5666         if (cRegion.contains(controlPoint)) \
5667             QVERIFY(qRed(pixel) != 0); \
5668         else \
5669             QVERIFY(qRed(pixel) == 0); \
5670         if (gRegion.contains(controlPoint)) \
5671             QVERIFY(qGreen(pixel) != 0); \
5672         else \
5673             QVERIFY(qGreen(pixel) == 0); \
5674     }
5675
5676     const QList<QGraphicsItem *> children = parent->childItems();
5677     const int childrenCount = children.count();
5678
5679     for (int i = 0; i < 5; ++i) {
5680         QString clipString;
5681         QString childString;
5682         switch (i) {
5683         case 0:
5684             // All children stacked in front.
5685             childString = QLatin1String("ChildrenInFront.png");
5686             foreach (QGraphicsItem *child, children)
5687                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
5688             break;
5689         case 1:
5690             // All children stacked behind.
5691             childString = QLatin1String("ChildrenBehind.png");
5692             foreach (QGraphicsItem *child, children)
5693                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
5694             break;
5695         case 2:
5696             // First half of the children behind, second half in front.
5697             childString = QLatin1String("FirstHalfBehind_SecondHalfInFront.png");
5698             for (int j = 0; j < childrenCount; ++j) {
5699                 QGraphicsItem *child = children.at(j);
5700                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j < childrenCount / 2));
5701             }
5702             break;
5703         case 3:
5704             // First half of the children in front, second half behind.
5705             childString = QLatin1String("FirstHalfInFront_SecondHalfBehind.png");
5706             for (int j = 0; j < childrenCount; ++j) {
5707                 QGraphicsItem *child = children.at(j);
5708                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j >= childrenCount / 2));
5709             }
5710             break;
5711         case 4:
5712             // Child2 and child4 behind, rest in front.
5713             childString = QLatin1String("Child2And4Behind_RestInFront.png");
5714             for (int j = 0; j < childrenCount; ++j) {
5715                 QGraphicsItem *child = children.at(j);
5716                 if (j == 1 || j == 3)
5717                     child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
5718                 else
5719                     child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
5720             }
5721             break;
5722         default:
5723             qFatal("internal error");
5724         }
5725
5726         // Nothing is clipped.
5727         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
5728         parent->setFlag(QGraphicsItem::ItemClipsToShape, false);
5729         clipString = QLatin1String("nothingClipped_");
5730         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5731         VERIFY_CONTROL_POINTS(parentRegion, childRegion, grandChildRegion);
5732
5733         // Parent clips children to shape.
5734         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5735         clipString = QLatin1String("parentClipsChildrenToShape_");
5736         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5737         VERIFY_CONTROL_POINTS(parentRegion, clippedChildRegion, clippedGrandChildRegion);
5738
5739         // Parent clips itself and children to shape.
5740         parent->setFlag(QGraphicsItem::ItemClipsToShape);
5741         clipString = QLatin1String("parentClipsItselfAndChildrenToShape_");
5742         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5743         VERIFY_CONTROL_POINTS(clippedParentRegion, clippedChildRegion, clippedGrandChildRegion);
5744
5745         // Parent clips itself to shape.
5746         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
5747         clipString = QLatin1String("parentClipsItselfToShape_");
5748         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5749         VERIFY_CONTROL_POINTS(clippedParentRegion, childRegion, grandChildRegion);
5750     }
5751 }
5752
5753 void tst_QGraphicsItem::itemClipsTextChildToShape()
5754 {
5755     // Construct a scene with a rect that clips its children, with one text
5756     // child that has text that exceeds the size of the rect.
5757     QGraphicsScene scene;
5758     QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::black), Qt::black);
5759     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5760     QGraphicsTextItem *text = new QGraphicsTextItem("This is a long sentence that's wider than 50 pixels.");
5761     text->setParentItem(rect);
5762
5763     // Render this scene to a transparent image.
5764     QRectF sr = scene.itemsBoundingRect();
5765     QImage image(sr.size().toSize(), QImage::Format_ARGB32_Premultiplied);
5766     image.fill(0);
5767     QPainter painter(&image);
5768     scene.render(&painter);
5769
5770     // Erase the area immediately underneath the rect.
5771     painter.setCompositionMode(QPainter::CompositionMode_Source);
5772     painter.fillRect(rect->sceneBoundingRect().translated(-sr.topLeft()).adjusted(-0.5, -0.5, 0.5, 0.5),
5773                      Qt::transparent);
5774     painter.end();
5775
5776     // Check that you get a truly transparent image back (i.e., the text was
5777     // clipped away, so there should be no trails left after erasing only the
5778     // rect's area).
5779     QImage emptyImage(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
5780     emptyImage.fill(0);
5781     QCOMPARE(image, emptyImage);
5782 }
5783
5784 void tst_QGraphicsItem::itemClippingDiscovery()
5785 {
5786     // A simple scene with an ellipse parent and two rect children, one a
5787     // child of the other.
5788     QGraphicsScene scene;
5789     QGraphicsEllipseItem *clipItem = scene.addEllipse(0, 0, 100, 100);
5790     QGraphicsRectItem *leftRectItem = scene.addRect(0, 0, 50, 100);
5791     QGraphicsRectItem *rightRectItem = scene.addRect(50, 0, 50, 100);
5792     leftRectItem->setParentItem(clipItem);
5793     rightRectItem->setParentItem(clipItem);
5794
5795     // The rects item are both visible at these points.
5796     QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)leftRectItem);
5797     QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)rightRectItem);
5798
5799     // The ellipse clips the rects now.
5800     clipItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5801
5802     // The rect items are no longer visible at these points.
5803     QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
5804     if (sizeof(qreal) != sizeof(double))
5805         QSKIP("This fails due to internal rounding errors");
5806     QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)0);
5807 }
5808
5809 void tst_QGraphicsItem::ancestorFlags()
5810 {
5811     QGraphicsItem *level1 = new QGraphicsRectItem;
5812     QGraphicsItem *level21 = new QGraphicsRectItem;
5813     level21->setParentItem(level1);
5814     QGraphicsItem *level22 = new QGraphicsRectItem;
5815     level22->setParentItem(level1);
5816     QGraphicsItem *level31 = new QGraphicsRectItem;
5817     level31->setParentItem(level21);
5818     QGraphicsItem *level32 = new QGraphicsRectItem;
5819     level32->setParentItem(level21);
5820
5821     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5822     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5823     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5824     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5825     QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5826
5827     // HandlesChildEvents: 1) Root level sets a flag
5828     level1->setHandlesChildEvents(true);
5829     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5830     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5831     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5832     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5833     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5834
5835     // HandlesChildEvents: 2) Root level set it again
5836     level1->setHandlesChildEvents(true);
5837     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5838     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5839     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5840     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5841     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5842
5843     // HandlesChildEvents: 3) Root level unsets a flag
5844     level1->setHandlesChildEvents(false);
5845     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5846     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5847     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5848     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5849     QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5850
5851     // HandlesChildEvents: 4) Child item sets a flag
5852     level21->setHandlesChildEvents(true);
5853     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5854     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5855     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5856     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5857     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5858
5859     // HandlesChildEvents: 5) Parent item sets a flag
5860     level1->setHandlesChildEvents(true);
5861     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5862     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5863     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5864     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5865     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5866
5867     // HandlesChildEvents: 6) Child item unsets a flag
5868     level21->setHandlesChildEvents(false);
5869     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5870     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5871     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5872     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5873     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5874
5875     // HandlesChildEvents: 7) Parent item unsets a flag
5876     level21->setHandlesChildEvents(true);
5877     level1->setHandlesChildEvents(false);
5878     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5879     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5880     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5881     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5882     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5883
5884     // Reparent the child to root
5885     level21->setParentItem(0);
5886     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5887     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5888     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5889     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5890
5891     // Reparent the child to level1 again.
5892     level1->setHandlesChildEvents(true);
5893     level21->setParentItem(level1);
5894     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5895     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5896     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5897     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5898     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5899
5900     // Reparenting level31 back to level1.
5901     level31->setParentItem(level1);
5902     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5903     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5904     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5905     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5906     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5907
5908     // Reparenting level31 back to level21.
5909     level31->setParentItem(0);
5910     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5911     level31->setParentItem(level21);
5912     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5913     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5914     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5915     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5916     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5917
5918     // Level1 doesn't handle child events
5919     level1->setHandlesChildEvents(false);
5920     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5921     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5922     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5923     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5924     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5925
5926     // Nobody handles child events
5927     level21->setHandlesChildEvents(false);
5928
5929     for (int i = 0; i < 2; ++i) {
5930         QGraphicsItem::GraphicsItemFlag flag = !i ? QGraphicsItem::ItemClipsChildrenToShape
5931                                                : QGraphicsItem::ItemIgnoresTransformations;
5932         int ancestorFlag = !i ? QGraphicsItemPrivate::AncestorClipsChildren
5933                            : QGraphicsItemPrivate::AncestorIgnoresTransformations;
5934
5935         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5936         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5937         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5938         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5939         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5940
5941         // HandlesChildEvents: 1) Root level sets a flag
5942         level1->setFlag(flag, true);
5943         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5944         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
5945         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
5946         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5947         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5948
5949         // HandlesChildEvents: 2) Root level set it again
5950         level1->setFlag(flag, true);
5951         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5952         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
5953         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
5954         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5955         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5956
5957         // HandlesChildEvents: 3) Root level unsets a flag
5958         level1->setFlag(flag, false);
5959         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5960         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5961         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5962         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5963         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5964
5965         // HandlesChildEvents: 4) Child item sets a flag
5966         level21->setFlag(flag, true);
5967         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5968         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5969         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5970         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5971         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5972
5973         // HandlesChildEvents: 5) Parent item sets a flag
5974         level1->setFlag(flag, true);
5975         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5976         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
5977         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
5978         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5979         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5980
5981         // HandlesChildEvents: 6) Child item unsets a flag
5982         level21->setFlag(flag, false);
5983         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5984         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
5985         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
5986         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5987         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5988
5989         // HandlesChildEvents: 7) Parent item unsets a flag
5990         level21->setFlag(flag, true);
5991         level1->setFlag(flag, false);
5992         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5993         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5994         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5995         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
5996         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
5997
5998         // Reparent the child to root
5999         level21->setParentItem(0);
6000         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6001         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6002         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6003         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6004
6005         // Reparent the child to level1 again.
6006         level1->setFlag(flag, true);
6007         level21->setParentItem(level1);
6008         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6009         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6010         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6011         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6012         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6013
6014         // Reparenting level31 back to level1.
6015         level31->setParentItem(level1);
6016         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6017         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6018         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6019         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6020         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6021
6022         // Reparenting level31 back to level21.
6023         level31->setParentItem(0);
6024         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
6025         level31->setParentItem(level21);
6026         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6027         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6028         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6029         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6030         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6031
6032         // Level1 doesn't handle child events
6033         level1->setFlag(flag, false);
6034         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6035         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6036         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6037         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6038         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6039
6040         // Nobody handles child events
6041         level21->setFlag(flag, false);
6042         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6043         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6044         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6045         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
6046         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
6047     }
6048
6049     delete level1;
6050 }
6051
6052 void tst_QGraphicsItem::untransformable()
6053 {
6054     QGraphicsItem *item1 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6055     item1->setZValue(1);
6056     item1->setFlag(QGraphicsItem::ItemIgnoresTransformations);
6057     item1->rotate(45);
6058     ((QGraphicsEllipseItem *)item1)->setBrush(Qt::red);
6059
6060     QGraphicsItem *item2 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6061     item2->setParentItem(item1);
6062     item2->rotate(45);
6063     item2->setPos(100, 0);
6064     ((QGraphicsEllipseItem *)item2)->setBrush(Qt::green);
6065
6066     QGraphicsItem *item3 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6067     item3->setParentItem(item2);
6068     item3->setPos(100, 0);
6069     ((QGraphicsEllipseItem *)item3)->setBrush(Qt::blue);
6070
6071     QGraphicsScene scene(-500, -500, 1000, 1000);
6072     scene.addItem(item1);
6073
6074     QWidget topLevel;
6075     QGraphicsView view(&scene,&topLevel);
6076     view.resize(300, 300);
6077     topLevel.show();
6078     view.scale(8, 8);
6079     view.centerOn(0, 0);
6080
6081 // Painting with the DiagCrossPattern is really slow on Mac
6082 // when zoomed out. (The test times out). Task to fix is 155567.
6083 #if !defined(Q_OS_MAC) || 1
6084     view.setBackgroundBrush(QBrush(Qt::black, Qt::DiagCrossPattern));
6085 #endif
6086
6087     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
6088
6089     for (int i = 0; i < 10; ++i) {
6090         QPoint center = view.viewport()->rect().center();
6091         QCOMPARE(view.itemAt(center), item1);
6092         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item1);
6093         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item1);
6094         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item1);
6095         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item1);
6096
6097         center += QPoint(70, 70);
6098         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item2);
6099         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item2);
6100         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item2);
6101         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item2);
6102
6103         center += QPoint(0, 100);
6104         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item3);
6105         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item3);
6106         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item3);
6107         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item3);
6108
6109         view.scale(0.5, 0.5);
6110         view.rotate(13);
6111         view.shear(qreal(0.01), qreal(0.01));
6112         view.translate(10, 10);
6113         QTest::qWait(25);
6114     }
6115 }
6116
6117 class ContextMenuItem : public QGraphicsRectItem
6118 {
6119 public:
6120     ContextMenuItem()
6121         : ignoreEvent(true), gotEvent(false), eventWasAccepted(false)
6122     { }
6123     bool ignoreEvent;
6124     bool gotEvent;
6125     bool eventWasAccepted;
6126 protected:
6127     void contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
6128     {
6129         gotEvent = true;
6130         eventWasAccepted = event->isAccepted();
6131         if (ignoreEvent)
6132             event->ignore();
6133     }
6134 };
6135
6136 void tst_QGraphicsItem::contextMenuEventPropagation()
6137 {
6138     ContextMenuItem *bottomItem = new ContextMenuItem;
6139     bottomItem->setRect(0, 0, 100, 100);
6140     ContextMenuItem *topItem = new ContextMenuItem;
6141     topItem->setParentItem(bottomItem);
6142     topItem->setRect(0, 0, 100, 100);
6143
6144     QGraphicsScene scene;
6145
6146     QGraphicsView view(&scene);
6147     view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
6148     view.show();
6149     view.resize(200, 200);
6150     QVERIFY(QTest::qWaitForWindowExposed(&view));
6151     QTest::qWait(20);
6152
6153     QContextMenuEvent event(QContextMenuEvent::Mouse, QPoint(10, 10),
6154                             view.viewport()->mapToGlobal(QPoint(10, 10)));
6155     event.ignore();
6156     QApplication::sendEvent(view.viewport(), &event);
6157     QVERIFY(!event.isAccepted());
6158
6159     scene.addItem(bottomItem);
6160     topItem->ignoreEvent = true;
6161     bottomItem->ignoreEvent = true;
6162
6163     QApplication::sendEvent(view.viewport(), &event);
6164     QVERIFY(!event.isAccepted());
6165     QCOMPARE(topItem->gotEvent, true);
6166     QCOMPARE(topItem->eventWasAccepted, true);
6167     QCOMPARE(bottomItem->gotEvent, true);
6168     QCOMPARE(bottomItem->eventWasAccepted, true);
6169
6170     topItem->ignoreEvent = false;
6171     topItem->gotEvent = false;
6172     bottomItem->gotEvent = false;
6173
6174     QApplication::sendEvent(view.viewport(), &event);
6175     QVERIFY(event.isAccepted());
6176     QCOMPARE(topItem->gotEvent, true);
6177     QCOMPARE(bottomItem->gotEvent, false);
6178     QCOMPARE(topItem->eventWasAccepted, true);
6179 }
6180
6181 void tst_QGraphicsItem::itemIsMovable()
6182 {
6183     QGraphicsRectItem *rect = new QGraphicsRectItem(-50, -50, 100, 100);
6184     rect->setFlag(QGraphicsItem::ItemIsMovable);
6185
6186     QGraphicsScene scene;
6187     scene.addItem(rect);
6188
6189     {
6190         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6191         event.setButton(Qt::LeftButton);
6192         event.setButtons(Qt::LeftButton);
6193         qApp->sendEvent(&scene, &event);
6194     }
6195     {
6196         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6197         event.setButton(Qt::LeftButton);
6198         event.setButtons(Qt::LeftButton);
6199         qApp->sendEvent(&scene, &event);
6200     }
6201     QCOMPARE(rect->pos(), QPointF(0, 0));
6202     {
6203         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6204         event.setButtons(Qt::LeftButton);
6205         event.setScenePos(QPointF(10, 10));
6206         qApp->sendEvent(&scene, &event);
6207     }
6208     QCOMPARE(rect->pos(), QPointF(10, 10));
6209     {
6210         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6211         event.setButtons(Qt::RightButton);
6212         event.setScenePos(QPointF(20, 20));
6213         qApp->sendEvent(&scene, &event);
6214     }
6215     QCOMPARE(rect->pos(), QPointF(10, 10));
6216     {
6217         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6218         event.setButtons(Qt::LeftButton);
6219         event.setScenePos(QPointF(30, 30));
6220         qApp->sendEvent(&scene, &event);
6221     }
6222     QCOMPARE(rect->pos(), QPointF(30, 30));
6223 }
6224
6225 class ItemAddScene : public QGraphicsScene
6226 {
6227     Q_OBJECT
6228 public:
6229     ItemAddScene()
6230     {
6231         QTimer::singleShot(500, this, SLOT(newTextItem()));
6232     }
6233
6234 public slots:
6235     void newTextItem()
6236     {
6237         // Add a text item
6238         QGraphicsItem *item = new QGraphicsTextItem("This item will not ensure that it's visible", 0);
6239         item->setPos(.0, .0);
6240         item->show();
6241     }
6242 };
6243
6244 void tst_QGraphicsItem::task141694_textItemEnsureVisible()
6245 {
6246     ItemAddScene scene;
6247     scene.setSceneRect(-1000, -1000, 2000, 2000);
6248
6249     QGraphicsView view(&scene);
6250     view.setFixedSize(200, 200);
6251     view.show();
6252     QVERIFY(QTest::qWaitForWindowExposed(&view));
6253
6254     view.ensureVisible(-1000, -1000, 5, 5);
6255     int hscroll = view.horizontalScrollBar()->value();
6256     int vscroll = view.verticalScrollBar()->value();
6257
6258     QTest::qWait(10);
6259
6260     // This should not cause the view to scroll
6261     QTRY_COMPARE(view.horizontalScrollBar()->value(), hscroll);
6262     QCOMPARE(view.verticalScrollBar()->value(), vscroll);
6263 }
6264
6265 void tst_QGraphicsItem::task128696_textItemEnsureMovable()
6266 {
6267     QGraphicsTextItem *item = new QGraphicsTextItem;
6268     item->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
6269     item->setTextInteractionFlags(Qt::TextEditorInteraction);
6270     item->setPlainText("abc de\nf ghi\n   j k l");
6271
6272     QGraphicsScene scene;
6273     scene.setSceneRect(-100, -100, 200, 200);
6274     scene.addItem(item);
6275
6276     QGraphicsView view(&scene);
6277     view.setFixedSize(200, 200);
6278     view.show();
6279
6280     QGraphicsSceneMouseEvent event1(QEvent::GraphicsSceneMousePress);
6281     event1.setScenePos(QPointF(0, 0));
6282     event1.setButton(Qt::LeftButton);
6283     event1.setButtons(Qt::LeftButton);
6284     QApplication::sendEvent(&scene, &event1);
6285     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6286
6287     QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
6288     event2.setScenePos(QPointF(10, 10));
6289     event2.setButton(Qt::LeftButton);
6290     event2.setButtons(Qt::LeftButton);
6291     QApplication::sendEvent(&scene, &event2);
6292     QCOMPARE(item->pos(), QPointF(10, 10));
6293 }
6294
6295 void tst_QGraphicsItem::task177918_lineItemUndetected()
6296 {
6297     QGraphicsScene scene;
6298     QGraphicsLineItem *line = scene.addLine(10, 10, 10, 10);
6299     QCOMPARE(line->boundingRect(), QRectF(10, 10, 0, 0));
6300
6301     QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemShape).isEmpty());
6302     QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemShape).isEmpty());
6303     QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemBoundingRect).isEmpty());
6304     QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemBoundingRect).isEmpty());
6305 }
6306
6307 void tst_QGraphicsItem::task240400_clickOnTextItem_data()
6308 {
6309     QTest::addColumn<int>("flags");
6310     QTest::addColumn<int>("textFlags");
6311     QTest::newRow("editor, noflags") << 0 << int(Qt::TextEditorInteraction);
6312     QTest::newRow("editor, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::TextEditorInteraction);
6313     QTest::newRow("editor, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::TextEditorInteraction);
6314     QTest::newRow("editor, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
6315                                                   << int(Qt::TextEditorInteraction);
6316     QTest::newRow("noninteractive, noflags") << 0 << int(Qt::NoTextInteraction);
6317     QTest::newRow("noninteractive, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::NoTextInteraction);
6318     QTest::newRow("noninteractive, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::NoTextInteraction);
6319     QTest::newRow("noninteractive, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
6320                                                           << int(Qt::NoTextInteraction);
6321 }
6322
6323 void tst_QGraphicsItem::task240400_clickOnTextItem()
6324 {
6325     QFETCH(int, flags);
6326     QFETCH(int, textFlags);
6327
6328     QGraphicsScene scene;
6329     QEvent activate(QEvent::WindowActivate);
6330     QApplication::sendEvent(&scene, &activate);
6331
6332     QGraphicsTextItem *item = scene.addText("Hello");
6333     item->setFlags(QGraphicsItem::GraphicsItemFlags(flags));
6334     item->setTextInteractionFlags(Qt::TextInteractionFlags(textFlags));
6335     bool focusable = (item->flags() & QGraphicsItem::ItemIsFocusable);
6336     QVERIFY(textFlags ? focusable : !focusable);
6337
6338     int column = item->textCursor().columnNumber();
6339     QCOMPARE(column, 0);
6340
6341     QVERIFY(!item->hasFocus());
6342
6343     // Click in the top-left corner of the item
6344     {
6345         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6346         event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
6347         event.setButton(Qt::LeftButton);
6348         event.setButtons(Qt::LeftButton);
6349         QApplication::sendEvent(&scene, &event);
6350     }
6351     if (flags || textFlags)
6352         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6353     else
6354         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
6355     {
6356         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
6357         event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
6358         event.setButton(Qt::LeftButton);
6359         event.setButtons(0);
6360         QApplication::sendEvent(&scene, &event);
6361     }
6362     if (textFlags)
6363         QVERIFY(item->hasFocus());
6364     else
6365         QVERIFY(!item->hasFocus());
6366     QVERIFY(!scene.mouseGrabberItem());
6367     bool selectable = (flags & QGraphicsItem::ItemIsSelectable);
6368     QVERIFY(selectable ? item->isSelected() : !item->isSelected());
6369
6370     // Now click in the middle and check that the cursor moved.
6371     {
6372         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6373         event.setScenePos(item->sceneBoundingRect().center());
6374         event.setButton(Qt::LeftButton);
6375         event.setButtons(Qt::LeftButton);
6376         QApplication::sendEvent(&scene, &event);
6377     }
6378     if (flags || textFlags)
6379         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6380     else
6381         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
6382     {
6383         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
6384         event.setScenePos(item->sceneBoundingRect().center());
6385         event.setButton(Qt::LeftButton);
6386         event.setButtons(0);
6387         QApplication::sendEvent(&scene, &event);
6388     }
6389     if (textFlags)
6390         QVERIFY(item->hasFocus());
6391     else
6392         QVERIFY(!item->hasFocus());
6393     QVERIFY(!scene.mouseGrabberItem());
6394
6395     QVERIFY(selectable ? item->isSelected() : !item->isSelected());
6396
6397     //
6398     if (textFlags & Qt::TextEditorInteraction)
6399         QVERIFY(item->textCursor().columnNumber() > column);
6400     else
6401         QCOMPARE(item->textCursor().columnNumber(), 0);
6402 }
6403
6404 class TextItem : public QGraphicsSimpleTextItem
6405 {
6406 public:
6407     TextItem(const QString& text) : QGraphicsSimpleTextItem(text)
6408     {
6409         updates = 0;
6410     }
6411
6412     void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
6413     {
6414         updates++;
6415         QGraphicsSimpleTextItem::paint(painter, option, widget);
6416     }
6417
6418     int updates;
6419 };
6420
6421 void tst_QGraphicsItem::ensureUpdateOnTextItem()
6422 {
6423     QGraphicsScene scene;
6424     QGraphicsView view(&scene);
6425     view.show();
6426     QVERIFY(QTest::qWaitForWindowExposed(&view));
6427     QTest::qWait(25);
6428     TextItem *text1 = new TextItem(QLatin1String("123"));
6429     scene.addItem(text1);
6430     qApp->processEvents();
6431     QTRY_COMPARE(text1->updates,1);
6432
6433     //same bouding rect but we have to update
6434     text1->setText(QLatin1String("321"));
6435     qApp->processEvents();
6436     QTRY_COMPARE(text1->updates,2);
6437 }
6438
6439 void tst_QGraphicsItem::task243707_addChildBeforeParent()
6440 {
6441     // Task reports that adding the child before the parent leads to an
6442     // inconsistent internal state that can cause a crash.  This test shows
6443     // one such crash.
6444     QGraphicsScene scene;
6445     QGraphicsWidget *widget = new QGraphicsWidget;
6446     QGraphicsWidget *widget2 = new QGraphicsWidget(widget);
6447     scene.addItem(widget2);
6448     QVERIFY(!widget2->parentItem());
6449     scene.addItem(widget);
6450     QVERIFY(!widget->commonAncestorItem(widget2));
6451     QVERIFY(!widget2->commonAncestorItem(widget));
6452 }
6453
6454 void tst_QGraphicsItem::task197802_childrenVisibility()
6455 {
6456     QGraphicsScene scene;
6457     QGraphicsRectItem item(QRectF(0,0,20,20));
6458
6459     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(0,0,10,10), &item);
6460     scene.addItem(&item);
6461
6462     //freshly created: both visible
6463     QVERIFY(item.isVisible());
6464     QVERIFY(item2->isVisible());
6465
6466     //hide child: parent visible, child not
6467     item2->hide();
6468     QVERIFY(item.isVisible());
6469     QVERIFY(!item2->isVisible());
6470
6471     //hide parent: parent and child invisible
6472     item.hide();
6473     QVERIFY(!item.isVisible());
6474     QVERIFY(!item2->isVisible());
6475
6476     //ask to show the child: parent and child invisible anyways
6477     item2->show();
6478     QVERIFY(!item.isVisible());
6479     QVERIFY(!item2->isVisible());
6480
6481     //show the parent: both parent and child visible
6482     item.show();
6483     QVERIFY(item.isVisible());
6484     QVERIFY(item2->isVisible());
6485
6486     delete item2;
6487 }
6488
6489 void tst_QGraphicsItem::boundingRegion_data()
6490 {
6491     QTest::addColumn<QLineF>("line");
6492     QTest::addColumn<qreal>("granularity");
6493     QTest::addColumn<QTransform>("transform");
6494     QTest::addColumn<QRegion>("expectedRegion");
6495
6496     QTest::newRow("(0, 0, 10, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.0) << QTransform()
6497                                                                         << QRegion(QRect(0, 0, 10, 10));
6498     QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform()
6499                                                                        << QRegion(QRect(0, 0, 10, 1));
6500     QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform()
6501                                                                       << QRegion(QRect(0, 0, 10, 1));
6502     QTest::newRow("(0, 0, 10, 0) | 1.0 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(1.0) << QTransform()
6503                                                                       << QRegion(QRect(0, 0, 10, 1));
6504     QTest::newRow("(0, 0, 0, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.0) << QTransform()
6505                                                                        << QRegion(QRect(0, 0, 1, 10));
6506     QTest::newRow("(0, 0, 0, 10) | 0.5 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.5) << QTransform()
6507                                                                       << QRegion(QRect(0, 0, 1, 10));
6508     QTest::newRow("(0, 0, 0, 10) | 1.0 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(1.0) << QTransform()
6509                                                                       << QRegion(QRect(0, 0, 1, 10));
6510 }
6511
6512 void tst_QGraphicsItem::boundingRegion()
6513 {
6514     QFETCH(QLineF, line);
6515     QFETCH(qreal, granularity);
6516     QFETCH(QTransform, transform);
6517     QFETCH(QRegion, expectedRegion);
6518
6519     QGraphicsLineItem item(line);
6520     QCOMPARE(item.boundingRegionGranularity(), qreal(0.0));
6521     item.setBoundingRegionGranularity(granularity);
6522     QCOMPARE(item.boundingRegionGranularity(), granularity);
6523     QCOMPARE(item.boundingRegion(transform), expectedRegion);
6524 }
6525
6526 void tst_QGraphicsItem::itemTransform_parentChild()
6527 {
6528     QGraphicsScene scene;
6529     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6530     QGraphicsItem *child = scene.addRect(0, 0, 100, 100);
6531     child->setParentItem(parent);
6532     child->setPos(10, 10);
6533     child->scale(2, 2);
6534     child->rotate(90);
6535
6536     QCOMPARE(child->itemTransform(parent).map(QPointF(10, 10)), QPointF(-10, 30));
6537     QCOMPARE(parent->itemTransform(child).map(QPointF(-10, 30)), QPointF(10, 10));
6538 }
6539
6540 void tst_QGraphicsItem::itemTransform_siblings()
6541 {
6542     QGraphicsScene scene;
6543     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6544     QGraphicsItem *brother = scene.addRect(0, 0, 100, 100);
6545     QGraphicsItem *sister = scene.addRect(0, 0, 100, 100);
6546     parent->scale(10, 5);
6547     parent->rotate(-180);
6548     parent->shear(2, 3);
6549
6550     brother->setParentItem(parent);
6551     sister->setParentItem(parent);
6552
6553     brother->setPos(10, 10);
6554     brother->scale(2, 2);
6555     brother->rotate(90);
6556     sister->setPos(10, 10);
6557     sister->scale(2, 2);
6558     sister->rotate(90);
6559
6560     QCOMPARE(brother->itemTransform(sister).map(QPointF(10, 10)), QPointF(10, 10));
6561     QCOMPARE(sister->itemTransform(brother).map(QPointF(10, 10)), QPointF(10, 10));
6562 }
6563
6564 void tst_QGraphicsItem::itemTransform_unrelated()
6565 {
6566     QGraphicsScene scene;
6567     QGraphicsItem *stranger1 = scene.addRect(0, 0, 100, 100);
6568     QGraphicsItem *stranger2 = scene.addRect(0, 0, 100, 100);
6569     stranger1->setPos(10, 10);
6570     stranger1->scale(2, 2);
6571     stranger1->rotate(90);
6572     stranger2->setPos(10, 10);
6573     stranger2->scale(2, 2);
6574     stranger2->rotate(90);
6575
6576     QCOMPARE(stranger1->itemTransform(stranger2).map(QPointF(10, 10)), QPointF(10, 10));
6577     QCOMPARE(stranger2->itemTransform(stranger1).map(QPointF(10, 10)), QPointF(10, 10));
6578 }
6579
6580 void tst_QGraphicsItem::opacity_data()
6581 {
6582     QTest::addColumn<qreal>("p_opacity");
6583     QTest::addColumn<int>("p_opacityFlags");
6584     QTest::addColumn<qreal>("c1_opacity");
6585     QTest::addColumn<int>("c1_opacityFlags");
6586     QTest::addColumn<qreal>("c2_opacity");
6587     QTest::addColumn<int>("c2_opacityFlags");
6588     QTest::addColumn<qreal>("p_effectiveOpacity");
6589     QTest::addColumn<qreal>("c1_effectiveOpacity");
6590     QTest::addColumn<qreal>("c2_effectiveOpacity");
6591     QTest::addColumn<qreal>("c3_effectiveOpacity");
6592
6593     // Modify the opacity and see how it propagates
6594     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
6595                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6596     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
6597                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6598     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
6599                                                         << qreal(0.5) << qreal(0.05) << qreal(0.05) << qreal(0.05);
6600     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
6601                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6602
6603     // Parent doesn't propagate to children - now modify the opacity and see how it propagates
6604     int flags = QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6605     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
6606                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6607     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
6608                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6609     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
6610                                                         << qreal(0.5) << qreal(0.1) << qreal(0.1) << qreal(0.1);
6611     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
6612                                                         << qreal(0.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6613
6614     // Child ignores parent - now modify the opacity and see how it propagates
6615     flags = QGraphicsItem::ItemIgnoresParentOpacity;
6616     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
6617                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6618     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
6619                                                         << qreal(0.5) << qreal(0.5) << qreal(0.25) << qreal(0.25);
6620     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
6621                                                         << qreal(0.2) << qreal(0.2) << qreal(0.04) << qreal(0.04);
6622     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
6623                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6624
6625     // Child ignores parent and doesn't propagate - now modify the opacity and see how it propagates
6626     flags = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6627     QTest::newRow("M: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6628                                                         << qreal(1.0) << flags // c1 (no prop)
6629                                                         << qreal(1.0) << 0 // c2
6630                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6631     QTest::newRow("M: 0.5 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6632                                                         << qreal(1.0) << flags // c1 (no prop)
6633                                                         << qreal(1.0) << 0 // c2
6634                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6635     QTest::newRow("M: 0.5 0 0.5 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6636                                                         << qreal(0.5) << flags // c1 (no prop)
6637                                                         << qreal(1.0) << 0 // c2
6638                                                         << qreal(0.5) << qreal(0.5) << qreal(1.0) << qreal(1.0);
6639     QTest::newRow("M: 0.5 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6640                                                         << qreal(0.5) << flags // c1 (no prop)
6641                                                         << qreal(0.5) << 0 // c2
6642                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6643     QTest::newRow("M: 1.0 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6644                                                         << qreal(0.5) << flags // c1 (no prop)
6645                                                         << qreal(0.5) << 0 // c2
6646                                                         << qreal(1.0) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6647 }
6648
6649 void tst_QGraphicsItem::opacity()
6650 {
6651     QFETCH(qreal, p_opacity);
6652     QFETCH(int, p_opacityFlags);
6653     QFETCH(qreal, p_effectiveOpacity);
6654     QFETCH(qreal, c1_opacity);
6655     QFETCH(int, c1_opacityFlags);
6656     QFETCH(qreal, c1_effectiveOpacity);
6657     QFETCH(qreal, c2_opacity);
6658     QFETCH(int, c2_opacityFlags);
6659     QFETCH(qreal, c2_effectiveOpacity);
6660     QFETCH(qreal, c3_effectiveOpacity);
6661
6662     QGraphicsRectItem *p = new QGraphicsRectItem;
6663     QGraphicsRectItem *c1 = new QGraphicsRectItem(p);
6664     QGraphicsRectItem *c2 = new QGraphicsRectItem(c1);
6665     QGraphicsRectItem *c3 = new QGraphicsRectItem(c2);
6666
6667     QCOMPARE(p->opacity(), qreal(1.0));
6668     QCOMPARE(p->effectiveOpacity(), qreal(1.0));
6669     int opacityMask = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6670     QVERIFY(!(p->flags() & opacityMask));
6671
6672     p->setOpacity(p_opacity);
6673     c1->setOpacity(c1_opacity);
6674     c2->setOpacity(c2_opacity);
6675     p->setFlags(QGraphicsItem::GraphicsItemFlags(p->flags() | p_opacityFlags));
6676     c1->setFlags(QGraphicsItem::GraphicsItemFlags(c1->flags() | c1_opacityFlags));
6677     c2->setFlags(QGraphicsItem::GraphicsItemFlags(c2->flags() | c2_opacityFlags));
6678
6679     QCOMPARE(int(p->flags() & opacityMask), p_opacityFlags);
6680     QCOMPARE(int(c1->flags() & opacityMask), c1_opacityFlags);
6681     QCOMPARE(int(c2->flags() & opacityMask), c2_opacityFlags);
6682     QCOMPARE(p->opacity(), p_opacity);
6683     QCOMPARE(p->effectiveOpacity(), p_effectiveOpacity);
6684     QCOMPARE(c1->effectiveOpacity(), c1_effectiveOpacity);
6685     QCOMPARE(c2->effectiveOpacity(), c2_effectiveOpacity);
6686     QCOMPARE(c3->effectiveOpacity(), c3_effectiveOpacity);
6687 }
6688
6689 void tst_QGraphicsItem::opacity2()
6690 {
6691     EventTester *parent = new EventTester;
6692     EventTester *child = new EventTester(parent);
6693     EventTester *grandChild = new EventTester(child);
6694
6695     QGraphicsScene scene;
6696     scene.addItem(parent);
6697
6698     MyGraphicsView view(&scene);
6699     view.show();
6700     QVERIFY(QTest::qWaitForWindowActive(&view));
6701     QTRY_VERIFY(view.repaints >= 1);
6702
6703 #define RESET_REPAINT_COUNTERS \
6704     parent->repaints = 0; \
6705     child->repaints = 0; \
6706     grandChild->repaints = 0; \
6707     view.repaints = 0;
6708
6709     RESET_REPAINT_COUNTERS
6710
6711     child->setOpacity(0.0);
6712     QTest::qWait(10);
6713     QTRY_COMPARE(view.repaints, 1);
6714     QCOMPARE(parent->repaints, 1);
6715     QCOMPARE(child->repaints, 0);
6716     QCOMPARE(grandChild->repaints, 0);
6717
6718     RESET_REPAINT_COUNTERS
6719
6720     child->setOpacity(1.0);
6721     QTest::qWait(10);
6722     QTRY_COMPARE(view.repaints, 1);
6723     QCOMPARE(parent->repaints, 1);
6724     QCOMPARE(child->repaints, 1);
6725     QCOMPARE(grandChild->repaints, 1);
6726
6727     RESET_REPAINT_COUNTERS
6728
6729     parent->setOpacity(0.0);
6730     QTest::qWait(10);
6731     QTRY_COMPARE(view.repaints, 1);
6732     QCOMPARE(parent->repaints, 0);
6733     QCOMPARE(child->repaints, 0);
6734     QCOMPARE(grandChild->repaints, 0);
6735
6736     RESET_REPAINT_COUNTERS
6737
6738     parent->setOpacity(1.0);
6739     QTest::qWait(10);
6740     QTRY_COMPARE(view.repaints, 1);
6741     QCOMPARE(parent->repaints, 1);
6742     QCOMPARE(child->repaints, 1);
6743     QCOMPARE(grandChild->repaints, 1);
6744
6745     grandChild->setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
6746     RESET_REPAINT_COUNTERS
6747
6748     child->setOpacity(0.0);
6749     QTest::qWait(10);
6750     QTRY_COMPARE(view.repaints, 1);
6751     QCOMPARE(parent->repaints, 1);
6752     QCOMPARE(child->repaints, 0);
6753     QCOMPARE(grandChild->repaints, 1);
6754
6755     RESET_REPAINT_COUNTERS
6756
6757     child->setOpacity(0.0); // Already 0.0; no change.
6758     QTest::qWait(10);
6759     QTRY_COMPARE(view.repaints, 0);
6760     QCOMPARE(parent->repaints, 0);
6761     QCOMPARE(child->repaints, 0);
6762     QCOMPARE(grandChild->repaints, 0);
6763 }
6764
6765 void tst_QGraphicsItem::opacityZeroUpdates()
6766 {
6767     EventTester *parent = new EventTester;
6768     EventTester *child = new EventTester(parent);
6769
6770     child->setPos(10, 10);
6771
6772     QGraphicsScene scene;
6773     scene.addItem(parent);
6774
6775     MyGraphicsView view(&scene);
6776     view.show();
6777     QVERIFY(QTest::qWaitForWindowActive(&view));
6778     QTRY_VERIFY(view.repaints > 0);
6779
6780     view.reset();
6781     parent->setOpacity(0.0);
6782
6783     QTest::qWait(20);
6784
6785     // transforming items bounding rect to view coordinates
6786     const QRect childDeviceBoundingRect = child->deviceTransform(view.viewportTransform())
6787                                            .mapRect(child->boundingRect()).toRect();
6788     const QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
6789                                            .mapRect(parent->boundingRect()).toRect();
6790
6791     QRegion expectedRegion = parentDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6792     expectedRegion += childDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6793
6794     COMPARE_REGIONS(view.paintedRegion, expectedRegion);
6795 }
6796
6797 class StacksBehindParentHelper : public QGraphicsRectItem
6798 {
6799 public:
6800     StacksBehindParentHelper(QList<QGraphicsItem *> *paintedItems, const QRectF &rect, QGraphicsItem *parent = 0)
6801         : QGraphicsRectItem(rect, parent), paintedItems(paintedItems)
6802     { }
6803
6804     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
6805     {
6806         QGraphicsRectItem::paint(painter, option, widget);
6807         paintedItems->append(this);
6808     }
6809
6810 private:
6811     QList<QGraphicsItem *> *paintedItems;
6812 };
6813
6814 void tst_QGraphicsItem::itemStacksBehindParent()
6815 {
6816     StacksBehindParentHelper *parent1 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6817     StacksBehindParentHelper *child11 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent1);
6818     StacksBehindParentHelper *grandChild111 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child11);
6819     StacksBehindParentHelper *child12 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent1);
6820     StacksBehindParentHelper *grandChild121 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child12);
6821
6822     StacksBehindParentHelper *parent2 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6823     StacksBehindParentHelper *child21 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent2);
6824     StacksBehindParentHelper *grandChild211 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child21);
6825     StacksBehindParentHelper *child22 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent2);
6826     StacksBehindParentHelper *grandChild221 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child22);
6827
6828     parent1->setData(0, "parent1");
6829     child11->setData(0, "child11");
6830     grandChild111->setData(0, "grandChild111");
6831     child12->setData(0, "child12");
6832     grandChild121->setData(0, "grandChild121");
6833     parent2->setData(0, "parent2");
6834     child21->setData(0, "child21");
6835     grandChild211->setData(0, "grandChild211");
6836     child22->setData(0, "child22");
6837     grandChild221->setData(0, "grandChild221");
6838
6839     // Disambiguate siblings
6840     parent1->setZValue(1);
6841     child11->setZValue(1);
6842     child21->setZValue(1);
6843
6844     QGraphicsScene scene;
6845     scene.addItem(parent1);
6846     scene.addItem(parent2);
6847
6848     QGraphicsView view(&scene);
6849     view.show();
6850     QVERIFY(QTest::qWaitForWindowExposed(&view));
6851     QTRY_VERIFY(!paintedItems.isEmpty());
6852     QTest::qWait(100);
6853     paintedItems.clear();
6854     view.viewport()->update();
6855     QApplication::processEvents();
6856     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6857                                            << grandChild111 << child11
6858                                            << grandChild121 << child12 << parent1
6859                                            << grandChild211 << child21
6860                                            << grandChild221 << child22 << parent2));
6861     QTRY_COMPARE(paintedItems, QList<QGraphicsItem *>()
6862              << parent2 << child22 << grandChild221
6863              << child21 << grandChild211
6864              << parent1 << child12 << grandChild121
6865              << child11 << grandChild111);
6866
6867     child11->setFlag(QGraphicsItem::ItemStacksBehindParent);
6868     scene.update();
6869     paintedItems.clear();
6870     QApplication::processEvents();
6871
6872     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6873                                            << grandChild121 << child12 << parent1
6874                                            << grandChild111 << child11
6875                                            << grandChild211 << child21
6876                                            << grandChild221 << child22 << parent2));
6877     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6878              << parent2 << child22 << grandChild221
6879              << child21 << grandChild211
6880              << child11 << grandChild111
6881              << parent1 << child12 << grandChild121);
6882
6883     child12->setFlag(QGraphicsItem::ItemStacksBehindParent);
6884     paintedItems.clear();
6885     scene.update();
6886     QApplication::processEvents();
6887
6888     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6889                                            << parent1 << grandChild111 << child11
6890                                            << grandChild121 << child12
6891                                            << grandChild211 << child21
6892                                            << grandChild221 << child22 << parent2));
6893     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6894              << parent2 << child22 << grandChild221
6895              << child21 << grandChild211
6896              << child12 << grandChild121
6897              << child11 << grandChild111 << parent1);
6898 }
6899
6900 class ClippingAndTransformsScene : public QGraphicsScene
6901 {
6902 public:
6903     QList<QGraphicsItem *> drawnItems;
6904 protected:
6905     void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[],
6906                    const QStyleOptionGraphicsItem options[], QWidget *widget = 0)
6907     {
6908         drawnItems.clear();
6909         for (int i = 0; i < numItems; ++i)
6910             drawnItems << items[i];
6911         QGraphicsScene::drawItems(painter, numItems, items, options, widget);
6912     }
6913 };
6914
6915 void tst_QGraphicsItem::nestedClipping()
6916 {
6917     ClippingAndTransformsScene scene;
6918     scene.setSceneRect(-50, -50, 200, 200);
6919
6920     QGraphicsRectItem *root = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6921     root->setBrush(QColor(0, 0, 255));
6922     root->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6923     QGraphicsRectItem *l1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6924     l1->setParentItem(root);
6925     l1->setPos(-50, 0);
6926     l1->setBrush(QColor(255, 0, 0));
6927     l1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6928     QGraphicsEllipseItem *l2 = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100));
6929     l2->setParentItem(l1);
6930     l2->setPos(50, 50);
6931     l2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6932     l2->setBrush(QColor(255, 255, 0));
6933     QGraphicsRectItem *l3 = new QGraphicsRectItem(QRectF(0, 0, 25, 25));
6934     l3->setParentItem(l2);
6935     l3->setBrush(QColor(0, 255, 0));
6936     l3->setPos(50 - 12, -12);
6937
6938     scene.addItem(root);
6939
6940     root->setData(0, "root");
6941     l1->setData(0, "l1");
6942     l2->setData(0, "l2");
6943     l3->setData(0, "l3");
6944
6945     QGraphicsView view(&scene);
6946     view.setOptimizationFlag(QGraphicsView::IndirectPainting);
6947     view.show();
6948     QVERIFY(QTest::qWaitForWindowExposed(&view));
6949     QTest::qWait(25);
6950
6951     QList<QGraphicsItem *> expected;
6952     expected << root << l1 << l2 << l3;
6953     QTRY_COMPARE(scene.drawnItems, expected);
6954
6955     QImage image(200, 200, QImage::Format_ARGB32_Premultiplied);
6956     image.fill(0);
6957
6958     QPainter painter(&image);
6959     scene.render(&painter);
6960     painter.end();
6961
6962     // Check transparent areas
6963     QCOMPARE(image.pixel(100, 25), qRgba(0, 0, 0, 0));
6964     QCOMPARE(image.pixel(100, 175), qRgba(0, 0, 0, 0));
6965     QCOMPARE(image.pixel(25, 100), qRgba(0, 0, 0, 0));
6966     QCOMPARE(image.pixel(175, 100), qRgba(0, 0, 0, 0));
6967     QCOMPARE(image.pixel(70, 80), qRgba(255, 0, 0, 255));
6968     QCOMPARE(image.pixel(80, 130), qRgba(255, 255, 0, 255));
6969     QCOMPARE(image.pixel(92, 105), qRgba(0, 255, 0, 255));
6970     QCOMPARE(image.pixel(105, 105), qRgba(0, 0, 255, 255));
6971 #if 0
6972     // Enable this to compare if the test starts failing.
6973     image.save("nestedClipping_reference.png");
6974 #endif
6975 }
6976
6977 class TransformDebugItem : public QGraphicsRectItem
6978 {
6979 public:
6980     TransformDebugItem()
6981         : QGraphicsRectItem(QRectF(-10, -10, 20, 20))
6982     {
6983         setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
6984     }
6985
6986     QTransform x;
6987
6988     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
6989                QWidget *widget = 0)
6990     {
6991         x = painter->worldTransform();
6992         QGraphicsRectItem::paint(painter, option, widget);
6993     }
6994 };
6995
6996 void tst_QGraphicsItem::nestedClippingTransforms()
6997 {
6998     TransformDebugItem *rootClipper = new TransformDebugItem;
6999     rootClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7000     TransformDebugItem *child = new TransformDebugItem;
7001     child->setParentItem(rootClipper);
7002     child->setPos(2, 2);
7003     TransformDebugItem *grandChildClipper = new TransformDebugItem;
7004     grandChildClipper->setParentItem(child);
7005     grandChildClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7006     grandChildClipper->setPos(4, 4);
7007     TransformDebugItem *greatGrandChild = new TransformDebugItem;
7008     greatGrandChild->setPos(2, 2);
7009     greatGrandChild->setParentItem(grandChildClipper);
7010     TransformDebugItem *grandChildClipper2 = new TransformDebugItem;
7011     grandChildClipper2->setParentItem(child);
7012     grandChildClipper2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7013     grandChildClipper2->setPos(8, 8);
7014     TransformDebugItem *greatGrandChild2 = new TransformDebugItem;
7015     greatGrandChild2->setPos(2, 2);
7016     greatGrandChild2->setParentItem(grandChildClipper2);
7017     TransformDebugItem *grandChildClipper3 = new TransformDebugItem;
7018     grandChildClipper3->setParentItem(child);
7019     grandChildClipper3->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7020     grandChildClipper3->setPos(12, 12);
7021     TransformDebugItem *greatGrandChild3 = new TransformDebugItem;
7022     greatGrandChild3->setPos(2, 2);
7023     greatGrandChild3->setParentItem(grandChildClipper3);
7024
7025     QGraphicsScene scene;
7026     scene.addItem(rootClipper);
7027
7028     QImage image(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
7029     image.fill(0);
7030     QPainter p(&image);
7031     scene.render(&p);
7032     p.end();
7033
7034     QCOMPARE(rootClipper->x, QTransform(1, 0, 0, 0, 1, 0, 10, 10, 1));
7035     QCOMPARE(child->x, QTransform(1, 0, 0, 0, 1, 0, 12, 12, 1));
7036     QCOMPARE(grandChildClipper->x, QTransform(1, 0, 0, 0, 1, 0, 16, 16, 1));
7037     QCOMPARE(greatGrandChild->x, QTransform(1, 0, 0, 0, 1, 0, 18, 18, 1));
7038     QCOMPARE(grandChildClipper2->x, QTransform(1, 0, 0, 0, 1, 0, 20, 20, 1));
7039     QCOMPARE(greatGrandChild2->x, QTransform(1, 0, 0, 0, 1, 0, 22, 22, 1));
7040     QCOMPARE(grandChildClipper3->x, QTransform(1, 0, 0, 0, 1, 0, 24, 24, 1));
7041     QCOMPARE(greatGrandChild3->x, QTransform(1, 0, 0, 0, 1, 0, 26, 26, 1));
7042 }
7043
7044 void tst_QGraphicsItem::sceneTransformCache()
7045 {
7046     // Test that an item's scene transform is updated correctly when the
7047     // parent is transformed.
7048     QGraphicsScene scene;
7049     QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
7050     QGraphicsRectItem *rect2 = scene.addRect(0, 0, 100, 100);
7051     rect2->setParentItem(rect);
7052     rect2->rotate(90);
7053     rect->translate(0, 50);
7054     QGraphicsView view(&scene);
7055     view.show();
7056     QVERIFY(QTest::qWaitForWindowExposed(&view));
7057     rect->translate(0, 100);
7058     QTransform x;
7059     x.translate(0, 150);
7060     x.rotate(90);
7061     QCOMPARE(rect2->sceneTransform(), x);
7062
7063     scene.removeItem(rect);
7064
7065     //Crazy use case : rect4 child of rect3 so the transformation of rect4 will be cached.Good!
7066     //We remove rect4 from the scene, then the validTransform bit flag is set to 0 and the index of the cache
7067     //add to the freeTransformSlots. The problem was that sceneTransformIndex was not set to -1 so if a new item arrive
7068     //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
7069     //added back to the scene then it will set the transform to his old sceneTransformIndex value that will erase the new
7070     //value of rect6 so rect6 transform will be wrong.
7071     QGraphicsRectItem *rect3 = scene.addRect(0, 0, 100, 100);
7072     QGraphicsRectItem *rect4 = scene.addRect(0, 0, 100, 100);
7073     rect3->setPos(QPointF(10,10));
7074
7075     rect4->setParentItem(rect3);
7076     rect4->setPos(QPointF(10,10));
7077
7078     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(20,20));
7079
7080     scene.removeItem(rect4);
7081     //rect4 transform is local only
7082     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7083
7084     QGraphicsRectItem *rect5 = scene.addRect(0, 0, 100, 100);
7085     QGraphicsRectItem *rect6 = scene.addRect(0, 0, 100, 100);
7086     rect5->setPos(QPointF(20,20));
7087
7088     rect6->setParentItem(rect5);
7089     rect6->setPos(QPointF(10,10));
7090     //test if rect6 transform is ok
7091     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7092
7093     scene.addItem(rect4);
7094
7095     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7096     //test if rect6 transform is still correct
7097     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7098 }
7099
7100 void tst_QGraphicsItem::tabChangesFocus_data()
7101 {
7102     QTest::addColumn<bool>("tabChangesFocus");
7103     QTest::newRow("tab changes focus") << true;
7104     QTest::newRow("tab doesn't change focus") << false;
7105 }
7106
7107 void tst_QGraphicsItem::tabChangesFocus()
7108 {
7109     QFETCH(bool, tabChangesFocus);
7110
7111     QGraphicsScene scene;
7112     QGraphicsTextItem *item = scene.addText("Hello");
7113     item->setTabChangesFocus(tabChangesFocus);
7114     item->setTextInteractionFlags(Qt::TextEditorInteraction);
7115     item->setFocus();
7116
7117     QDial *dial1 = new QDial;
7118     QGraphicsView *view = new QGraphicsView(&scene);
7119
7120     QDial *dial2 = new QDial;
7121     QVBoxLayout *layout = new QVBoxLayout;
7122     layout->addWidget(dial1);
7123     layout->addWidget(view);
7124     layout->addWidget(dial2);
7125
7126     QWidget widget;
7127     widget.setLayout(layout);
7128     widget.show();
7129     QVERIFY(QTest::qWaitForWindowActive(&widget));
7130
7131     QTRY_VERIFY(scene.isActive());
7132
7133     dial1->setFocus();
7134     QTest::qWait(15);
7135     QTRY_VERIFY(dial1->hasFocus());
7136
7137     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7138     QTest::qWait(15);
7139     QTRY_VERIFY(view->hasFocus());
7140     QTRY_VERIFY(item->hasFocus());
7141
7142     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7143     QTest::qWait(15);
7144
7145     if (tabChangesFocus) {
7146         QTRY_VERIFY(!view->hasFocus());
7147         QTRY_VERIFY(!item->hasFocus());
7148         QTRY_VERIFY(dial2->hasFocus());
7149     } else {
7150         QTRY_VERIFY(view->hasFocus());
7151         QTRY_VERIFY(item->hasFocus());
7152         QCOMPARE(item->toPlainText(), QString("\tHello"));
7153     }
7154 }
7155
7156 void tst_QGraphicsItem::cacheMode()
7157 {
7158     QGraphicsScene scene(0, 0, 100, 100);
7159     QGraphicsView view(&scene);
7160     view.resize(150, 150);
7161     view.show();
7162     QApplication::setActiveWindow(&view);
7163     QVERIFY(QTest::qWaitForWindowActive(&view));
7164
7165     // Increase the probability of window activation
7166     // not causing another repaint of test items.
7167     QTest::qWait(50);
7168
7169     EventTester *tester = new EventTester;
7170     EventTester *testerChild = new EventTester;
7171     testerChild->setParentItem(tester);
7172     EventTester *testerChild2 = new EventTester;
7173     testerChild2->setParentItem(testerChild);
7174     testerChild2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
7175
7176     scene.addItem(tester);
7177     QTest::qWait(10);
7178
7179     for (int i = 0; i < 2; ++i) {
7180         // No visual change.
7181         QTRY_COMPARE(tester->repaints, 1);
7182         QCOMPARE(testerChild->repaints, 1);
7183         QCOMPARE(testerChild2->repaints, 1);
7184         tester->setCacheMode(QGraphicsItem::NoCache);
7185         testerChild->setCacheMode(QGraphicsItem::NoCache);
7186         testerChild2->setCacheMode(QGraphicsItem::NoCache);
7187         QTest::qWait(25);
7188         QTRY_COMPARE(tester->repaints, 1);
7189         QCOMPARE(testerChild->repaints, 1);
7190         QCOMPARE(testerChild2->repaints, 1);
7191         tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7192         testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7193         testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7194         QTest::qWait(25);
7195     }
7196
7197     // The first move causes a repaint as the item is painted into its pixmap.
7198     // (Only occurs if the item has previously been painted without cache).
7199     tester->setPos(10, 10);
7200     testerChild->setPos(10, 10);
7201     testerChild2->setPos(10, 10);
7202     QTest::qWait(25);
7203     QTRY_COMPARE(tester->repaints, 2);
7204     QCOMPARE(testerChild->repaints, 2);
7205     QCOMPARE(testerChild2->repaints, 2);
7206
7207     // Consecutive moves should not repaint.
7208     tester->setPos(20, 20);
7209     testerChild->setPos(20, 20);
7210     testerChild2->setPos(20, 20);
7211     QTest::qWait(250);
7212     QCOMPARE(tester->repaints, 2);
7213     QCOMPARE(testerChild->repaints, 2);
7214     QCOMPARE(testerChild2->repaints, 2);
7215
7216     // Translating does not result in a repaint.
7217     tester->translate(10, 10);
7218     QTest::qWait(25);
7219     QTRY_COMPARE(tester->repaints, 2);
7220     QCOMPARE(testerChild->repaints, 2);
7221     QCOMPARE(testerChild2->repaints, 2);
7222
7223     // Rotating results in a repaint.
7224     tester->rotate(45);
7225     QTest::qWait(25);
7226     QTRY_COMPARE(tester->repaints, 3);
7227     QCOMPARE(testerChild->repaints, 3);
7228     QCOMPARE(testerChild2->repaints, 2);
7229
7230     // Change to ItemCoordinateCache (triggers repaint).
7231     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7232     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7233     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7234     QTest::qWait(25);
7235     QTRY_COMPARE(tester->repaints, 4);
7236     QCOMPARE(testerChild->repaints, 4);
7237     QCOMPARE(testerChild2->repaints, 3);
7238
7239     // Rotating items with ItemCoordinateCache doesn't cause a repaint.
7240     tester->rotate(22);
7241     testerChild->rotate(22);
7242     testerChild2->rotate(22);
7243     QTest::qWait(25);
7244     QTRY_COMPARE(tester->repaints, 4);
7245     QTRY_COMPARE(testerChild->repaints, 4);
7246     QTRY_COMPARE(testerChild2->repaints, 3);
7247     tester->resetTransform();
7248     testerChild->resetTransform();
7249     testerChild2->resetTransform();
7250
7251     // Explicit update causes a repaint.
7252     tester->update(0, 0, 5, 5);
7253     QTest::qWait(25);
7254     QTRY_COMPARE(tester->repaints, 5);
7255     QCOMPARE(testerChild->repaints, 4);
7256     QCOMPARE(testerChild2->repaints, 3);
7257
7258     // Updating outside the item's bounds does not cause a repaint.
7259     tester->update(10, 10, 5, 5);
7260     QTest::qWait(25);
7261     QTRY_COMPARE(tester->repaints, 5);
7262     QCOMPARE(testerChild->repaints, 4);
7263     QCOMPARE(testerChild2->repaints, 3);
7264
7265     // Resizing an item should cause a repaint of that item. (because of
7266     // autosize).
7267     tester->setGeometry(QRectF(-15, -15, 30, 30));
7268     QTest::qWait(25);
7269     QTRY_COMPARE(tester->repaints, 6);
7270     QCOMPARE(testerChild->repaints, 4);
7271     QCOMPARE(testerChild2->repaints, 3);
7272
7273     // Set fixed size.
7274     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7275     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7276     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7277     QTest::qWait(20);
7278     QTRY_COMPARE(tester->repaints, 7);
7279     QCOMPARE(testerChild->repaints, 5);
7280     QCOMPARE(testerChild2->repaints, 4);
7281
7282     // Resizing the item should cause a repaint.
7283     testerChild->setGeometry(QRectF(-15, -15, 30, 30));
7284     QTest::qWait(25);
7285     QTRY_COMPARE(tester->repaints, 7);
7286     QCOMPARE(testerChild->repaints, 6);
7287     QCOMPARE(testerChild2->repaints, 4);
7288
7289     // Scaling the view does not cause a repaint.
7290     view.scale(0.7, 0.7);
7291     QTest::qWait(25);
7292     QTRY_COMPARE(tester->repaints, 7);
7293     QCOMPARE(testerChild->repaints, 6);
7294     QCOMPARE(testerChild2->repaints, 4);
7295
7296     // Switch to device coordinate cache.
7297     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7298     testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7299     testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7300     QTest::qWait(25);
7301     QTRY_COMPARE(tester->repaints, 8);
7302     QCOMPARE(testerChild->repaints, 7);
7303     QCOMPARE(testerChild2->repaints, 5);
7304
7305     // Scaling the view back should cause repaints for two of the items.
7306     view.setTransform(QTransform());
7307     QTest::qWait(25);
7308     QTRY_COMPARE(tester->repaints, 9);
7309     QCOMPARE(testerChild->repaints, 8);
7310     QCOMPARE(testerChild2->repaints, 5);
7311
7312     // Rotating the base item (perspective) should repaint two items.
7313     tester->setTransform(QTransform().rotate(10, Qt::XAxis));
7314     QTest::qWait(25);
7315     QTRY_COMPARE(tester->repaints, 10);
7316     QCOMPARE(testerChild->repaints, 9);
7317     QCOMPARE(testerChild2->repaints, 5);
7318
7319     // Moving the middle item should case a repaint even if it's a move,
7320     // because the parent is rotated with a perspective.
7321     testerChild->setPos(1, 1);
7322     QTest::qWait(25);
7323     QTRY_COMPARE(tester->repaints, 11);
7324     QTRY_COMPARE(testerChild->repaints, 10);
7325     QTRY_COMPARE(testerChild2->repaints, 5);
7326     tester->resetTransform();
7327
7328     // Make a huge item
7329     tester->setGeometry(QRectF(-4000, -4000, 8000, 8000));
7330     QTRY_COMPARE(tester->repaints, 12);
7331     QTRY_COMPARE(testerChild->repaints, 11);
7332     QTRY_COMPARE(testerChild2->repaints, 5);
7333
7334     // Move the large item - will cause a repaint as the
7335     // cache is clipped.
7336     tester->setPos(5, 0);
7337     QTRY_COMPARE(tester->repaints, 13);
7338     QTRY_COMPARE(testerChild->repaints, 11);
7339     QTRY_COMPARE(testerChild2->repaints, 5);
7340
7341     // Hiding and showing should invalidate the cache
7342     tester->hide();
7343     QTest::qWait(25);
7344     tester->show();
7345     QTRY_COMPARE(tester->repaints, 14);
7346     QTRY_COMPARE(testerChild->repaints, 12);
7347     QTRY_COMPARE(testerChild2->repaints, 6);
7348 }
7349
7350 void tst_QGraphicsItem::cacheMode2()
7351 {
7352     QGraphicsScene scene(0, 0, 100, 100);
7353     QGraphicsView view(&scene);
7354     view.resize(150, 150);
7355     view.show();
7356     QApplication::setActiveWindow(&view);
7357     QVERIFY(QTest::qWaitForWindowActive(&view));
7358
7359     // Increase the probability of window activation
7360     // not causing another repaint of test items.
7361     QTest::qWait(50);
7362
7363     EventTester *tester = new EventTester;
7364     scene.addItem(tester);
7365     QTest::qWait(10);
7366     QTRY_COMPARE(tester->repaints, 1);
7367
7368     // Switching from NoCache to NoCache (no repaint)
7369     tester->setCacheMode(QGraphicsItem::NoCache);
7370     QTest::qWait(50);
7371     QTRY_COMPARE(tester->repaints, 1);
7372
7373     // Switching from NoCache to DeviceCoordinateCache (no repaint)
7374     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7375     QTest::qWait(50);
7376     QTRY_COMPARE(tester->repaints, 1);
7377
7378     // Switching from DeviceCoordinateCache to DeviceCoordinateCache (no repaint)
7379     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7380     QTest::qWait(50);
7381     QTRY_COMPARE(tester->repaints, 1);
7382
7383     // Switching from DeviceCoordinateCache to NoCache (no repaint)
7384     tester->setCacheMode(QGraphicsItem::NoCache);
7385     QTest::qWait(50);
7386     QTRY_COMPARE(tester->repaints, 1);
7387
7388     // Switching from NoCache to ItemCoordinateCache (repaint)
7389     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7390     QTest::qWait(50);
7391     QTRY_COMPARE(tester->repaints, 2);
7392
7393     // Switching from ItemCoordinateCache to ItemCoordinateCache (no repaint)
7394     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7395     QTest::qWait(50);
7396     QTRY_COMPARE(tester->repaints, 2);
7397
7398     // Switching from ItemCoordinateCache to ItemCoordinateCache with different size (repaint)
7399     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(100, 100));
7400     QTest::qWait(50);
7401     QTRY_COMPARE(tester->repaints, 3);
7402
7403     // Switching from ItemCoordinateCache to NoCache (repaint)
7404     tester->setCacheMode(QGraphicsItem::NoCache);
7405     QTest::qWait(50);
7406     QTRY_COMPARE(tester->repaints, 4);
7407
7408     // Switching from DeviceCoordinateCache to ItemCoordinateCache (repaint)
7409     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7410     QTest::qWait(50);
7411     QTRY_COMPARE(tester->repaints, 4);
7412     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7413     QTest::qWait(50);
7414     QTRY_COMPARE(tester->repaints, 5);
7415
7416     // Switching from ItemCoordinateCache to DeviceCoordinateCache (repaint)
7417     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7418     QTest::qWait(50);
7419     QTRY_COMPARE(tester->repaints, 6);
7420 }
7421
7422 void tst_QGraphicsItem::updateCachedItemAfterMove()
7423 {
7424     // A simple item that uses ItemCoordinateCache
7425     EventTester *tester = new EventTester;
7426     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7427
7428     // Add to a scene, show in a view, ensure it's painted and reset its
7429     // repaint counter.
7430     QGraphicsScene scene;
7431     scene.addItem(tester);
7432     QGraphicsView view(&scene);
7433     view.show();
7434     QVERIFY(QTest::qWaitForWindowExposed(&view));
7435
7436     QTest::qWait(12);
7437     QTRY_VERIFY(tester->repaints > 0);
7438     tester->repaints = 0;
7439
7440     // Move the item, should not cause repaints
7441     tester->setPos(10, 0);
7442     QTest::qWait(12);
7443     QCOMPARE(tester->repaints, 0);
7444
7445     // Move then update, should cause one repaint
7446     tester->setPos(20, 0);
7447     tester->update();
7448     QTest::qWait(12);
7449     QCOMPARE(tester->repaints, 1);
7450
7451     // Hiding the item doesn't cause a repaint
7452     tester->hide();
7453     QTest::qWait(12);
7454     QCOMPARE(tester->repaints, 1);
7455
7456     // Moving a hidden item doesn't cause a repaint
7457     tester->setPos(30, 0);
7458     tester->update();
7459     QTest::qWait(12);
7460     QCOMPARE(tester->repaints, 1);
7461 }
7462
7463 class Track : public QGraphicsRectItem
7464 {
7465 public:
7466     Track(const QRectF &rect)
7467         : QGraphicsRectItem(rect)
7468     {
7469         setAcceptHoverEvents(true);
7470     }
7471
7472     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7473     {
7474         QGraphicsRectItem::paint(painter, option, widget);
7475         painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1x%2\n%3x%4").arg(p.x()).arg(p.y()).arg(sp.x()).arg(sp.y()));
7476     }
7477
7478 protected:
7479     void hoverMoveEvent(QGraphicsSceneHoverEvent *event)
7480     {
7481         p = event->pos();
7482         sp = event->widget()->mapFromGlobal(event->screenPos());
7483         update();
7484     }
7485 private:
7486     QPointF p;
7487     QPoint sp;
7488 };
7489
7490 void tst_QGraphicsItem::deviceTransform_data()
7491 {
7492     QTest::addColumn<bool>("untransformable1");
7493     QTest::addColumn<bool>("untransformable2");
7494     QTest::addColumn<bool>("untransformable3");
7495     QTest::addColumn<qreal>("rotation1");
7496     QTest::addColumn<qreal>("rotation2");
7497     QTest::addColumn<qreal>("rotation3");
7498     QTest::addColumn<QTransform>("deviceX");
7499     QTest::addColumn<QPointF>("mapResult1");
7500     QTest::addColumn<QPointF>("mapResult2");
7501     QTest::addColumn<QPointF>("mapResult3");
7502
7503     QTest::newRow("nil") << false << false << false
7504                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7505                          << QTransform()
7506                          << QPointF(150, 150) << QPointF(250, 250) << QPointF(350, 350);
7507     QTest::newRow("deviceX rot 90") << false << false << false
7508                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7509                          << QTransform().rotate(90)
7510                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-350, 350);
7511     QTest::newRow("deviceX rot 90 100") << true << false << false
7512                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7513                          << QTransform().rotate(90)
7514                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7515     QTest::newRow("deviceX rot 90 010") << false << true << false
7516                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7517                          << QTransform().rotate(90)
7518                          << QPointF(-150, 150) << QPointF(-150, 250) << QPointF(-50, 350);
7519     QTest::newRow("deviceX rot 90 001") << false << false << true
7520                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7521                          << QTransform().rotate(90)
7522                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-250, 350);
7523     QTest::newRow("deviceX rot 90 111") << true << true << true
7524                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7525                          << QTransform().rotate(90)
7526                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7527     QTest::newRow("deviceX rot 90 101") << true << false << true
7528                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7529                          << QTransform().rotate(90)
7530                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7531 }
7532
7533 void tst_QGraphicsItem::deviceTransform()
7534 {
7535     QFETCH(bool, untransformable1);
7536     QFETCH(bool, untransformable2);
7537     QFETCH(bool, untransformable3);
7538     QFETCH(qreal, rotation1);
7539     QFETCH(qreal, rotation2);
7540     QFETCH(qreal, rotation3);
7541     QFETCH(QTransform, deviceX);
7542     QFETCH(QPointF, mapResult1);
7543     QFETCH(QPointF, mapResult2);
7544     QFETCH(QPointF, mapResult3);
7545
7546     QGraphicsScene scene;
7547     Track *rect1 = new Track(QRectF(0, 0, 100, 100));
7548     Track *rect2 = new Track(QRectF(0, 0, 100, 100));
7549     Track *rect3 = new Track(QRectF(0, 0, 100, 100));
7550     rect2->setParentItem(rect1);
7551     rect3->setParentItem(rect2);
7552     rect1->setPos(100, 100);
7553     rect2->setPos(100, 100);
7554     rect3->setPos(100, 100);
7555     rect1->rotate(rotation1);
7556     rect2->rotate(rotation2);
7557     rect3->rotate(rotation3);
7558     rect1->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable1);
7559     rect2->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable2);
7560     rect3->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable3);
7561     rect1->setBrush(Qt::red);
7562     rect2->setBrush(Qt::green);
7563     rect3->setBrush(Qt::blue);
7564     scene.addItem(rect1);
7565
7566     QCOMPARE(rect1->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult1);
7567     QCOMPARE(rect2->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult2);
7568     QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3);
7569 }
7570
7571 void tst_QGraphicsItem::update()
7572 {
7573     QGraphicsScene scene;
7574     scene.setSceneRect(-100, -100, 200, 200);
7575     QWidget topLevel;
7576     MyGraphicsView view(&scene,&topLevel);
7577
7578     topLevel.resize(300, 300);
7579     topLevel.show();
7580     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
7581
7582     EventTester *item = new EventTester;
7583     scene.addItem(item);
7584     QTest::qWait(100); // Make sure all pending updates are processed.
7585     item->repaints = 0;
7586
7587     item->update(); // Item marked as dirty
7588     scene.update(); // Entire scene marked as dirty
7589     qApp->processEvents();
7590     QCOMPARE(item->repaints, 1);
7591
7592     // Make sure the dirty state from the previous update is reset so that
7593     // the item don't think it is already dirty and discards this update.
7594     item->update();
7595     qApp->processEvents();
7596     QCOMPARE(item->repaints, 2);
7597
7598     // Make sure a partial update doesn't cause a full update to be discarded.
7599     view.reset();
7600     item->repaints = 0;
7601     item->update(QRectF(0, 0, 5, 5));
7602     item->update();
7603     qApp->processEvents();
7604     QCOMPARE(item->repaints, 1);
7605     QCOMPARE(view.repaints, 1);
7606     QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7607                                                          .mapRect(item->boundingRect()).toAlignedRect();
7608     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7609     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7610     QCOMPARE(view.paintedRegion, expectedRegion);
7611
7612     // Make sure update requests outside the bounding rect are discarded.
7613     view.reset();
7614     item->repaints = 0;
7615     item->update(-15, -15, 5, 5); // Item's brect: (-10, -10, 20, 20)
7616     qApp->processEvents();
7617     QCOMPARE(item->repaints, 0);
7618     QCOMPARE(view.repaints, 0);
7619
7620     // Make sure the area occupied by an item is repainted when hiding it.
7621     view.reset();
7622     item->repaints = 0;
7623     item->update(); // Full update; all sub-sequent update requests are discarded.
7624     item->hide(); // visible set to 0. ignoreVisible must be set to 1; the item won't be processed otherwise.
7625     qApp->processEvents();
7626     QCOMPARE(item->repaints, 0);
7627     QCOMPARE(view.repaints, 1);
7628     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7629     QCOMPARE(view.paintedRegion, expectedRegion);
7630
7631     // Make sure item is repainted when shown (after being hidden).
7632     view.reset();
7633     item->repaints = 0;
7634     item->show();
7635     qApp->processEvents();
7636     QCOMPARE(item->repaints, 1);
7637     QCOMPARE(view.repaints, 1);
7638     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7639     QCOMPARE(view.paintedRegion, expectedRegion);
7640
7641     item->repaints = 0;
7642     item->hide();
7643     qApp->processEvents();
7644     view.reset();
7645     const QPointF originalPos = item->pos();
7646     item->setPos(5000, 5000);
7647     qApp->processEvents();
7648     QCOMPARE(item->repaints, 0);
7649     QCOMPARE(view.repaints, 0);
7650     qApp->processEvents();
7651
7652     item->setPos(originalPos);
7653     qApp->processEvents();
7654     QCOMPARE(item->repaints, 0);
7655     QCOMPARE(view.repaints, 0);
7656     item->show();
7657     qApp->processEvents();
7658     QCOMPARE(item->repaints, 1);
7659     QCOMPARE(view.repaints, 1);
7660     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7661     QCOMPARE(view.paintedRegion, expectedRegion);
7662
7663     QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
7664     item->setPos(originalPos + QPoint(50, 50));
7665     viewPrivate->updateAll();
7666     QVERIFY(viewPrivate->fullUpdatePending);
7667     QTest::qWait(50);
7668     item->repaints = 0;
7669     view.reset();
7670     item->setPos(originalPos);
7671     QTest::qWait(50);
7672     qApp->processEvents();
7673     QCOMPARE(item->repaints, 1);
7674     QCOMPARE(view.repaints, 1);
7675     COMPARE_REGIONS(view.paintedRegion, expectedRegion + expectedRegion.translated(50, 50));
7676
7677     // Make sure moving a parent item triggers an update on the children
7678     // (even though the parent itself is outside the viewport).
7679     QGraphicsRectItem *parent = new QGraphicsRectItem(0, 0, 10, 10);
7680     parent->setPos(-400, 0);
7681     item->setParentItem(parent);
7682     item->setPos(400, 0);
7683     scene.addItem(parent);
7684     QTest::qWait(50);
7685     itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7686                                                    .mapRect(item->boundingRect()).toAlignedRect();
7687     expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7688     view.reset();
7689     item->repaints = 0;
7690     parent->translate(-400, 0);
7691     qApp->processEvents();
7692     QCOMPARE(item->repaints, 0);
7693     QCOMPARE(view.repaints, 1);
7694     QCOMPARE(view.paintedRegion, expectedRegion);
7695     view.reset();
7696     item->repaints = 0;
7697     parent->translate(400, 0);
7698     qApp->processEvents();
7699     QCOMPARE(item->repaints, 1);
7700     QCOMPARE(view.repaints, 1);
7701     QCOMPARE(view.paintedRegion, expectedRegion);
7702     QCOMPARE(view.paintedRegion, expectedRegion);
7703 }
7704
7705 void tst_QGraphicsItem::setTransformProperties_data()
7706 {
7707     QTest::addColumn<QPointF>("origin");
7708     QTest::addColumn<qreal>("rotation");
7709     QTest::addColumn<qreal>("scale");
7710
7711     QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(1.0);
7712
7713     QTest::newRow("rotation") << QPointF() << qreal(42.2) << qreal(1.0);
7714
7715     QTest::newRow("rotation dicentred") << QPointF(qreal(22.3), qreal(-56.2))
7716                                 << qreal(-2578.2)
7717                                 << qreal(1.0);
7718
7719     QTest::newRow("Scale")    << QPointF() << qreal(0.0)
7720                                           << qreal(6);
7721
7722     QTest::newRow("Everything dicentred")  << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196);
7723 }
7724
7725 /**
7726  * the normal QCOMPARE doesn't work because it doesn't use qFuzzyCompare
7727  */
7728 #define QCOMPARE_TRANSFORM(X1, X2)   QVERIFY(((X1)*(X2).inverted()).isIdentity())
7729
7730 void tst_QGraphicsItem::setTransformProperties()
7731 {
7732     QFETCH(QPointF,origin);
7733     QFETCH(qreal,rotation);
7734     QFETCH(qreal,scale);
7735
7736     QTransform result;
7737     result.translate(origin.x(), origin.y());
7738     result.rotate(rotation, Qt::ZAxis);
7739     result.scale(scale, scale);
7740     result.translate(-origin.x(), -origin.y());
7741
7742     QGraphicsScene scene;
7743     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
7744     scene.addItem(item);
7745
7746     item->setRotation(rotation);
7747     item->setScale(scale);
7748     item->setTransformOriginPoint(origin);
7749
7750     QCOMPARE(item->rotation(), rotation);
7751     QCOMPARE(item->scale(), scale);
7752     QCOMPARE(item->transformOriginPoint(), origin);
7753
7754     QCOMPARE(QTransform(), item->transform());
7755     QCOMPARE(result, item->sceneTransform());
7756
7757     //-----------------------------------------------------------------
7758     //Change the rotation Z
7759     item->setRotation(45);
7760     QTransform result2;
7761     result2.translate(origin.x(), origin.y());
7762     result2.rotate(45);
7763     result2.scale(scale, scale);
7764     result2.translate(-origin.x(), -origin.y());
7765
7766     QCOMPARE(item->rotation(), 45.);
7767     QCOMPARE(item->scale(), scale);
7768     QCOMPARE(item->transformOriginPoint(), origin);
7769
7770     QCOMPARE(QTransform(), item->transform());
7771     QCOMPARE(result2, item->sceneTransform());
7772
7773     //-----------------------------------------------------------------
7774     // calling setTransform() and setPos should change the sceneTransform
7775     item->setTransform(result);
7776     item->setPos(100, -150.5);
7777
7778     QCOMPARE(item->rotation(), 45.);
7779     QCOMPARE(item->scale(), scale);
7780     QCOMPARE(item->transformOriginPoint(), origin);
7781     QCOMPARE(result, item->transform());
7782
7783     QTransform result3(result);
7784
7785     result3.translate(origin.x(), origin.y());
7786     result3.rotate(45);
7787     result3.scale(scale, scale);
7788     result3.translate(-origin.x(), -origin.y());
7789
7790     result3 *= QTransform::fromTranslate(100, -150.5); //the pos;
7791
7792     QCOMPARE(result3, item->sceneTransform());
7793
7794     //-----------------------------------------------------
7795     // setting the propertiees should be the same as setting a transform
7796     {//with center origin on the matrix
7797         QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7798         scene.addItem(item1);
7799         QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7800         scene.addItem(item2);
7801
7802         item1->setPos(12.3, -5);
7803         item2->setPos(12.3, -5);
7804         item1->setRotation(rotation);
7805         item1->setScale(scale);
7806         item1->setTransformOriginPoint(origin);
7807
7808         item2->setTransform(result);
7809
7810         QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform());
7811
7812         QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform());
7813         QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform());
7814     }
7815 }
7816
7817 class MyStyleOptionTester : public QGraphicsRectItem
7818 {
7819 public:
7820     MyStyleOptionTester(const QRectF &rect)
7821         : QGraphicsRectItem(rect), startTrack(false)
7822     {}
7823
7824     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7825     {
7826         if (startTrack) {
7827             //Doesn't use the extended style option so the exposed rect is the boundingRect
7828             if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) {
7829                 QCOMPARE(option->exposedRect, boundingRect());
7830                 QCOMPARE(option->matrix, QMatrix());
7831             } else {
7832                 QVERIFY(option->exposedRect != QRect());
7833                 QVERIFY(option->exposedRect != boundingRect());
7834                 QCOMPARE(option->matrix, sceneTransform().toAffine());
7835             }
7836         }
7837         QGraphicsRectItem::paint(painter, option, widget);
7838     }
7839     bool startTrack;
7840 };
7841
7842 void tst_QGraphicsItem::itemUsesExtendedStyleOption()
7843 {
7844     QGraphicsScene scene(0, 0, 300, 300);
7845     QGraphicsPixmapItem item;
7846     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7847     QCOMPARE(item.flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
7848     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
7849     QCOMPARE(item.flags(), 0);
7850
7851     //We now test the content of the style option
7852     MyStyleOptionTester *rect = new MyStyleOptionTester(QRect(0, 0, 100, 100));
7853     scene.addItem(rect);
7854     rect->setPos(200, 200);
7855     QWidget topLevel;
7856     QGraphicsView view(&scene, &topLevel);
7857     topLevel.setWindowFlags(Qt::X11BypassWindowManagerHint);
7858     rect->startTrack = false;
7859     topLevel.show();
7860     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
7861     QTest::qWait(60);
7862     rect->startTrack = true;
7863     rect->update(10, 10, 10, 10);
7864     QTest::qWait(60);
7865     rect->startTrack = false;
7866     rect->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7867     QVERIFY((rect->flags() & QGraphicsItem::ItemUsesExtendedStyleOption));
7868     QTest::qWait(60);
7869     rect->startTrack = true;
7870     rect->update(10, 10, 10, 10);
7871     QTest::qWait(60);
7872 }
7873
7874 void tst_QGraphicsItem::itemSendsGeometryChanges()
7875 {
7876     ItemChangeTester item;
7877     item.setFlags(0);
7878     item.clear();
7879
7880     QTransform x = QTransform().rotate(45);
7881     QPointF pos(10, 10);
7882     qreal o(0.5);
7883     qreal r(10.0);
7884     qreal s(1.5);
7885     QPointF origin(1.0, 1.0);
7886     item.setTransform(x);
7887     item.setPos(pos);
7888     item.setRotation(r);
7889     item.setScale(s);
7890     item.setTransformOriginPoint(origin);
7891     QCOMPARE(item.transform(), x);
7892     QCOMPARE(item.pos(), pos);
7893     QCOMPARE(item.rotation(), r);
7894     QCOMPARE(item.scale(), s);
7895     QCOMPARE(item.transformOriginPoint(), origin);
7896     QCOMPARE(item.changes.size(), 0);
7897
7898     item.setOpacity(o);
7899     QCOMPARE(item.changes.size(), 2); // opacity
7900
7901     item.setFlag(QGraphicsItem::ItemSendsGeometryChanges);
7902     QCOMPARE(item.changes.size(), 4); // flags
7903     item.setTransform(QTransform());
7904     item.setPos(QPointF());
7905     QCOMPARE(item.changes.size(), 8); // transform + pos
7906     QCOMPARE(item.transform(), QTransform());
7907     QCOMPARE(item.pos(), QPointF());
7908     QCOMPARE(item.opacity(), o);
7909     item.setRotation(0.0);
7910     item.setScale(1.0);
7911     item.setTransformOriginPoint(0.0, 0.0);
7912     QCOMPARE(item.changes.size(), 14); // rotation + scale + origin
7913     QCOMPARE(item.rotation(), qreal(0.0));
7914     QCOMPARE(item.scale(), qreal(1.0));
7915     QCOMPARE(item.transformOriginPoint(), QPointF(0.0, 0.0));
7916
7917     QCOMPARE(item.changes, QList<QGraphicsItem::GraphicsItemChange>()
7918              << QGraphicsItem::ItemOpacityChange
7919              << QGraphicsItem::ItemOpacityHasChanged
7920              << QGraphicsItem::ItemFlagsChange
7921              << QGraphicsItem::ItemFlagsHaveChanged
7922              << QGraphicsItem::ItemTransformChange
7923              << QGraphicsItem::ItemTransformHasChanged
7924              << QGraphicsItem::ItemPositionChange
7925              << QGraphicsItem::ItemPositionHasChanged
7926              << QGraphicsItem::ItemRotationChange
7927              << QGraphicsItem::ItemRotationHasChanged
7928              << QGraphicsItem::ItemScaleChange
7929              << QGraphicsItem::ItemScaleHasChanged
7930              << QGraphicsItem::ItemTransformOriginPointChange
7931              << QGraphicsItem::ItemTransformOriginPointHasChanged);
7932 }
7933
7934 // Make sure we update moved items correctly.
7935 void tst_QGraphicsItem::moveItem()
7936 {
7937     QGraphicsScene scene;
7938     scene.setSceneRect(-50, -50, 200, 200);
7939
7940     MyGraphicsView view(&scene);
7941     view.show();
7942     QVERIFY(QTest::qWaitForWindowExposed(&view));
7943
7944     EventTester *parent = new EventTester;
7945     EventTester *child = new EventTester(parent);
7946     EventTester *grandChild = new EventTester(child);
7947
7948 #define RESET_COUNTERS \
7949     parent->repaints = 0; \
7950     child->repaints = 0; \
7951     grandChild->repaints = 0; \
7952     view.reset();
7953
7954     scene.addItem(parent);
7955     QTest::qWait(100);
7956
7957     RESET_COUNTERS
7958
7959     // Item's boundingRect:  (-10, -10, 20, 20).
7960     QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
7961                                      .mapRect(parent->boundingRect()).toAlignedRect()
7962                                      .adjusted(-2, -2, 2, 2); // Adjusted for antialiasing.
7963
7964     parent->setPos(20, 20);
7965     qApp->processEvents();
7966     QCOMPARE(parent->repaints, 1);
7967     QCOMPARE(view.repaints, 1);
7968     QRegion expectedParentRegion = parentDeviceBoundingRect; // old position
7969     parentDeviceBoundingRect.translate(20, 20);
7970     expectedParentRegion += parentDeviceBoundingRect; // new position
7971     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
7972
7973     RESET_COUNTERS
7974
7975     child->setPos(20, 20);
7976     qApp->processEvents();
7977     QCOMPARE(parent->repaints, 1);
7978     QCOMPARE(child->repaints, 1);
7979     QCOMPARE(view.repaints, 1);
7980     const QRegion expectedChildRegion = expectedParentRegion.translated(20, 20);
7981     COMPARE_REGIONS(view.paintedRegion, expectedChildRegion);
7982
7983     RESET_COUNTERS
7984
7985     grandChild->setPos(20, 20);
7986     qApp->processEvents();
7987     QCOMPARE(parent->repaints, 1);
7988     QCOMPARE(child->repaints, 1);
7989     QCOMPARE(grandChild->repaints, 1);
7990     QCOMPARE(view.repaints, 1);
7991     const QRegion expectedGrandChildRegion = expectedParentRegion.translated(40, 40);
7992     COMPARE_REGIONS(view.paintedRegion, expectedGrandChildRegion);
7993
7994     RESET_COUNTERS
7995
7996     parent->translate(20, 20);
7997     qApp->processEvents();
7998     QCOMPARE(parent->repaints, 1);
7999     QCOMPARE(child->repaints, 1);
8000     QCOMPARE(grandChild->repaints, 1);
8001     QCOMPARE(view.repaints, 1);
8002     expectedParentRegion.translate(20, 20);
8003     expectedParentRegion += expectedChildRegion.translated(20, 20);
8004     expectedParentRegion += expectedGrandChildRegion.translated(20, 20);
8005     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
8006 }
8007
8008 void tst_QGraphicsItem::moveLineItem()
8009 {
8010     QGraphicsScene scene;
8011     scene.setSceneRect(0, 0, 200, 200);
8012     QGraphicsLineItem *item = new QGraphicsLineItem(0, 0, 100, 0);
8013     item->setPos(50, 50);
8014     scene.addItem(item);
8015
8016     MyGraphicsView view(&scene);
8017     view.show();
8018     QVERIFY(QTest::qWaitForWindowActive(&view));
8019     view.reset();
8020
8021     QRectF brect = item->boundingRect();
8022     // Do same adjustments as in qgraphicsscene.cpp
8023     if (!brect.width())
8024         brect.adjust(qreal(-0.00001), 0, qreal(0.00001), 0);
8025     if (!brect.height())
8026         brect.adjust(0, qreal(-0.00001), 0, qreal(0.00001));
8027     const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
8028                                          .mapRect(brect).toAlignedRect();
8029     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // antialiasing
8030
8031     // Make sure the calculated region is correct.
8032     item->update();
8033     QTest::qWait(10);
8034     QTRY_COMPARE(view.paintedRegion, expectedRegion);
8035     view.reset();
8036
8037     // Old position: (50, 50)
8038     item->setPos(50, 100);
8039     expectedRegion += expectedRegion.translated(0, 50);
8040     QTest::qWait(10);
8041     QCOMPARE(view.paintedRegion, expectedRegion);
8042 }
8043
8044 void tst_QGraphicsItem::sorting_data()
8045 {
8046     QTest::addColumn<int>("index");
8047
8048     QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex);
8049     QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex);
8050 }
8051
8052 void tst_QGraphicsItem::sorting()
8053 {
8054     if (qGuiApp->styleHints()->showIsFullScreen())
8055         QSKIP("Skipped because Platform is auto maximizing");
8056
8057     _paintedItems.clear();
8058
8059     QGraphicsScene scene;
8060     QGraphicsItem *grid[100][100];
8061     for (int x = 0; x < 100; ++x) {
8062         for (int y = 0; y < 100; ++y) {
8063             PainterItem *item = new PainterItem;
8064             item->setPos(x * 25, y * 25);
8065             item->setData(0, QString("%1x%2").arg(x).arg(y));
8066             grid[x][y] = item;
8067             scene.addItem(item);
8068         }
8069     }
8070
8071     PainterItem *item1 = new PainterItem;
8072     PainterItem *item2 = new PainterItem;
8073     item1->setData(0, "item1");
8074     item2->setData(0, "item2");
8075     scene.addItem(item1);
8076     scene.addItem(item2);
8077
8078     QGraphicsView view(&scene);
8079     // Use Qt::Tool as fully decorated windows have a minimum width of 160 on Windows.
8080     view.setWindowFlags(view.windowFlags() | Qt::Tool);
8081     view.setResizeAnchor(QGraphicsView::NoAnchor);
8082     view.setTransformationAnchor(QGraphicsView::NoAnchor);
8083     view.resize(120, 100);
8084     view.setFrameStyle(0);
8085     view.show();
8086     qApp->setActiveWindow(&view);
8087     QVERIFY(QTest::qWaitForWindowActive(&view));
8088     QTest::qWait(100);
8089
8090     _paintedItems.clear();
8091
8092     view.viewport()->repaint();
8093 #if defined(Q_OS_MAC)
8094     // There's no difference between repaint and update on the Mac,
8095     // so we have to process events here to make sure we get the event.
8096     QTest::qWait(100);
8097 #endif
8098
8099     QCOMPARE(_paintedItems, QList<QGraphicsItem *>()
8100                  << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3]
8101                  << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3]
8102                  << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3]
8103                  << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3]
8104                  << grid[4][0] << grid[4][1] << grid[4][2] << grid[4][3]
8105                  << item1 << item2);
8106 }
8107
8108 void tst_QGraphicsItem::itemHasNoContents()
8109 {
8110     PainterItem *item1 = new PainterItem;
8111     PainterItem *item2 = new PainterItem;
8112     item2->setParentItem(item1);
8113     item2->setPos(50, 50);
8114     item1->setFlag(QGraphicsItem::ItemHasNoContents);
8115     item1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
8116
8117     QGraphicsScene scene;
8118     scene.addItem(item1);
8119
8120     QGraphicsView view(&scene);
8121     view.show();
8122     qApp->setActiveWindow(&view);
8123     QVERIFY(QTest::qWaitForWindowActive(&view));
8124     QTRY_VERIFY(!_paintedItems.isEmpty());
8125
8126     _paintedItems.clear();
8127
8128     view.viewport()->repaint();
8129 #ifdef Q_OS_MAC
8130     // There's no difference between update() and repaint() on the Mac,
8131     // so we have to process events here to make sure we get the event.
8132     QTest::qWait(10);
8133 #endif
8134
8135     QTRY_COMPARE(_paintedItems, QList<QGraphicsItem *>() << item2);
8136 }
8137
8138 void tst_QGraphicsItem::hitTestUntransformableItem()
8139 {
8140     QGraphicsScene scene;
8141     scene.setSceneRect(-100, -100, 200, 200);
8142
8143     QGraphicsView view(&scene);
8144     view.show();
8145     QVERIFY(QTest::qWaitForWindowExposed(&view));
8146
8147     // Confuse the BSP with dummy items.
8148     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8149     dummy->setPos(-100, -100);
8150     scene.addItem(dummy);
8151     for (int i = 0; i < 100; ++i) {
8152         QGraphicsItem *parent = dummy;
8153         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8154         dummy->setPos(-100 + i, -100 + i);
8155         dummy->setParentItem(parent);
8156     }
8157
8158     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
8159     item1->setPos(-200, -200);
8160
8161     QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 20, 20);
8162     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8163     item2->setParentItem(item1);
8164     item2->setPos(200, 200);
8165
8166     QGraphicsRectItem *item3 = new QGraphicsRectItem(0, 0, 20, 20);
8167     item3->setParentItem(item2);
8168     item3->setPos(80, 80);
8169
8170     scene.addItem(item1);
8171     QTest::qWait(100);
8172
8173     QList<QGraphicsItem *> items = scene.items(QPointF(80, 80));
8174     QCOMPARE(items.size(), 1);
8175     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8176
8177     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8178     QTest::qWait(100);
8179
8180     items = scene.items(QPointF(80, 80));
8181     QCOMPARE(items.size(), 1);
8182     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8183 }
8184
8185 void tst_QGraphicsItem::hitTestGraphicsEffectItem()
8186 {
8187     QGraphicsScene scene;
8188     scene.setSceneRect(-100, -100, 200, 200);
8189
8190     QWidget toplevel;
8191
8192     QGraphicsView view(&scene, &toplevel);
8193     toplevel.resize(300, 300);
8194     toplevel.show();
8195     QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
8196
8197     // Confuse the BSP with dummy items.
8198     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8199     dummy->setPos(-100, -100);
8200     scene.addItem(dummy);
8201     for (int i = 0; i < 100; ++i) {
8202         QGraphicsItem *parent = dummy;
8203         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8204         dummy->setPos(-100 + i, -100 + i);
8205         dummy->setParentItem(parent);
8206     }
8207
8208     const QRectF itemBoundingRect(0, 0, 20, 20);
8209     EventTester *item1 = new EventTester;
8210     item1->br = itemBoundingRect;
8211     item1->setPos(-200, -200);
8212     item1->brush = Qt::red;
8213
8214     EventTester *item2 = new EventTester;
8215     item2->br = itemBoundingRect;
8216     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8217     item2->setParentItem(item1);
8218     item2->setPos(200, 200);
8219     item2->brush = Qt::green;
8220
8221     EventTester *item3 = new EventTester;
8222     item3->br = itemBoundingRect;
8223     item3->setParentItem(item2);
8224     item3->setPos(80, 80);
8225     item3->brush = Qt::blue;
8226
8227     scene.addItem(item1);
8228     QTest::qWait(100);
8229
8230     item1->repaints = 0;
8231     item2->repaints = 0;
8232     item3->repaints = 0;
8233
8234     // Apply shadow effect to the entire sub-tree.
8235     QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
8236     shadow->setOffset(-20, -20);
8237     item1->setGraphicsEffect(shadow);
8238     QTest::qWait(50);
8239
8240     // Make sure all visible items are repainted.
8241     QCOMPARE(item1->repaints, 1);
8242     QCOMPARE(item2->repaints, 1);
8243     QCOMPARE(item3->repaints, 1);
8244
8245     // Make sure an item doesn't respond to a click on its shadow.
8246     QList<QGraphicsItem *> items = scene.items(QPointF(75, 75));
8247     QVERIFY(items.isEmpty());
8248     items = scene.items(QPointF(80, 80));
8249     QCOMPARE(items.size(), 1);
8250     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8251
8252     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8253     QTest::qWait(100);
8254
8255     items = scene.items(QPointF(75, 75));
8256     QVERIFY(items.isEmpty());
8257     items = scene.items(QPointF(80, 80));
8258     QCOMPARE(items.size(), 1);
8259     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8260 }
8261
8262 void tst_QGraphicsItem::focusProxy()
8263 {
8264     QGraphicsScene scene;
8265     QEvent activate(QEvent::WindowActivate);
8266     QApplication::sendEvent(&scene, &activate);
8267
8268     QGraphicsItem *item = scene.addRect(0, 0, 10, 10);
8269     item->setFlag(QGraphicsItem::ItemIsFocusable);
8270     QVERIFY(!item->focusProxy());
8271
8272     QGraphicsItem *item2 = scene.addRect(0, 0, 10, 10);
8273     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8274     item->setFocusProxy(item2);
8275     QCOMPARE(item->focusProxy(), item2);
8276
8277     item->setFocus();
8278     QVERIFY(item->hasFocus());
8279     QVERIFY(item2->hasFocus());
8280
8281     // Try to make a focus chain loop
8282     QString err;
8283     QTextStream stream(&err);
8284     stream << "QGraphicsItem::setFocusProxy: "
8285            << (void*)item << " is already in the focus proxy chain" << flush;
8286     QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
8287     item2->setFocusProxy(item); // fails
8288     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8289     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8290
8291     // Try to assign self as focus proxy
8292     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
8293     item->setFocusProxy(item); // fails
8294     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8295     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8296
8297     // Reset the focus proxy
8298     item->setFocusProxy(0);
8299     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8300     QVERIFY(!item->hasFocus());
8301     QVERIFY(item2->hasFocus());
8302
8303     // Test deletion
8304     item->setFocusProxy(item2);
8305     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8306     delete item2;
8307     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8308
8309     // Test event delivery
8310     item2 = scene.addRect(0, 0, 10, 10);
8311     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8312     item->setFocusProxy(item2);
8313     item->clearFocus();
8314
8315     EventSpy focusInSpy(&scene, item, QEvent::FocusIn);
8316     EventSpy focusOutSpy(&scene, item, QEvent::FocusOut);
8317     EventSpy focusInSpy2(&scene, item2, QEvent::FocusIn);
8318     EventSpy focusOutSpy2(&scene, item2, QEvent::FocusOut);
8319     QCOMPARE(focusInSpy.count(), 0);
8320     QCOMPARE(focusOutSpy.count(), 0);
8321     QCOMPARE(focusInSpy2.count(), 0);
8322     QCOMPARE(focusOutSpy2.count(), 0);
8323
8324     item->setFocus();
8325     QCOMPARE(focusInSpy.count(), 0);
8326     QCOMPARE(focusInSpy2.count(), 1);
8327     item->clearFocus();
8328     QCOMPARE(focusOutSpy.count(), 0);
8329     QCOMPARE(focusOutSpy2.count(), 1);
8330
8331     // Test two items proxying one item.
8332     QGraphicsItem *item3 = scene.addRect(0, 0, 10, 10);
8333     item3->setFlag(QGraphicsItem::ItemIsFocusable);
8334     item3->setFocusProxy(item2); // item and item3 use item2 as proxy
8335
8336     QCOMPARE(item->focusProxy(), item2);
8337     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8338     QCOMPARE(item3->focusProxy(), item2);
8339     delete item2;
8340     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8341     QCOMPARE(item3->focusProxy(), (QGraphicsItem *)0);
8342 }
8343
8344 void tst_QGraphicsItem::subFocus()
8345 {
8346     // Construct a text item that's not part of a scene (yet)
8347     // and has no parent. Setting focus on it will not make
8348     // the item gain input focus; that requires a scene. But
8349     // it does set subfocus, indicating that the item wishes
8350     // to gain focus later.
8351     QGraphicsTextItem *text = new QGraphicsTextItem("Hello");
8352     text->setTextInteractionFlags(Qt::TextEditorInteraction);
8353     QVERIFY(!text->hasFocus());
8354     text->setFocus();
8355     QVERIFY(!text->hasFocus());
8356     QCOMPARE(text->focusItem(), (QGraphicsItem *)text);
8357
8358     // Add a sibling.
8359     QGraphicsTextItem *text2 = new QGraphicsTextItem("Hi");
8360     text2->setTextInteractionFlags(Qt::TextEditorInteraction);
8361     text2->setPos(30, 30);
8362
8363     // Add both items to a scene and check that it's text that
8364     // got input focus.
8365     QGraphicsScene scene;
8366     QEvent activate(QEvent::WindowActivate);
8367     QApplication::sendEvent(&scene, &activate);
8368
8369     scene.addItem(text);
8370     scene.addItem(text2);
8371     QVERIFY(text->hasFocus());
8372
8373     text->setData(0, "text");
8374     text2->setData(0, "text2");
8375
8376     // Remove text2 and set subfocus on it. Then readd. Reparent it onto the
8377     // other item and see that it gains input focus.
8378     scene.removeItem(text2);
8379     text2->setFocus();
8380     scene.addItem(text2);
8381     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8382     text2->setParentItem(text);
8383     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8384     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8385     QVERIFY(!text->hasFocus());
8386     QVERIFY(text2->hasFocus());
8387
8388     // Remove both items from the scene, restore subfocus and
8389     // readd them. Now the subfocus should kick in and give
8390     // text2 focus.
8391     scene.removeItem(text);
8392     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8393     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8394     text2->setFocus();
8395     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8396     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8397     scene.addItem(text);
8398
8399     // Hiding and showing text should pass focus to text2.
8400     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8401     QVERIFY(text2->hasFocus());
8402
8403     // Subfocus should repropagate to root when reparenting.
8404     QGraphicsRectItem *rect = new QGraphicsRectItem;
8405     QGraphicsRectItem *rect2 = new QGraphicsRectItem(rect);
8406     QGraphicsRectItem *rect3 = new QGraphicsRectItem(rect2);
8407     rect3->setFlag(QGraphicsItem::ItemIsFocusable);
8408
8409     text->setData(0, "text");
8410     text2->setData(0, "text2");
8411     rect->setData(0, "rect");
8412     rect2->setData(0, "rect2");
8413     rect3->setData(0, "rect3");
8414
8415     rect3->setFocus();
8416     QVERIFY(!rect3->hasFocus());
8417     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8418     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8419     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8420     rect->setParentItem(text2);
8421     QCOMPARE(text->focusItem(), (QGraphicsItem *)rect3);
8422     QCOMPARE(text2->focusItem(), (QGraphicsItem *)rect3);
8423     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8424     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8425     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8426     QVERIFY(!rect->hasFocus());
8427     QVERIFY(!rect2->hasFocus());
8428     QVERIFY(rect3->hasFocus());
8429
8430     delete rect2;
8431     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8432     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8433     QCOMPARE(rect->focusItem(), (QGraphicsItem *)0);
8434 }
8435
8436 void tst_QGraphicsItem::focusProxyDeletion()
8437 {
8438     QGraphicsRectItem *rect = new QGraphicsRectItem;
8439     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8440     rect->setFocusProxy(rect2);
8441     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8442
8443     delete rect2;
8444     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8445
8446     rect2 = new QGraphicsRectItem;
8447     rect->setFocusProxy(rect2);
8448     delete rect; // don't crash
8449
8450     rect = new QGraphicsRectItem;
8451     rect->setFocusProxy(rect2);
8452     QGraphicsScene *scene = new QGraphicsScene;
8453     scene->addItem(rect);
8454     scene->addItem(rect2);
8455     delete rect2;
8456     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8457
8458     rect2 = new QGraphicsRectItem;
8459     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
8460     rect->setFocusProxy(rect2);
8461     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8462     scene->addItem(rect2);
8463     rect->setFocusProxy(rect2);
8464     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8465     delete rect; // don't crash
8466
8467     rect = new QGraphicsRectItem;
8468     rect2 = new QGraphicsRectItem;
8469     rect->setFocusProxy(rect2);
8470     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8471     scene->addItem(rect);
8472     scene->addItem(rect2);
8473     rect->setFocusProxy(rect2);
8474     delete scene; // don't crash
8475 }
8476
8477 void tst_QGraphicsItem::negativeZStacksBehindParent()
8478 {
8479     QGraphicsRectItem rect;
8480     QCOMPARE(rect.zValue(), qreal(0.0));
8481     QVERIFY(!(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent));
8482     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8483     rect.setZValue(-1);
8484     QCOMPARE(rect.zValue(), qreal(-1.0));
8485     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8486     rect.setZValue(0);
8487     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
8488     QVERIFY(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent);
8489     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8490     rect.setZValue(-1);
8491     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8492     rect.setZValue(0);
8493     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8494     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8495     rect.setZValue(-1);
8496     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, true);
8497     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8498     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8499     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8500 }
8501
8502 void tst_QGraphicsItem::setGraphicsEffect()
8503 {
8504     // Check that we don't have any effect by default.
8505     QGraphicsItem *item = new QGraphicsRectItem(0, 0, 10, 10);
8506     QVERIFY(!item->graphicsEffect());
8507
8508     // SetGet check.
8509     QPointer<QGraphicsEffect> blurEffect = new QGraphicsBlurEffect;
8510     item->setGraphicsEffect(blurEffect);
8511     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(blurEffect));
8512
8513     // Ensure the existing effect is deleted when setting a new one.
8514     QPointer<QGraphicsEffect> shadowEffect = new QGraphicsDropShadowEffect;
8515     item->setGraphicsEffect(shadowEffect);
8516     QVERIFY(!blurEffect);
8517     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(shadowEffect));
8518     blurEffect = new QGraphicsBlurEffect;
8519
8520     // Ensure the effect is uninstalled when setting it on a new target.
8521     QGraphicsItem *anotherItem = new QGraphicsRectItem(0, 0, 10, 10);
8522     anotherItem->setGraphicsEffect(blurEffect);
8523     item->setGraphicsEffect(blurEffect);
8524     QVERIFY(!anotherItem->graphicsEffect());
8525     QVERIFY(!shadowEffect);
8526
8527     // Ensure the existing effect is deleted when deleting the item.
8528     delete item;
8529     QVERIFY(!blurEffect);
8530     delete anotherItem;
8531
8532     // Ensure the effect is uninstalled when deleting it
8533     item = new QGraphicsRectItem(0, 0, 10, 10);
8534     blurEffect = new QGraphicsBlurEffect;
8535     item->setGraphicsEffect(blurEffect);
8536     delete blurEffect;
8537     QVERIFY(!item->graphicsEffect());
8538
8539     // Ensure the existing effect is uninstalled and deleted when setting a null effect
8540     blurEffect = new QGraphicsBlurEffect;
8541     item->setGraphicsEffect(blurEffect);
8542     item->setGraphicsEffect(0);
8543     QVERIFY(!item->graphicsEffect());
8544     QVERIFY(!blurEffect);
8545
8546     delete item;
8547 }
8548
8549 void tst_QGraphicsItem::panel()
8550 {
8551     QGraphicsScene scene;
8552
8553     QGraphicsRectItem *panel1 = new QGraphicsRectItem;
8554     QGraphicsRectItem *panel2 = new QGraphicsRectItem;
8555     QGraphicsRectItem *panel3 = new QGraphicsRectItem;
8556     QGraphicsRectItem *panel4 = new QGraphicsRectItem;
8557     QGraphicsRectItem *notPanel1 = new QGraphicsRectItem;
8558     QGraphicsRectItem *notPanel2 = new QGraphicsRectItem;
8559     panel1->setFlag(QGraphicsItem::ItemIsPanel);
8560     panel2->setFlag(QGraphicsItem::ItemIsPanel);
8561     panel3->setFlag(QGraphicsItem::ItemIsPanel);
8562     panel4->setFlag(QGraphicsItem::ItemIsPanel);
8563     scene.addItem(panel1);
8564     scene.addItem(panel2);
8565     scene.addItem(panel3);
8566     scene.addItem(panel4);
8567     scene.addItem(notPanel1);
8568     scene.addItem(notPanel2);
8569
8570     EventSpy spy_activate_panel1(&scene, panel1, QEvent::WindowActivate);
8571     EventSpy spy_deactivate_panel1(&scene, panel1, QEvent::WindowDeactivate);
8572     EventSpy spy_activate_panel2(&scene, panel2, QEvent::WindowActivate);
8573     EventSpy spy_deactivate_panel2(&scene, panel2, QEvent::WindowDeactivate);
8574     EventSpy spy_activate_panel3(&scene, panel3, QEvent::WindowActivate);
8575     EventSpy spy_deactivate_panel3(&scene, panel3, QEvent::WindowDeactivate);
8576     EventSpy spy_activate_panel4(&scene, panel4, QEvent::WindowActivate);
8577     EventSpy spy_deactivate_panel4(&scene, panel4, QEvent::WindowDeactivate);
8578     EventSpy spy_activate_notPanel1(&scene, notPanel1, QEvent::WindowActivate);
8579     EventSpy spy_deactivate_notPanel1(&scene, notPanel1, QEvent::WindowDeactivate);
8580     EventSpy spy_activate_notPanel2(&scene, notPanel1, QEvent::WindowActivate);
8581     EventSpy spy_deactivate_notPanel2(&scene, notPanel1, QEvent::WindowDeactivate);
8582
8583     QCOMPARE(spy_activate_panel1.count(), 0);
8584     QCOMPARE(spy_deactivate_panel1.count(), 0);
8585     QCOMPARE(spy_activate_panel2.count(), 0);
8586     QCOMPARE(spy_deactivate_panel2.count(), 0);
8587     QCOMPARE(spy_activate_panel3.count(), 0);
8588     QCOMPARE(spy_deactivate_panel3.count(), 0);
8589     QCOMPARE(spy_activate_panel4.count(), 0);
8590     QCOMPARE(spy_deactivate_panel4.count(), 0);
8591     QCOMPARE(spy_activate_notPanel1.count(), 0);
8592     QCOMPARE(spy_deactivate_notPanel1.count(), 0);
8593     QCOMPARE(spy_activate_notPanel2.count(), 0);
8594     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8595
8596     QVERIFY(!scene.activePanel());
8597     QVERIFY(!scene.isActive());
8598
8599     QEvent activate(QEvent::WindowActivate);
8600     QEvent deactivate(QEvent::WindowDeactivate);
8601
8602     QApplication::sendEvent(&scene, &activate);
8603
8604     // No previous activation, so the scene is active.
8605     QVERIFY(scene.isActive());
8606     QCOMPARE(scene.activePanel(), (QGraphicsItem *)panel1);
8607     QVERIFY(panel1->isActive());
8608     QVERIFY(!panel2->isActive());
8609     QVERIFY(!panel3->isActive());
8610     QVERIFY(!panel4->isActive());
8611     QVERIFY(!notPanel1->isActive());
8612     QVERIFY(!notPanel2->isActive());
8613     QCOMPARE(spy_deactivate_notPanel1.count(), 0);
8614     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8615     QCOMPARE(spy_activate_panel1.count(), 1);
8616     QCOMPARE(spy_activate_panel2.count(), 0);
8617     QCOMPARE(spy_activate_panel3.count(), 0);
8618     QCOMPARE(spy_activate_panel4.count(), 0);
8619
8620     // Switch back to scene.
8621     scene.setActivePanel(0);
8622     QVERIFY(!scene.activePanel());
8623     QVERIFY(!panel1->isActive());
8624     QVERIFY(!panel2->isActive());
8625     QVERIFY(!panel3->isActive());
8626     QVERIFY(!panel4->isActive());
8627     QVERIFY(notPanel1->isActive());
8628     QVERIFY(notPanel2->isActive());
8629     QCOMPARE(spy_activate_notPanel1.count(), 1);
8630     QCOMPARE(spy_activate_notPanel2.count(), 1);
8631
8632     // Deactivate the scene
8633     QApplication::sendEvent(&scene, &deactivate);
8634     QVERIFY(!scene.activePanel());
8635     QVERIFY(!panel1->isActive());
8636     QVERIFY(!panel2->isActive());
8637     QVERIFY(!panel3->isActive());
8638     QVERIFY(!panel4->isActive());
8639     QVERIFY(!notPanel1->isActive());
8640     QVERIFY(!notPanel2->isActive());
8641     QCOMPARE(spy_deactivate_notPanel1.count(), 1);
8642     QCOMPARE(spy_deactivate_notPanel2.count(), 1);
8643
8644     // Reactivate the scene
8645     QApplication::sendEvent(&scene, &activate);
8646     QVERIFY(!scene.activePanel());
8647     QVERIFY(!panel1->isActive());
8648     QVERIFY(!panel2->isActive());
8649     QVERIFY(!panel3->isActive());
8650     QVERIFY(!panel4->isActive());
8651     QVERIFY(notPanel1->isActive());
8652     QVERIFY(notPanel2->isActive());
8653     QCOMPARE(spy_activate_notPanel1.count(), 2);
8654     QCOMPARE(spy_activate_notPanel2.count(), 2);
8655
8656     // Switch to panel1
8657     scene.setActivePanel(panel1);
8658     QVERIFY(panel1->isActive());
8659     QCOMPARE(spy_deactivate_notPanel1.count(), 2);
8660     QCOMPARE(spy_deactivate_notPanel2.count(), 2);
8661     QCOMPARE(spy_activate_panel1.count(), 2);
8662
8663     // Deactivate the scene
8664     QApplication::sendEvent(&scene, &deactivate);
8665     QVERIFY(!panel1->isActive());
8666     QCOMPARE(spy_deactivate_panel1.count(), 2);
8667
8668     // Reactivate the scene
8669     QApplication::sendEvent(&scene, &activate);
8670     QVERIFY(panel1->isActive());
8671     QCOMPARE(spy_activate_panel1.count(), 3);
8672
8673     // Deactivate the scene
8674     QApplication::sendEvent(&scene, &deactivate);
8675     QVERIFY(!panel1->isActive());
8676     QVERIFY(!scene.activePanel());
8677     scene.setActivePanel(0);
8678
8679     // Reactivate the scene
8680     QApplication::sendEvent(&scene, &activate);
8681     QVERIFY(!panel1->isActive());
8682 }
8683
8684 void tst_QGraphicsItem::panelWithFocusItem()
8685 {
8686     QGraphicsScene scene;
8687     QEvent activate(QEvent::WindowActivate);
8688     QApplication::sendEvent(&scene, &activate);
8689
8690     QGraphicsRectItem *parentPanel = new QGraphicsRectItem;
8691     QGraphicsRectItem *parentPanelFocusItem = new QGraphicsRectItem(parentPanel);
8692     parentPanel->setFlag(QGraphicsItem::ItemIsPanel);
8693     parentPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8694     parentPanelFocusItem->setFocus();
8695     scene.addItem(parentPanel);
8696
8697     QVERIFY(parentPanel->isActive());
8698     QVERIFY(parentPanelFocusItem->hasFocus());
8699     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8700     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8701
8702     QGraphicsRectItem *childPanel = new QGraphicsRectItem;
8703     QGraphicsRectItem *childPanelFocusItem = new QGraphicsRectItem(childPanel);
8704     childPanel->setFlag(QGraphicsItem::ItemIsPanel);
8705     childPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8706     childPanelFocusItem->setFocus();
8707
8708     QVERIFY(!childPanelFocusItem->hasFocus());
8709     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8710     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8711
8712     childPanel->setParentItem(parentPanel);
8713
8714     QVERIFY(!parentPanel->isActive());
8715     QVERIFY(!parentPanelFocusItem->hasFocus());
8716     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8717     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8718
8719     QVERIFY(childPanel->isActive());
8720     QVERIFY(childPanelFocusItem->hasFocus());
8721     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8722     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8723
8724     childPanel->hide();
8725
8726     QVERIFY(parentPanel->isActive());
8727     QVERIFY(parentPanelFocusItem->hasFocus());
8728     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8729     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8730 }
8731
8732 void tst_QGraphicsItem::addPanelToActiveScene()
8733 {
8734     QGraphicsScene scene;
8735     QVERIFY(!scene.isActive());
8736
8737     QGraphicsRectItem *rect = new QGraphicsRectItem;
8738     scene.addItem(rect);
8739     QVERIFY(!rect->isActive());
8740     scene.removeItem(rect);
8741
8742     QEvent activate(QEvent::WindowActivate);
8743     QEvent deactivate(QEvent::WindowDeactivate);
8744
8745     QApplication::sendEvent(&scene, &activate);
8746     QVERIFY(scene.isActive());
8747     scene.addItem(rect);
8748     QVERIFY(rect->isActive());
8749     scene.removeItem(rect);
8750
8751     rect->setFlag(QGraphicsItem::ItemIsPanel);
8752     scene.addItem(rect);
8753     QVERIFY(rect->isActive());
8754     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8755
8756     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8757     scene.addItem(rect2);
8758     QVERIFY(rect->isActive());
8759     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8760 }
8761
8762 void tst_QGraphicsItem::activate()
8763 {
8764     QGraphicsScene scene;
8765     QGraphicsRectItem *rect = scene.addRect(-10, -10, 20, 20);
8766     QVERIFY(!rect->isActive());
8767
8768     QEvent activate(QEvent::WindowActivate);
8769     QEvent deactivate(QEvent::WindowDeactivate);
8770
8771     QApplication::sendEvent(&scene, &activate);
8772
8773     // Non-panel item (active when scene is active).
8774     QVERIFY(rect->isActive());
8775
8776     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8777     rect2->setFlag(QGraphicsItem::ItemIsPanel);
8778     QGraphicsRectItem *rect3 = new QGraphicsRectItem;
8779     rect3->setFlag(QGraphicsItem::ItemIsPanel);
8780
8781     // Test normal activation.
8782     QVERIFY(!rect2->isActive());
8783     scene.addItem(rect2);
8784     QVERIFY(rect2->isActive()); // first panel item is activated
8785     scene.addItem(rect3);
8786     QVERIFY(!rect3->isActive()); // second panel item is _not_ activated
8787     rect3->setActive(true);
8788     QVERIFY(rect3->isActive());
8789     scene.removeItem(rect3);
8790     QVERIFY(!rect3->isActive()); // no panel is active anymore
8791     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8792     scene.addItem(rect3);
8793     QVERIFY(rect3->isActive()); // second panel item is activated
8794
8795     // Test pending activation.
8796     scene.removeItem(rect3);
8797     rect2->setActive(true);
8798     QVERIFY(rect2->isActive()); // first panel item is activated
8799     rect3->setActive(true);
8800     QVERIFY(!rect3->isActive()); // not active (yet)
8801     scene.addItem(rect3);
8802     QVERIFY(rect3->isActive()); // now becomes active
8803
8804     // Test pending deactivation.
8805     scene.removeItem(rect3);
8806     rect3->setActive(false);
8807     scene.addItem(rect3);
8808     QVERIFY(!rect3->isActive()); // doesn't become active
8809
8810     // Child of panel activation.
8811     rect3->setActive(true);
8812     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
8813     rect4->setFlag(QGraphicsItem::ItemIsPanel);
8814     QGraphicsRectItem *rect5 = new QGraphicsRectItem(rect4);
8815     QGraphicsRectItem *rect6 = new QGraphicsRectItem(rect5);
8816     scene.addItem(rect4);
8817     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect3);
8818     scene.removeItem(rect4);
8819     rect6->setActive(true);
8820     scene.addItem(rect4);
8821     QVERIFY(rect4->isActive());
8822     QVERIFY(rect5->isActive());
8823     QVERIFY(rect6->isActive());
8824     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect4);
8825     scene.removeItem(rect4); // no active panel
8826     rect6->setActive(false);
8827     scene.addItem(rect4);
8828     QVERIFY(!rect4->isActive());
8829     QVERIFY(!rect5->isActive());
8830     QVERIFY(!rect6->isActive());
8831     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8832
8833     // Controlling auto-activation when the scene changes activation.
8834     rect4->setActive(true);
8835     QApplication::sendEvent(&scene, &deactivate);
8836     QVERIFY(!scene.isActive());
8837     QVERIFY(!rect4->isActive());
8838     rect4->setActive(false);
8839     QApplication::sendEvent(&scene, &activate);
8840     QVERIFY(scene.isActive());
8841     QVERIFY(!scene.activePanel());
8842     QVERIFY(!rect4->isActive());
8843 }
8844
8845 void tst_QGraphicsItem::setActivePanelOnInactiveScene()
8846 {
8847     QGraphicsScene scene;
8848     QGraphicsRectItem *item = scene.addRect(QRectF());
8849     QGraphicsRectItem *panel = scene.addRect(QRectF());
8850     panel->setFlag(QGraphicsItem::ItemIsPanel);
8851
8852     EventSpy itemActivateSpy(&scene, item, QEvent::WindowActivate);
8853     EventSpy itemDeactivateSpy(&scene, item, QEvent::WindowDeactivate);
8854     EventSpy panelActivateSpy(&scene, panel, QEvent::WindowActivate);
8855     EventSpy panelDeactivateSpy(&scene, panel, QEvent::WindowDeactivate);
8856     EventSpy sceneActivationChangeSpy(&scene, QEvent::ActivationChange);
8857
8858     scene.setActivePanel(panel);
8859     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8860     QCOMPARE(itemActivateSpy.count(), 0);
8861     QCOMPARE(itemDeactivateSpy.count(), 0);
8862     QCOMPARE(panelActivateSpy.count(), 0);
8863     QCOMPARE(panelDeactivateSpy.count(), 0);
8864     QCOMPARE(sceneActivationChangeSpy.count(), 0);
8865 }
8866
8867 void tst_QGraphicsItem::activationOnShowHide()
8868 {
8869     QGraphicsScene scene;
8870     QEvent activate(QEvent::WindowActivate);
8871     QApplication::sendEvent(&scene, &activate);
8872
8873     QGraphicsRectItem *rootPanel = scene.addRect(QRectF());
8874     rootPanel->setFlag(QGraphicsItem::ItemIsPanel);
8875     rootPanel->setActive(true);
8876
8877     QGraphicsRectItem *subPanel = new QGraphicsRectItem;
8878     subPanel->setFlag(QGraphicsItem::ItemIsPanel);
8879
8880     // Reparenting onto an active panel auto-activates the child panel.
8881     subPanel->setParentItem(rootPanel);
8882     QVERIFY(subPanel->isActive());
8883     QVERIFY(!rootPanel->isActive());
8884
8885     // Hiding an active child panel will reactivate the parent panel.
8886     subPanel->hide();
8887     QVERIFY(rootPanel->isActive());
8888
8889     // Showing a child panel will auto-activate it.
8890     subPanel->show();
8891     QVERIFY(subPanel->isActive());
8892     QVERIFY(!rootPanel->isActive());
8893
8894     // Adding an unrelated panel doesn't affect activation.
8895     QGraphicsRectItem *otherPanel = new QGraphicsRectItem;
8896     otherPanel->setFlag(QGraphicsItem::ItemIsPanel);
8897     scene.addItem(otherPanel);
8898     QVERIFY(subPanel->isActive());
8899
8900     // Showing an unrelated panel doesn't affect activation.
8901     otherPanel->hide();
8902     otherPanel->show();
8903     QVERIFY(subPanel->isActive());
8904
8905     // Add a non-panel item.
8906     QGraphicsRectItem *otherItem = new QGraphicsRectItem;
8907     scene.addItem(otherItem);
8908     otherItem->setActive(true);
8909     QVERIFY(otherItem->isActive());
8910
8911     // Reparent a panel onto an active non-panel item.
8912     subPanel->setParentItem(otherItem);
8913     QVERIFY(subPanel->isActive());
8914
8915     // Showing a child panel of a non-panel item will activate it.
8916     subPanel->hide();
8917     QVERIFY(!subPanel->isActive());
8918     QVERIFY(otherItem->isActive());
8919     subPanel->show();
8920     QVERIFY(subPanel->isActive());
8921
8922     // Hiding a toplevel active panel will pass activation back
8923     // to the non-panel items.
8924     rootPanel->setActive(true);
8925     rootPanel->hide();
8926     QVERIFY(!rootPanel->isActive());
8927     QVERIFY(otherItem->isActive());
8928 }
8929
8930 class MoveWhileDying : public QGraphicsRectItem
8931 {
8932 public:
8933     MoveWhileDying(QGraphicsItem *parent = 0)
8934         : QGraphicsRectItem(parent)
8935     { }
8936     ~MoveWhileDying()
8937     {
8938         foreach (QGraphicsItem *c, childItems()) {
8939             foreach (QGraphicsItem *cc, c->childItems()) {
8940                 cc->moveBy(10, 10);
8941             }
8942             c->moveBy(10, 10);
8943         }
8944         if (QGraphicsItem *p = parentItem()) { p->moveBy(10, 10); }
8945     }
8946 };
8947
8948 void tst_QGraphicsItem::moveWhileDeleting()
8949 {
8950     QGraphicsScene scene;
8951     QGraphicsRectItem *rect = new QGraphicsRectItem;
8952     MoveWhileDying *silly = new MoveWhileDying(rect);
8953     QGraphicsRectItem *child = new QGraphicsRectItem(silly);
8954     scene.addItem(rect);
8955     delete rect; // don't crash!
8956
8957     rect = new QGraphicsRectItem;
8958     silly = new MoveWhileDying(rect);
8959     child = new QGraphicsRectItem(silly);
8960
8961     QGraphicsView view(&scene);
8962     view.show();
8963     QVERIFY(QTest::qWaitForWindowExposed(&view));
8964
8965     delete rect;
8966
8967     rect = new QGraphicsRectItem;
8968     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
8969     silly = new MoveWhileDying(rect);
8970     child = new QGraphicsRectItem(silly);
8971
8972     QTest::qWait(125);
8973
8974     delete rect;
8975
8976     rect = new MoveWhileDying;
8977     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
8978     child = new QGraphicsRectItem(rect);
8979     silly = new MoveWhileDying(child);
8980
8981     QTest::qWait(125);
8982
8983     delete rect;
8984 }
8985
8986 class MyRectItem : public QGraphicsWidget
8987 {
8988     Q_OBJECT
8989 public:
8990     MyRectItem(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
8991     {
8992
8993     }
8994
8995     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
8996     {
8997         painter->setBrush(brush);
8998         painter->drawRect(boundingRect());
8999     }
9000     void move()
9001     {
9002         setPos(-100,-100);
9003         topLevel->collidingItems(Qt::IntersectsItemBoundingRect);
9004     }
9005 public:
9006     QGraphicsItem *topLevel;
9007     QBrush brush;
9008 };
9009
9010
9011 void tst_QGraphicsItem::ensureDirtySceneTransform()
9012 {
9013     QGraphicsScene scene;
9014
9015     MyRectItem *topLevel = new MyRectItem;
9016     topLevel->setGeometry(0, 0, 100, 100);
9017     topLevel->setPos(-50, -50);
9018     topLevel->brush = QBrush(QColor(Qt::black));
9019     scene.addItem(topLevel);
9020
9021     MyRectItem *parent = new MyRectItem;
9022     parent->topLevel = topLevel;
9023     parent->setGeometry(0, 0, 100, 100);
9024     parent->setPos(0, 0);
9025     parent->brush = QBrush(QColor(Qt::magenta));
9026     parent->setObjectName("parent");
9027     scene.addItem(parent);
9028
9029     MyRectItem *child = new MyRectItem(parent);
9030     child->setGeometry(0, 0, 80, 80);
9031     child->setPos(10, 10);
9032     child->setObjectName("child");
9033     child->brush = QBrush(QColor(Qt::blue));
9034
9035     MyRectItem *child2 = new MyRectItem(parent);
9036     child2->setGeometry(0, 0, 80, 80);
9037     child2->setPos(15, 15);
9038     child2->setObjectName("child2");
9039     child2->brush = QBrush(QColor(Qt::green));
9040
9041     MyRectItem *child3 = new MyRectItem(parent);
9042     child3->setGeometry(0, 0, 80, 80);
9043     child3->setPos(20, 20);
9044     child3->setObjectName("child3");
9045     child3->brush = QBrush(QColor(Qt::gray));
9046
9047     QGraphicsView view(&scene);
9048     view.show();
9049     QApplication::setActiveWindow(&view);
9050     QVERIFY(QTest::qWaitForWindowActive(&view));
9051     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
9052
9053     //We move the parent
9054     parent->move();
9055     QApplication::processEvents();
9056
9057     //We check if all items moved
9058     QCOMPARE(child->pos(), QPointF(10, 10));
9059     QCOMPARE(child2->pos(), QPointF(15, 15));
9060     QCOMPARE(child3->pos(), QPointF(20, 20));
9061
9062     QCOMPARE(child->sceneBoundingRect(), QRectF(-90, -90, 80, 80));
9063     QCOMPARE(child2->sceneBoundingRect(), QRectF(-85, -85, 80, 80));
9064     QCOMPARE(child3->sceneBoundingRect(), QRectF(-80, -80, 80, 80));
9065
9066     QCOMPARE(child->sceneTransform(), QTransform::fromTranslate(-90, -90));
9067     QCOMPARE(child2->sceneTransform(), QTransform::fromTranslate(-85, -85));
9068     QCOMPARE(child3->sceneTransform(), QTransform::fromTranslate(-80, -80));
9069 }
9070
9071 void tst_QGraphicsItem::focusScope()
9072 {
9073     // ItemIsFocusScope is an internal feature (for now).
9074     QGraphicsScene scene;
9075
9076     QGraphicsRectItem *scope3 = new QGraphicsRectItem;
9077     scope3->setData(0, "scope3");
9078     scope3->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9079     scope3->setFocus();
9080     QVERIFY(!scope3->focusScopeItem());
9081     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9082
9083     QGraphicsRectItem *scope2 = new QGraphicsRectItem;
9084     scope2->setData(0, "scope2");
9085     scope2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9086     scope2->setFocus();
9087     QVERIFY(!scope2->focusScopeItem());
9088     scope3->setParentItem(scope2);
9089     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9090     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9091
9092     QGraphicsRectItem *scope1 = new QGraphicsRectItem;
9093     scope1->setData(0, "scope1");
9094     scope1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9095     scope1->setFocus();
9096     QVERIFY(!scope1->focusScopeItem());
9097     scope2->setParentItem(scope1);
9098
9099     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9100     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9101     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9102     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9103     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9104     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9105
9106     scene.addItem(scope1);
9107
9108     QEvent windowActivate(QEvent::WindowActivate);
9109     qApp->sendEvent(&scene, &windowActivate);
9110     scene.setFocus();
9111
9112     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9113     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9114     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9115     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9116     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9117     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9118
9119     QVERIFY(scope3->hasFocus());
9120
9121     scope3->hide();
9122     QVERIFY(scope2->hasFocus());
9123     scope2->hide();
9124     QVERIFY(scope1->hasFocus());
9125     scope2->show();
9126     QVERIFY(scope2->hasFocus());
9127     scope3->show();
9128     QVERIFY(scope3->hasFocus());
9129     scope1->hide();
9130     QVERIFY(!scope3->hasFocus());
9131     scope1->show();
9132     QVERIFY(scope3->hasFocus());
9133     scope3->clearFocus();
9134     QVERIFY(scope2->hasFocus());
9135     scope2->clearFocus();
9136     QVERIFY(scope1->hasFocus());
9137     scope2->hide();
9138     scope2->show();
9139     QVERIFY(!scope2->hasFocus());
9140     QVERIFY(scope1->hasFocus());
9141     scope2->setFocus();
9142     QVERIFY(scope2->hasFocus());
9143     scope3->setFocus();
9144     QVERIFY(scope3->hasFocus());
9145
9146     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
9147     rect4->setData(0, "rect4");
9148     rect4->setParentItem(scope3);
9149
9150     QGraphicsRectItem *rect5 = new QGraphicsRectItem;
9151     rect5->setData(0, "rect5");
9152     rect5->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9153     rect5->setFocus();
9154     rect5->setParentItem(rect4);
9155     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)rect5);
9156     QVERIFY(rect5->hasFocus());
9157
9158     rect4->setParentItem(0);
9159     QVERIFY(rect5->hasFocus());
9160     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9161     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)0);
9162     QVERIFY(!scope3->hasFocus());
9163
9164     QGraphicsRectItem *rectA = new QGraphicsRectItem;
9165     QGraphicsRectItem *scopeA = new QGraphicsRectItem(rectA);
9166     scopeA->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9167     scopeA->setFocus();
9168     QGraphicsRectItem *scopeB = new QGraphicsRectItem(scopeA);
9169     scopeB->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9170     scopeB->setFocus();
9171
9172     scene.addItem(rectA);
9173     QVERIFY(rect5->hasFocus());
9174     QVERIFY(!scopeB->hasFocus());
9175
9176     scopeA->setFocus();
9177     QVERIFY(scopeB->hasFocus());
9178     QCOMPARE(scopeB->focusItem(), (QGraphicsItem *)scopeB);
9179 }
9180
9181 void tst_QGraphicsItem::focusScope2()
9182 {
9183     QGraphicsRectItem *child1 = new QGraphicsRectItem;
9184     child1->setFlags(QGraphicsItem::ItemIsFocusable);
9185     child1->setFocus();
9186     QCOMPARE(child1->focusItem(), (QGraphicsItem *)child1);
9187
9188     QGraphicsRectItem *child2 = new QGraphicsRectItem;
9189     child2->setFlags(QGraphicsItem::ItemIsFocusable);
9190
9191     QGraphicsRectItem *rootFocusScope = new QGraphicsRectItem;
9192     rootFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9193     rootFocusScope->setFocus();
9194     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)rootFocusScope);
9195
9196     child1->setParentItem(rootFocusScope);
9197     child2->setParentItem(rootFocusScope);
9198
9199     QCOMPARE(rootFocusScope->focusScopeItem(), (QGraphicsItem *)child1);
9200     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)child1);
9201
9202     QGraphicsRectItem *siblingChild1 = new QGraphicsRectItem;
9203     siblingChild1->setFlags(QGraphicsItem::ItemIsFocusable);
9204     siblingChild1->setFocus();
9205
9206     QGraphicsRectItem *siblingChild2 = new QGraphicsRectItem;
9207     siblingChild2->setFlags(QGraphicsItem::ItemIsFocusable);
9208
9209     QGraphicsRectItem *siblingFocusScope = new QGraphicsRectItem;
9210     siblingFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9211
9212     siblingChild1->setParentItem(siblingFocusScope);
9213     siblingChild2->setParentItem(siblingFocusScope);
9214
9215     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild1);
9216     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9217
9218     QGraphicsItem *root = new QGraphicsRectItem;
9219     rootFocusScope->setParentItem(root);
9220     siblingFocusScope->setParentItem(root);
9221
9222     QCOMPARE(root->focusItem(), (QGraphicsItem *)child1);
9223
9224     QGraphicsScene scene;
9225     scene.addItem(root);
9226
9227     QEvent activate(QEvent::WindowActivate);
9228     qApp->sendEvent(&scene, &activate);
9229     scene.setFocus();
9230
9231     QCOMPARE(scene.focusItem(), (QGraphicsItem *)child1);
9232
9233     // You cannot set focus on a descendant of a focus scope directly;
9234     // this will only change the scope's focus scope item pointer. If
9235     // you want to give true input focus, you must set it directly on
9236     // the scope itself
9237     siblingChild2->setFocus();
9238     QVERIFY(!siblingChild2->hasFocus());
9239     QVERIFY(!siblingChild2->focusItem());
9240     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9241     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9242
9243     // Set focus on the scope; focus is forwarded to the focus scope item.
9244     siblingFocusScope->setFocus();
9245     QVERIFY(siblingChild2->hasFocus());
9246     QVERIFY(siblingChild2->focusItem());
9247     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9248     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)siblingChild2);
9249 }
9250
9251 void tst_QGraphicsItem::stackBefore()
9252 {
9253     QGraphicsRectItem parent;
9254     QGraphicsRectItem *child1 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9255     QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9256     QGraphicsRectItem *child3 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9257     QGraphicsRectItem *child4 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9258     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9259     child1->setData(0, "child1");
9260     child2->setData(0, "child2");
9261     child3->setData(0, "child3");
9262     child4->setData(0, "child4");
9263
9264     // Remove and append
9265     child2->setParentItem(0);
9266     child2->setParentItem(&parent);
9267     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9268
9269     // Move child2 before child1
9270     child2->stackBefore(child1); // 2134
9271     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9272     child2->stackBefore(child2); // 2134
9273     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9274     child1->setZValue(1); // 2341
9275     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9276     child1->stackBefore(child2); // 2341
9277     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9278     child1->setZValue(0); // 1234
9279     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9280     child4->stackBefore(child1); // 4123
9281     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9282     child4->setZValue(1); // 1234 (4123)
9283     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9284     child3->stackBefore(child1); // 3124 (4312)
9285     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9286     child4->setZValue(0); // 4312
9287     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9288
9289     // Make them all toplevels
9290     child1->setParentItem(0);
9291     child2->setParentItem(0);
9292     child3->setParentItem(0);
9293     child4->setParentItem(0);
9294
9295     QGraphicsScene scene;
9296     scene.addItem(child1);
9297     scene.addItem(child2);
9298     scene.addItem(child3);
9299     scene.addItem(child4);
9300     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder),
9301              (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9302
9303     // Remove and append
9304     scene.removeItem(child2);
9305     scene.addItem(child2);
9306     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9307
9308     // Move child2 before child1
9309     child2->stackBefore(child1); // 2134
9310     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9311     child2->stackBefore(child2); // 2134
9312     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9313     child1->setZValue(1); // 2341
9314     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9315     child1->stackBefore(child2); // 2341
9316     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9317     child1->setZValue(0); // 1234
9318     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9319     child4->stackBefore(child1); // 4123
9320     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9321     child4->setZValue(1); // 1234 (4123)
9322     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9323     child3->stackBefore(child1); // 3124 (4312)
9324     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9325     child4->setZValue(0); // 4312
9326     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9327 }
9328
9329 void tst_QGraphicsItem::QTBUG_4233_updateCachedWithSceneRect()
9330 {
9331     EventTester *tester = new EventTester;
9332     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
9333
9334     QGraphicsScene scene;
9335     scene.addItem(tester);
9336     scene.setSceneRect(-100, -100, 200, 200); // contains the tester item
9337
9338     QGraphicsView view(&scene);
9339     view.show();
9340     QApplication::setActiveWindow(&view);
9341     QVERIFY(QTest::qWaitForWindowActive(&view));
9342     QCOMPARE(QApplication::activeWindow(), (QWidget *)&view);
9343
9344     QTRY_COMPARE(tester->repaints, 1);
9345
9346     scene.update(); // triggers "updateAll" optimization
9347     qApp->processEvents();
9348     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9349
9350     QCOMPARE(tester->repaints, 1);
9351
9352     scene.update(); // triggers "updateAll" optimization
9353     tester->update();
9354     qApp->processEvents();
9355     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9356
9357     QCOMPARE(tester->repaints, 2);
9358 }
9359
9360 void tst_QGraphicsItem::sceneModality()
9361 {
9362     // 1) Test mouse events (delivery/propagation/redirection)
9363     // 2) Test hover events (incl. leave on block, enter on unblock)
9364     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9365     // 4) Test clickfocus
9366     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9367     // 6) ### modality for non-panels is unsupported for now
9368     QGraphicsScene scene;
9369
9370     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9371     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9372     bottomItem->setBrush(Qt::yellow);
9373
9374     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9375     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9376     leftParent->setBrush(Qt::blue);
9377
9378     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9379     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9380     leftChild->setBrush(Qt::green);
9381     leftChild->setParentItem(leftParent);
9382
9383     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9384     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9385     rightParent->setBrush(Qt::red);
9386     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9387     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9388     rightChild->setBrush(Qt::gray);
9389     rightChild->setParentItem(rightParent);
9390
9391     leftParent->setPos(-75, 0);
9392     rightParent->setPos(75, 0);
9393
9394     bottomItem->setData(0, "bottomItem");
9395     leftParent->setData(0, "leftParent");
9396     leftChild->setData(0, "leftChild");
9397     rightParent->setData(0, "rightParent");
9398     rightChild->setData(0, "rightChild");
9399
9400     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9401
9402     EventSpy2 leftParentSpy(&scene, leftParent);
9403     EventSpy2 leftChildSpy(&scene, leftChild);
9404     EventSpy2 rightParentSpy(&scene, rightParent);
9405     EventSpy2 rightChildSpy(&scene, rightChild);
9406     EventSpy2 bottomItemSpy(&scene, bottomItem);
9407
9408     // Scene modality, also test multiple scene modal items
9409     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9410     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9411     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9412     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9413     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9414     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // not a panel
9415
9416     // Click inside left child
9417     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9418     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9419     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9420     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9421     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9422     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9423     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9424
9425     // Click on left parent, event goes to modal child
9426     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9427     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9428     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9429     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9430     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9431     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9432     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9433
9434     // Click on all other items and outside the items
9435     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9436     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9437     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9438     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9439     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9440     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9441     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9442     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9443     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9444     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9445     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9446     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9447     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9448
9449     leftChildSpy.counts.clear();
9450     rightChildSpy.counts.clear();
9451     leftParentSpy.counts.clear();
9452     rightParentSpy.counts.clear();
9453     bottomItemSpy.counts.clear();
9454
9455     leftChild->setPanelModality(QGraphicsItem::NonModal);
9456     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9457     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9458     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9459     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 1);
9460     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9461
9462     // Left parent enters scene modality.
9463     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9464     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9465     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9466     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9467     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9468     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9469
9470     // Click inside left child.
9471     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9472     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9473     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9474     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // panel stops propagation
9475     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9476     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9477     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9478
9479    // Click on left parent.
9480     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9481     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9482     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9483     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9484     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9485     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9486     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9487
9488     // Click on all other items and outside the items
9489     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9490     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9491     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9492     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9493     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9494     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9495     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9496     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9497     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9498     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9499     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9500     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9501     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9502
9503     leftChildSpy.counts.clear();
9504     rightChildSpy.counts.clear();
9505     leftParentSpy.counts.clear();
9506     rightParentSpy.counts.clear();
9507     bottomItemSpy.counts.clear();
9508
9509     // Now both left parent and child are scene modal. Left parent is blocked.
9510     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9511     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9512     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9513     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9514     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9515     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9516
9517     // Click inside left child
9518     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9519     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9520     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9521     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9522     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9523     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9524     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9525
9526     // Click on left parent, event goes to modal child
9527     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9528     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9529     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9530     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9531     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9532     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9533     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9534
9535     // Click on all other items and outside the items
9536     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9537     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9538     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9539     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9540     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9541     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9542     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9543     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9544     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9545     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9546     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9547     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9548     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9549
9550     leftChildSpy.counts.clear();
9551     rightChildSpy.counts.clear();
9552     leftParentSpy.counts.clear();
9553     rightParentSpy.counts.clear();
9554     bottomItemSpy.counts.clear();
9555
9556     // Right child enters scene modality, only left child is blocked.
9557     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9558     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9559     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9560     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9561     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9562     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9563 }
9564
9565 void tst_QGraphicsItem::panelModality()
9566 {
9567     // 1) Test mouse events (delivery/propagation/redirection)
9568     // 2) Test hover events (incl. leave on block, enter on unblock)
9569     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9570     // 4) Test clickfocus
9571     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9572     // 6) ### modality for non-panels is unsupported for now
9573     QGraphicsScene scene;
9574
9575     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9576     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9577     bottomItem->setBrush(Qt::yellow);
9578
9579     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9580     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9581     leftParent->setBrush(Qt::blue);
9582
9583     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9584     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9585     leftChild->setBrush(Qt::green);
9586     leftChild->setParentItem(leftParent);
9587
9588     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9589     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9590     rightParent->setBrush(Qt::red);
9591     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9592     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9593     rightChild->setBrush(Qt::gray);
9594     rightChild->setParentItem(rightParent);
9595
9596     leftParent->setPos(-75, 0);
9597     rightParent->setPos(75, 0);
9598
9599     bottomItem->setData(0, "bottomItem");
9600     leftParent->setData(0, "leftParent");
9601     leftChild->setData(0, "leftChild");
9602     rightParent->setData(0, "rightParent");
9603     rightChild->setData(0, "rightChild");
9604
9605     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9606
9607     EventSpy2 leftParentSpy(&scene, leftParent);
9608     EventSpy2 leftChildSpy(&scene, leftChild);
9609     EventSpy2 rightParentSpy(&scene, rightParent);
9610     EventSpy2 rightChildSpy(&scene, rightChild);
9611     EventSpy2 bottomItemSpy(&scene, bottomItem);
9612
9613     // Left Child enters panel modality, only left parent is blocked.
9614     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9615     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9616     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9617     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9618     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9619     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9620
9621     leftChild->setPanelModality(QGraphicsItem::NonModal);
9622     leftChildSpy.counts.clear();
9623     rightChildSpy.counts.clear();
9624     leftParentSpy.counts.clear();
9625     rightParentSpy.counts.clear();
9626     bottomItemSpy.counts.clear();
9627
9628     // Left parent enter panel modality, nothing is blocked.
9629     leftParent->setPanelModality(QGraphicsItem::PanelModal);
9630     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9631     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9632     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9633     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9634     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9635
9636     // Left child enters panel modality, left parent is blocked again.
9637     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9638     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9639     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9640     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9641     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9642     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9643
9644     leftChildSpy.counts.clear();
9645     rightChildSpy.counts.clear();
9646     leftParentSpy.counts.clear();
9647     rightParentSpy.counts.clear();
9648     bottomItemSpy.counts.clear();
9649
9650     leftChild->setPanelModality(QGraphicsItem::NonModal);
9651     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9652     leftParent->setPanelModality(QGraphicsItem::NonModal);
9653     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9654     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9655     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9656     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9657     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9658
9659     leftChildSpy.counts.clear();
9660     rightChildSpy.counts.clear();
9661     leftParentSpy.counts.clear();
9662     rightParentSpy.counts.clear();
9663     bottomItemSpy.counts.clear();
9664
9665     // Left and right child enter panel modality, both parents are blocked.
9666     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9667     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9668     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9669     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9670     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9671     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9672 }
9673
9674 void tst_QGraphicsItem::mixedModality()
9675 {
9676     // 1) Test mouse events (delivery/propagation/redirection)
9677     // 2) Test hover events (incl. leave on block, enter on unblock)
9678     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9679     // 4) Test clickfocus
9680     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9681     // 6) ### modality for non-panels is unsupported for now
9682     QGraphicsScene scene;
9683
9684     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9685     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9686     bottomItem->setBrush(Qt::yellow);
9687
9688     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9689     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9690     leftParent->setBrush(Qt::blue);
9691
9692     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9693     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9694     leftChild->setBrush(Qt::green);
9695     leftChild->setParentItem(leftParent);
9696
9697     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9698     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9699     rightParent->setBrush(Qt::red);
9700     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9701     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9702     rightChild->setBrush(Qt::gray);
9703     rightChild->setParentItem(rightParent);
9704
9705     leftParent->setPos(-75, 0);
9706     rightParent->setPos(75, 0);
9707
9708     bottomItem->setData(0, "bottomItem");
9709     leftParent->setData(0, "leftParent");
9710     leftChild->setData(0, "leftChild");
9711     rightParent->setData(0, "rightParent");
9712     rightChild->setData(0, "rightChild");
9713
9714     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9715
9716     EventSpy2 leftParentSpy(&scene, leftParent);
9717     EventSpy2 leftChildSpy(&scene, leftChild);
9718     EventSpy2 rightParentSpy(&scene, rightParent);
9719     EventSpy2 rightChildSpy(&scene, rightChild);
9720     EventSpy2 bottomItemSpy(&scene, bottomItem);
9721
9722     // Left Child enters panel modality, only left parent is blocked.
9723     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9724     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9725     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9726     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9727     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9728
9729     // Left parent enters scene modality, which blocks everything except the child.
9730     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9731     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9732     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9733     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9734     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9735     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9736     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9737     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9738     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9739
9740     // Right child enters panel modality (changes nothing).
9741     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9742     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9743     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9744     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9745     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9746     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9747     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9748     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9749     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9750
9751     // Left parent leaves modality. Right child is unblocked.
9752     leftParent->setPanelModality(QGraphicsItem::NonModal);
9753     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9754     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9755     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9756     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9757     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9758     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9759     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9760     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9761
9762     // Right child "upgrades" its modality to scene modal. Left child is blocked.
9763     // Right parent is unaffected.
9764     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9765     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9766     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9767     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9768     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9769     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9770     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9771     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9772     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9773
9774     // "downgrade" right child back to panel modal, left child is unblocked
9775     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9776     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9777     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 1);
9778     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9779     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9780     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9781     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9782     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9783     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9784 }
9785
9786 void tst_QGraphicsItem::modality_hover()
9787 {
9788     QGraphicsScene scene;
9789     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9790     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9791     rect1->setAcceptHoverEvents(true);
9792     rect1->setData(0, "rect1");
9793
9794     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9795     rect2->setParentItem(rect1);
9796     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9797     rect2->setAcceptHoverEvents(true);
9798     rect2->setPos(50, 50);
9799     rect2->setPanelModality(QGraphicsItem::SceneModal);
9800     rect2->setData(0, "rect2");
9801
9802     EventSpy2 rect1Spy(&scene, rect1);
9803     EventSpy2 rect2Spy(&scene, rect2);
9804
9805     sendMouseMove(&scene, QPointF(-25, -25));
9806
9807     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9808     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9809     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9810
9811     sendMouseMove(&scene, QPointF(75, 75));
9812
9813     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9814     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9815     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9816     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9817     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9818     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9819
9820     sendMouseMove(&scene, QPointF(-25, -25));
9821
9822     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9823     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9824     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9825     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9826
9827     rect2->setPanelModality(QGraphicsItem::NonModal);
9828
9829     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9830     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9831
9832     sendMouseMove(&scene, QPointF(75, 75));
9833
9834     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9835     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9836
9837     rect2->setPanelModality(QGraphicsItem::SceneModal);
9838
9839     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9840     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9841     // changing modality causes a spurious GraphicsSceneHoveMove, even though the mouse didn't
9842     // actually move
9843     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9844
9845     sendMouseMove(&scene, QPointF(-25, -25));
9846
9847     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9848     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9849     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9850     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9851
9852     rect2->setPanelModality(QGraphicsItem::PanelModal);
9853
9854     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9855     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9856     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9857     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9858     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9859     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9860
9861     rect2->setPanelModality(QGraphicsItem::NonModal);
9862
9863     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9864     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9865     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9866     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9867     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9868 }
9869
9870 void tst_QGraphicsItem::modality_mouseGrabber()
9871 {
9872     QGraphicsScene scene;
9873     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9874     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9875     rect1->setFlag(QGraphicsItem::ItemIsMovable);
9876     rect1->setData(0, "rect1");
9877
9878     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9879     rect2->setParentItem(rect1);
9880     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9881     rect2->setFlag(QGraphicsItem::ItemIsMovable);
9882     rect2->setPos(50, 50);
9883     rect2->setData(0, "rect2");
9884
9885     EventSpy2 rect1Spy(&scene, rect1);
9886     EventSpy2 rect2Spy(&scene, rect2);
9887
9888     {
9889         // pressing mouse on rect1 starts implicit grab
9890         sendMousePress(&scene, QPoint(-25, -25));
9891         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9892         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9893         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
9894         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9895         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9896         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9897
9898         // grab lost when rect1 is modally shadowed
9899         rect2->setPanelModality(QGraphicsItem::SceneModal);
9900         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9901         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9902         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9903         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9904         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9905
9906         // releasing goes nowhere
9907         sendMouseRelease(&scene, QPoint(-25, -25));
9908         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9909         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9910         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9911         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9912         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9913         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9914         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9915
9916         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
9917         sendMouseClick(&scene, QPoint(-25, -25));
9918         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9919         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9920         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9921         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9922         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9923         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9924         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
9925         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9926
9927         rect2->setPanelModality(QGraphicsItem::NonModal);
9928
9929         // pressing mouse on rect1 starts implicit grab
9930         sendMousePress(&scene, QPoint(-25, -25));
9931         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9932         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
9933         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9934         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9935         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9936         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9937
9938         // grab lost to rect2 when rect1 is modally shadowed
9939         rect2->setPanelModality(QGraphicsItem::SceneModal);
9940         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9941         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9942         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9943         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9944         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9945
9946         // rect1 does *not* re-grab when rect2 is no longer modal
9947         rect2->setPanelModality(QGraphicsItem::NonModal);
9948         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9949         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9950         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9951         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9952         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9953
9954         // release goes nowhere
9955         sendMouseRelease(&scene, QPoint(-25, -25));
9956         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9957         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9958         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9959         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9960         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9961         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9962     }
9963     {
9964         // repeat the test using PanelModal
9965         rect2->setPanelModality(QGraphicsItem::NonModal);
9966         rect1Spy.counts.clear();
9967         rect2Spy.counts.clear();
9968
9969         // pressing mouse on rect1 starts implicit grab
9970         sendMousePress(&scene, QPoint(-25, -25));
9971         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9972         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9973         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
9974         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9975         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9976         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9977
9978         // grab lost when rect1 is modally shadowed
9979         rect2->setPanelModality(QGraphicsItem::PanelModal);
9980         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9981         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9982         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9983         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9984         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9985
9986         // releasing goes nowhere
9987         sendMouseRelease(&scene, QPoint(-25, -25));
9988         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9989         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9990         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9991         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9992         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9993         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9994         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9995
9996         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
9997         sendMouseClick(&scene, QPoint(-25, -25));
9998         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9999         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10000         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10001         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10002         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10003         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10004         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10005         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10006
10007         rect2->setPanelModality(QGraphicsItem::NonModal);
10008
10009         // pressing mouse on rect1 starts implicit grab
10010         sendMousePress(&scene, QPoint(-25, -25));
10011         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10012         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
10013         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10014         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10015         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10016         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10017
10018         // grab lost to rect2 when rect1 is modally shadowed
10019         rect2->setPanelModality(QGraphicsItem::PanelModal);
10020         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10021         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10022         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10023         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10024         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10025
10026         // rect1 does *not* re-grab when rect2 is no longer modal
10027         rect2->setPanelModality(QGraphicsItem::NonModal);
10028         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10029         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10030         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10031         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10032         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10033
10034         // release goes nowhere
10035         sendMouseRelease(&scene, QPoint(-25, -25));
10036         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10037         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10038         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10039         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10040         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10041         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10042     }
10043
10044     {
10045         // repeat the PanelModal tests, but this time the mouse events will be on a non-modal item,
10046         // meaning normal grabbing should work
10047         rect2->setPanelModality(QGraphicsItem::NonModal);
10048         rect1Spy.counts.clear();
10049         rect2Spy.counts.clear();
10050
10051         QGraphicsRectItem *rect3 = scene.addRect(-50, -50, 100, 100);
10052         rect3->setFlag(QGraphicsItem::ItemIsPanel);
10053         rect3->setFlag(QGraphicsItem::ItemIsMovable);
10054         rect3->setPos(150, 50);
10055         rect3->setData(0, "rect3");
10056
10057         EventSpy2 rect3Spy(&scene, rect3);
10058
10059         // pressing mouse on rect3 starts implicit grab
10060         sendMousePress(&scene, QPoint(150, 50));
10061         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10062         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10063         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10064         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10065         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10066         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10067         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10068         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10069
10070         // grab is *not* lost when rect1 is modally shadowed by rect2
10071         rect2->setPanelModality(QGraphicsItem::PanelModal);
10072         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10073         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10074         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10075         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10076         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10077         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10078         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10079
10080         // releasing goes to rect3
10081         sendMouseRelease(&scene, QPoint(150, 50));
10082         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10083         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10084         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10085         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10086         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10087         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10088         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10089         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10090
10091         rect2->setPanelModality(QGraphicsItem::NonModal);
10092
10093         // pressing mouse on rect3 starts implicit grab
10094         sendMousePress(&scene, QPoint(150, 50));
10095         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10096         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10097         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10098         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10099         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10100         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10101         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10102
10103         // grab is not lost
10104         rect2->setPanelModality(QGraphicsItem::PanelModal);
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], 2);
10110         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10111         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10112
10113         // grab stays on rect3
10114         rect2->setPanelModality(QGraphicsItem::NonModal);
10115         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10116         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10117         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10118         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10119         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10120         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10121         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10122
10123         // release goes to rect3
10124         sendMouseRelease(&scene, QPoint(150, 50));
10125         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10126         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10127         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10128         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10129         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10130         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 2);
10131         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10132     }
10133 }
10134
10135 void tst_QGraphicsItem::modality_clickFocus()
10136 {
10137     QGraphicsScene scene;
10138     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10139     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10140     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10141     rect1->setData(0, "rect1");
10142
10143     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10144     rect2->setParentItem(rect1);
10145     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10146     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10147     rect2->setPos(50, 50);
10148     rect2->setData(0, "rect2");
10149
10150     QEvent windowActivateEvent(QEvent::WindowActivate);
10151     QApplication::sendEvent(&scene, &windowActivateEvent);
10152
10153     EventSpy2 rect1Spy(&scene, rect1);
10154     EventSpy2 rect2Spy(&scene, rect2);
10155
10156     // activate rect1, it should not get focus
10157     rect1->setActive(true);
10158     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10159
10160     // focus stays unset when rect2 becomes modal
10161     rect2->setPanelModality(QGraphicsItem::SceneModal);
10162     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10163     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10164     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10165     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10166     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10167
10168     // clicking on rect1 should not set it's focus item
10169     sendMouseClick(&scene, QPointF(-25, -25));
10170     QCOMPARE(rect1->focusItem(), (QGraphicsItem *) 0);
10171     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10172     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10173     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10174     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10175
10176     // clicking on rect2 gives it focus
10177     rect2->setActive(true);
10178     sendMouseClick(&scene, QPointF(75, 75));
10179     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect2);
10180     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10181     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10182     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10183     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10184
10185     // clicking on rect1 does *not* give it focus
10186     rect1->setActive(true);
10187     sendMouseClick(&scene, QPointF(-25, -25));
10188     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10189     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10190     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10191     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10192     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10193
10194     // focus doesn't change when leaving modality either
10195     rect2->setPanelModality(QGraphicsItem::NonModal);
10196     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10197     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10198     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10199     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10200     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10201
10202     // click on rect1, it should get focus now
10203     sendMouseClick(&scene, QPointF(-25, -25));
10204     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1);
10205     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 1);
10206     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10207     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10208     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10209 }
10210
10211 void tst_QGraphicsItem::modality_keyEvents()
10212 {
10213     QGraphicsScene scene;
10214     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10215     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10216     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10217     rect1->setData(0, "rect1");
10218
10219     QGraphicsRectItem *rect1child = scene.addRect(-10, -10, 20, 20);
10220     rect1child->setParentItem(rect1);
10221     rect1child->setFlag(QGraphicsItem::ItemIsFocusable);
10222     rect1child->setData(0, "rect1child1");
10223
10224     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10225     rect2->setParentItem(rect1);
10226     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10227     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10228     rect2->setPos(50, 50);
10229     rect2->setData(0, "rect2");
10230
10231     QGraphicsRectItem *rect2child = scene.addRect(-10, -10, 20, 20);
10232     rect2child->setParentItem(rect2);
10233     rect2child->setFlag(QGraphicsItem::ItemIsFocusable);
10234     rect2child->setData(0, "rect2child1");
10235
10236     QEvent windowActivateEvent(QEvent::WindowActivate);
10237     QApplication::sendEvent(&scene, &windowActivateEvent);
10238
10239     EventSpy2 rect1Spy(&scene, rect1);
10240     EventSpy2 rect1childSpy(&scene, rect1child);
10241     EventSpy2 rect2Spy(&scene, rect2);
10242     EventSpy2 rect2childSpy(&scene, rect2child);
10243
10244     // activate rect1 and give it rect1child focus
10245     rect1->setActive(true);
10246     rect1child->setFocus();
10247     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10248
10249     // focus stays on rect1child when rect2 becomes modal
10250     rect2->setPanelModality(QGraphicsItem::SceneModal);
10251     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10252
10253     // but key events to rect1child should be neither delivered nor propagated
10254     sendKeyClick(&scene, Qt::Key_A);
10255     sendKeyClick(&scene, Qt::Key_S);
10256     sendKeyClick(&scene, Qt::Key_D);
10257     sendKeyClick(&scene, Qt::Key_F);
10258     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10259     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10260     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10261     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10262
10263     // change to panel modality, rect1child1 keeps focus
10264     rect2->setPanelModality(QGraphicsItem::PanelModal);
10265     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10266
10267     // still no key events
10268     sendKeyClick(&scene, Qt::Key_J);
10269     sendKeyClick(&scene, Qt::Key_K);
10270     sendKeyClick(&scene, Qt::Key_L);
10271     sendKeyClick(&scene, Qt::Key_Semicolon);
10272     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10273     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10274     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10275     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10276 }
10277
10278 void tst_QGraphicsItem::itemIsInFront()
10279 {
10280     QGraphicsScene scene;
10281     QGraphicsRectItem *rect1 = new QGraphicsRectItem;
10282     rect1->setData(0, "rect1");
10283     scene.addItem(rect1);
10284
10285     QGraphicsRectItem *rect1child1 = new QGraphicsRectItem(rect1);
10286     rect1child1->setZValue(1);
10287     rect1child1->setData(0, "rect1child1");
10288
10289     QGraphicsRectItem *rect1child2 = new QGraphicsRectItem(rect1);
10290     rect1child2->setParentItem(rect1);
10291     rect1child2->setData(0, "rect1child2");
10292
10293     QGraphicsRectItem *rect1child1_1 = new QGraphicsRectItem(rect1child1);
10294     rect1child1_1->setData(0, "rect1child1_1");
10295
10296     QGraphicsRectItem *rect1child1_2 = new QGraphicsRectItem(rect1child1);
10297     rect1child1_2->setFlag(QGraphicsItem::ItemStacksBehindParent);
10298     rect1child1_2->setData(0, "rect1child1_2");
10299
10300     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
10301     rect2->setData(0, "rect2");
10302     scene.addItem(rect2);
10303
10304     QGraphicsRectItem *rect2child1 = new QGraphicsRectItem(rect2);
10305     rect2child1->setData(0, "rect2child1");
10306
10307     QCOMPARE(qt_closestItemFirst(rect1, rect1), false);
10308     QCOMPARE(qt_closestItemFirst(rect1, rect2), false);
10309     QCOMPARE(qt_closestItemFirst(rect1child1, rect2child1), false);
10310     QCOMPARE(qt_closestItemFirst(rect1child1, rect1child2), true);
10311     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child2), true);
10312     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child1), true);
10313     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child2), true);
10314     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child1), false);
10315     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1), true);
10316     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2), false);
10317     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2child1), false);
10318 }
10319
10320 class ScenePosChangeTester : public ItemChangeTester
10321 {
10322 public:
10323     ScenePosChangeTester()
10324     { }
10325     ScenePosChangeTester(QGraphicsItem *parent) : ItemChangeTester(parent)
10326     { }
10327 };
10328
10329 void tst_QGraphicsItem::scenePosChange()
10330 {
10331     ScenePosChangeTester* root = new ScenePosChangeTester;
10332     ScenePosChangeTester* child1 = new ScenePosChangeTester(root);
10333     ScenePosChangeTester* grandChild1 = new ScenePosChangeTester(child1);
10334     ScenePosChangeTester* child2 = new ScenePosChangeTester(root);
10335     ScenePosChangeTester* grandChild2 = new ScenePosChangeTester(child2);
10336
10337     child1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10338     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10339
10340     QVERIFY(child1->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10341     QVERIFY(grandChild2->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10342
10343     QGraphicsScene scene;
10344     scene.addItem(root);
10345
10346     // ignore uninteresting changes
10347     child1->clear();
10348     child2->clear();
10349     grandChild1->clear();
10350     grandChild2->clear();
10351
10352     // move whole tree
10353     root->moveBy(1.0, 1.0);
10354     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10355     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10356     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10357     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10358
10359     // move subtree
10360     child2->moveBy(1.0, 1.0);
10361     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10362     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10363     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10364     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10365
10366     // reparent
10367     grandChild2->setParentItem(child1);
10368     child1->moveBy(1.0, 1.0);
10369     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10370     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10371     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10372     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10373
10374     // change flags
10375     grandChild1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10376     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false);
10377     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10378     child1->moveBy(1.0, 1.0);
10379     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10380     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10381     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10382     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10383
10384     // remove
10385     scene.removeItem(grandChild1);
10386     delete grandChild2; grandChild2 = 0;
10387     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10388     root->moveBy(1.0, 1.0);
10389     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 4);
10390     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10391     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10392
10393     root->setX(1);
10394     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 5);
10395     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10396     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10397
10398     root->setY(1);
10399     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 6);
10400     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10401     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10402 }
10403
10404 void tst_QGraphicsItem::textItem_shortcuts()
10405 {
10406     QWidget w;
10407     QVBoxLayout l;
10408     w.setLayout(&l);
10409     QGraphicsScene scene;
10410     QGraphicsView view(&scene);
10411     l.addWidget(&view);
10412     QPushButton b("Push Me");
10413     l.addWidget(&b);
10414
10415     QGraphicsTextItem *item = scene.addText("Troll Text");
10416     item->setFlag(QGraphicsItem::ItemIsFocusable);
10417     item->setTextInteractionFlags(Qt::TextEditorInteraction);
10418     w.show();
10419     QVERIFY(QTest::qWaitForWindowExposed(&w));
10420
10421     item->setFocus();
10422     QTRY_VERIFY(item->hasFocus());
10423     QVERIFY(item->textCursor().selectedText().isEmpty());
10424
10425     // Shortcut should work (select all)
10426     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10427     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10428     QTextCursor tc = item->textCursor();
10429     tc.clearSelection();
10430     item->setTextCursor(tc);
10431     QVERIFY(item->textCursor().selectedText().isEmpty());
10432
10433     // Shortcut should also work if the text item has the focus and another widget
10434     // has the same shortcut.
10435     b.setShortcut(QKeySequence("CTRL+A"));
10436     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10437     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10438 }
10439
10440 void tst_QGraphicsItem::scroll()
10441 {
10442     // Create two overlapping rectangles in the scene:
10443     // +-------+
10444     // |       | <- item1
10445     // |   +-------+
10446     // |   |       |
10447     // +---|       | <- item2
10448     //     |       |
10449     //     +-------+
10450
10451     EventTester *item1 = new EventTester;
10452     item1->br = QRectF(0, 0, 200, 200);
10453     item1->brush = Qt::red;
10454     item1->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10455
10456     EventTester *item2 = new EventTester;
10457     item2->br = QRectF(0, 0, 200, 200);
10458     item2->brush = Qt::blue;
10459     item2->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10460     item2->setPos(100, 100);
10461
10462     QGraphicsScene scene(0, 0, 300, 300);
10463     scene.addItem(item1);
10464     scene.addItem(item2);
10465
10466     MyGraphicsView view(&scene);
10467     view.setFrameStyle(0);
10468     view.show();
10469     QVERIFY(QTest::qWaitForWindowActive(&view));
10470     QTRY_VERIFY(view.repaints > 0);
10471
10472     view.reset();
10473     item1->reset();
10474     item2->reset();
10475
10476     const QRectF item1BoundingRect = item1->boundingRect();
10477     const QRectF item2BoundingRect = item2->boundingRect();
10478
10479     // Scroll item1:
10480     // Item1 should get full exposure
10481     // Item2 should get exposure for the part that overlaps item1.
10482     item1->scroll(0, -10);
10483     QTRY_VERIFY(view.repaints > 0);
10484     QCOMPARE(item1->lastExposedRect, item1BoundingRect);
10485
10486     QRectF expectedItem2Expose = item2BoundingRect;
10487     // NB! Adjusted by 2 pixels for antialiasing
10488     expectedItem2Expose &= item1->mapRectToItem(item2, item1BoundingRect.adjusted(-2, -2, 2, 2));
10489     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10490
10491     // Enable ItemCoordinateCache on item1.
10492     view.reset();
10493     item1->setCacheMode(QGraphicsItem::ItemCoordinateCache);
10494     QTRY_VERIFY(view.repaints > 0);
10495     view.reset();
10496     item1->reset();
10497     item2->reset();
10498
10499     // Scroll item1:
10500     // Item1 should only get expose for the newly exposed area (accelerated scroll).
10501     // Item2 should get exposure for the part that overlaps item1.
10502     item1->scroll(0, -10, QRectF(50, 50, 100, 100));
10503     QTRY_VERIFY(view.repaints > 0);
10504     QCOMPARE(item1->lastExposedRect, QRectF(50, 140, 100, 10));
10505
10506     expectedItem2Expose = item2BoundingRect;
10507     // NB! Adjusted by 2 pixels for antialiasing
10508     expectedItem2Expose &= item1->mapRectToItem(item2, QRectF(50, 50, 100, 100).adjusted(-2, -2, 2, 2));
10509     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10510 }
10511
10512 Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlag);
10513
10514 void tst_QGraphicsItem::focusHandling_data()
10515 {
10516     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("focusFlag");
10517     QTest::addColumn<bool>("useStickyFocus");
10518     QTest::addColumn<int>("expectedFocusItem"); // 0: none, 1: focusableUnder, 2: itemWithFocus
10519
10520     QTest::newRow("Focus goes through.")
10521         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << false << 1;
10522
10523     QTest::newRow("Focus goes through, even with sticky scene.")
10524         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << true  << 1;
10525
10526     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (but can still focus-out).")
10527         << QGraphicsItem::ItemStopsClickFocusPropagation << false << 0;
10528
10529     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (and cannot focus-out if scene is sticky).")
10530         << QGraphicsItem::ItemStopsClickFocusPropagation << true << 2;
10531
10532     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses.")
10533         << QGraphicsItem::ItemStopsFocusHandling << false << 2;
10534
10535     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses (even if scene is sticky).")
10536         << QGraphicsItem::ItemStopsFocusHandling << true << 2;
10537 }
10538
10539 void tst_QGraphicsItem::focusHandling()
10540 {
10541     QFETCH(QGraphicsItem::GraphicsItemFlag, focusFlag);
10542     QFETCH(bool, useStickyFocus);
10543     QFETCH(int, expectedFocusItem);
10544
10545     class MyItem : public QGraphicsRectItem
10546     {
10547     public:
10548         MyItem() : QGraphicsRectItem(0, 0, 100, 100) {}
10549         void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
10550         {
10551             painter->fillRect(boundingRect(), hasFocus() ? QBrush(Qt::red) : brush());
10552         }
10553     };
10554
10555     QGraphicsRectItem *noFocusOnTop = new MyItem;
10556     noFocusOnTop->setFlag(QGraphicsItem::ItemIsFocusable, false);
10557     noFocusOnTop->setBrush(Qt::yellow);
10558
10559     QGraphicsRectItem *focusableUnder = new MyItem;
10560     focusableUnder->setBrush(Qt::blue);
10561     focusableUnder->setFlag(QGraphicsItem::ItemIsFocusable);
10562     focusableUnder->setPos(50, 50);
10563
10564     QGraphicsRectItem *itemWithFocus = new MyItem;
10565     itemWithFocus->setBrush(Qt::black);
10566     itemWithFocus->setFlag(QGraphicsItem::ItemIsFocusable);
10567     itemWithFocus->setPos(250, 10);
10568
10569     QGraphicsScene scene(-50, -50, 400, 400);
10570     scene.addItem(noFocusOnTop);
10571     scene.addItem(focusableUnder);
10572     scene.addItem(itemWithFocus);
10573     scene.setStickyFocus(useStickyFocus);
10574
10575     noFocusOnTop->setFlag(focusFlag);
10576     focusableUnder->stackBefore(noFocusOnTop);
10577     itemWithFocus->setFocus();
10578
10579     QGraphicsView view(&scene);
10580     view.show();
10581     QVERIFY(QTest::qWaitForWindowExposed(&view));
10582
10583     QApplication::setActiveWindow(&view);
10584     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
10585     QVERIFY(itemWithFocus->hasFocus());
10586
10587     const QPointF mousePressPoint = noFocusOnTop->mapToScene(noFocusOnTop->boundingRect().center());
10588     const QList<QGraphicsItem *> itemsAtMousePressPosition = scene.items(mousePressPoint);
10589     QVERIFY(itemsAtMousePressPosition.contains(noFocusOnTop));
10590
10591     sendMousePress(&scene, mousePressPoint);
10592
10593     switch (expectedFocusItem) {
10594     case 0:
10595         QCOMPARE(scene.focusItem(), static_cast<QGraphicsRectItem *>(0));
10596         break;
10597     case 1:
10598         QCOMPARE(scene.focusItem(), focusableUnder);
10599         break;
10600     case 2:
10601         QCOMPARE(scene.focusItem(), itemWithFocus);
10602         break;
10603     }
10604
10605     // Sanity check - manually setting the focus must work regardless of our
10606     // focus handling flags:
10607     focusableUnder->setFocus();
10608     QCOMPARE(scene.focusItem(), focusableUnder);
10609 }
10610
10611 void tst_QGraphicsItem::touchEventPropagation_data()
10612 {
10613     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("flag");
10614     QTest::addColumn<int>("expectedCount");
10615
10616     QTest::newRow("ItemIsPanel")
10617         << QGraphicsItem::ItemIsPanel << 0;
10618     QTest::newRow("ItemStopsClickFocusPropagation")
10619         << QGraphicsItem::ItemStopsClickFocusPropagation << 1;
10620     QTest::newRow("ItemStopsFocusHandling")
10621         << QGraphicsItem::ItemStopsFocusHandling << 1;
10622 }
10623
10624 void tst_QGraphicsItem::touchEventPropagation()
10625 {
10626     QFETCH(QGraphicsItem::GraphicsItemFlag, flag);
10627     QFETCH(int, expectedCount);
10628
10629     class Testee : public QGraphicsRectItem
10630     {
10631     public:
10632         int touchBeginEventCount;
10633
10634         Testee()
10635             : QGraphicsRectItem(0, 0, 100, 100)
10636             , touchBeginEventCount(0)
10637         {
10638             setAcceptTouchEvents(true);
10639             setFlag(QGraphicsItem::ItemIsFocusable, false);
10640         }
10641
10642         bool sceneEvent(QEvent *ev)
10643         {
10644             if (ev->type() == QEvent::TouchBegin)
10645                 ++touchBeginEventCount;
10646
10647             return QGraphicsRectItem::sceneEvent(ev);
10648         }
10649     };
10650
10651     Testee *touchEventReceiver = new Testee;
10652     QGraphicsItem *topMost = new QGraphicsRectItem(touchEventReceiver->boundingRect());
10653
10654     QGraphicsScene scene;
10655     scene.addItem(topMost);
10656     scene.addItem(touchEventReceiver);
10657
10658     topMost->setAcceptTouchEvents(true);
10659     topMost->setZValue(FLT_MAX);
10660     topMost->setFlag(QGraphicsItem::ItemIsFocusable, false);
10661     topMost->setFlag(flag, true);
10662
10663     QGraphicsView view(&scene);
10664     view.setSceneRect(touchEventReceiver->boundingRect());
10665     view.show();
10666     QVERIFY(QTest::qWaitForWindowExposed(&view));
10667
10668     QCOMPARE(touchEventReceiver->touchBeginEventCount, 0);
10669
10670     QTouchEvent::TouchPoint tp(0);
10671     tp.setState(Qt::TouchPointPressed);
10672     tp.setScenePos(view.sceneRect().center());
10673     tp.setLastScenePos(view.sceneRect().center());
10674
10675     QList<QTouchEvent::TouchPoint> touchPoints;
10676     touchPoints << tp;
10677
10678     sendMousePress(&scene, tp.scenePos());
10679     QTouchDevice *device = new QTouchDevice;
10680     device->setType(QTouchDevice::TouchScreen);
10681     QWindowSystemInterface::registerTouchDevice(device);
10682     QTouchEvent touchBegin(QEvent::TouchBegin, device, Qt::NoModifier, Qt::TouchPointPressed, touchPoints);
10683
10684     qApp->sendEvent(&scene, &touchBegin);
10685     QCOMPARE(touchEventReceiver->touchBeginEventCount, expectedCount);
10686 }
10687
10688 void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations()
10689 {
10690     // Make sure we don't invalidate the cache when applying simple
10691     // (90, 180, 270, 360) rotation transforms to the item.
10692     QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 300, 200);
10693     item->setBrush(Qt::red);
10694     item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
10695
10696     QGraphicsScene scene;
10697     scene.setSceneRect(0, 0, 300, 200);
10698     scene.addItem(item);
10699
10700     MyGraphicsView view(&scene);
10701     view.show();
10702     QVERIFY(QTest::qWaitForWindowExposed(&view));
10703     QTRY_VERIFY(view.repaints > 0);
10704
10705     QGraphicsItemCache *itemCache = QGraphicsItemPrivate::get(item)->extraItemCache();
10706     QVERIFY(itemCache);
10707     QPixmapCache::Key currentKey = itemCache->deviceData.value(view.viewport()).key;
10708
10709     // Trigger an update and verify that the cache is unchanged.
10710     QPixmapCache::Key oldKey = currentKey;
10711     view.reset();
10712     view.viewport()->update();
10713     QTRY_VERIFY(view.repaints > 0);
10714     currentKey = itemCache->deviceData.value(view.viewport()).key;
10715     QCOMPARE(currentKey, oldKey);
10716
10717     // Check 90, 180, 270 and 360 degree rotations.
10718     for (int angle = 90; angle <= 360; angle += 90) {
10719         // Rotate item and verify that the cache was invalidated.
10720         oldKey = currentKey;
10721         view.reset();
10722         QTransform transform;
10723         transform.translate(150, 100);
10724         transform.rotate(angle);
10725         transform.translate(-150, -100);
10726         item->setTransform(transform);
10727         QTRY_VERIFY(view.repaints > 0);
10728         currentKey = itemCache->deviceData.value(view.viewport()).key;
10729         QVERIFY(currentKey != oldKey);
10730
10731         // IMPORTANT PART:
10732         // Trigger an update and verify that the cache is unchanged.
10733         oldKey = currentKey;
10734         view.reset();
10735         view.viewport()->update();
10736         QTRY_VERIFY(view.repaints > 0);
10737         currentKey = itemCache->deviceData.value(view.viewport()).key;
10738         QCOMPARE(currentKey, oldKey);
10739     }
10740
10741     // 45 degree rotation.
10742     oldKey = currentKey;
10743     view.reset();
10744     QTransform transform;
10745     transform.translate(150, 100);
10746     transform.rotate(45);
10747     transform.translate(-150, -100);
10748     item->setTransform(transform);
10749     QTRY_VERIFY(view.repaints > 0);
10750     currentKey = itemCache->deviceData.value(view.viewport()).key;
10751     QVERIFY(currentKey != oldKey);
10752
10753     // Trigger an update and verify that the cache was invalidated.
10754     // We should always invalidate the cache for non-trivial transforms.
10755     oldKey = currentKey;
10756     view.reset();
10757     view.viewport()->update();
10758     QTRY_VERIFY(view.repaints > 0);
10759     currentKey = itemCache->deviceData.value(view.viewport()).key;
10760     QVERIFY(currentKey != oldKey);
10761 }
10762
10763 void tst_QGraphicsItem::QTBUG_5418_textItemSetDefaultColor()
10764 {
10765     struct Item : public QGraphicsTextItem
10766     {
10767         int painted;
10768         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
10769         {
10770             painted++;
10771             QGraphicsTextItem::paint(painter, opt, wid);
10772         }
10773     };
10774
10775     Item *i = new Item;
10776     i->painted = 0;
10777     i->setPlainText("I AM A TROLL");
10778
10779     QGraphicsScene scene;
10780     QGraphicsView view(&scene);
10781     view.show();
10782     QVERIFY(QTest::qWaitForWindowExposed(&view));
10783     scene.addItem(i);
10784     QApplication::processEvents();
10785     QTRY_VERIFY(i->painted);
10786     QApplication::processEvents();
10787
10788     i->painted = 0;
10789     QColor col(Qt::red);
10790     i->setDefaultTextColor(col);
10791     QApplication::processEvents();
10792     QTRY_COMPARE(i->painted, 1); //check that changing the color force an update
10793
10794     i->painted = false;
10795     QImage image(400, 200, QImage::Format_RGB32);
10796     image.fill(0);
10797     QPainter painter(&image);
10798     scene.render(&painter);
10799     painter.end();
10800     QCOMPARE(i->painted, 1);
10801
10802     int numRedPixel = 0;
10803     QRgb rgb = col.rgb();
10804     for (int y = 0; y < image.height(); ++y) {
10805         for (int x = 0; x < image.width(); ++x) {
10806             // Because of antialiasing we allow a certain range of errors here.
10807             QRgb pixel = image.pixel(x, y);
10808             if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) +
10809                 qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) +
10810                 qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) {
10811                 if (++numRedPixel >= 10) {
10812                     return;
10813                 }
10814             }
10815         }
10816     }
10817     QCOMPARE(numRedPixel, -1); //color not found, FAIL!
10818
10819     i->painted = 0;
10820     i->setDefaultTextColor(col);
10821     QApplication::processEvents();
10822     QCOMPARE(i->painted, 0); //same color as before should not trigger an update (QTBUG-6242)
10823 }
10824
10825 void tst_QGraphicsItem::QTBUG_6738_missingUpdateWithSetParent()
10826 {
10827     // In all 3 test cases below the reparented item should disappear
10828     EventTester *parent = new EventTester;
10829     EventTester *child = new EventTester(parent);
10830     EventTester *child2 = new EventTester(parent);
10831     EventTester *child3 = new EventTester(parent);
10832     EventTester *child4 = new EventTester(parent);
10833
10834     child->setPos(10, 10);
10835     child2->setPos(20, 20);
10836     child3->setPos(30, 30);
10837     child4->setPos(40, 40);
10838
10839     QGraphicsScene scene;
10840     scene.addItem(parent);
10841
10842     MyGraphicsView view(&scene);
10843     view.show();
10844     qApp->setActiveWindow(&view);
10845     QVERIFY(QTest::qWaitForWindowActive(&view));
10846     QTRY_VERIFY(view.repaints > 0);
10847
10848     // test case #1
10849     view.reset();
10850     child2->setVisible(false);
10851     child2->setParentItem(child);
10852
10853     QTRY_VERIFY(view.repaints == 1);
10854
10855     // test case #2
10856     view.reset();
10857     child3->setOpacity(0.0);
10858     child3->setParentItem(child);
10859
10860     QTRY_VERIFY(view.repaints == 1);
10861
10862     // test case #3
10863     view.reset();
10864     child4->setParentItem(child);
10865     child4->setVisible(false);
10866
10867     QTRY_VERIFY(view.repaints == 1);
10868 }
10869
10870 void tst_QGraphicsItem::QT_2653_fullUpdateDiscardingOpacityUpdate()
10871 {
10872     QGraphicsScene scene(0, 0, 200, 200);
10873     MyGraphicsView view(&scene);
10874
10875     EventTester *parentGreen = new EventTester();
10876     parentGreen->setGeometry(QRectF(20, 20, 100, 100));
10877     parentGreen->brush = Qt::green;
10878
10879     EventTester *childYellow = new EventTester(parentGreen);
10880     childYellow->setGeometry(QRectF(10, 10, 50, 50));
10881     childYellow->brush = Qt::yellow;
10882
10883     scene.addItem(parentGreen);
10884
10885     childYellow->setOpacity(0.0);
10886     parentGreen->setOpacity(0.0);
10887
10888     // set any of the flags below to trigger a fullUpdate to reproduce the bug:
10889     // ItemIgnoresTransformations, ItemClipsChildrenToShape, ItemIsSelectable
10890     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
10891
10892     view.show();
10893     QVERIFY(QTest::qWaitForWindowActive(&view));
10894     view.reset();
10895
10896     parentGreen->setOpacity(1.0);
10897
10898     QTRY_COMPARE(view.repaints, 1);
10899
10900     view.reset();
10901     childYellow->repaints = 0;
10902
10903     childYellow->setOpacity(1.0);
10904
10905     QTRY_COMPARE(view.repaints, 1);
10906     QTRY_COMPARE(childYellow->repaints, 1);
10907 }
10908
10909 void tst_QGraphicsItem::QTBUG_7714_fullUpdateDiscardingOpacityUpdate2()
10910 {
10911     QGraphicsScene scene(0, 0, 200, 200);
10912     MyGraphicsView view(&scene);
10913     MyGraphicsView origView(&scene);
10914
10915     EventTester *parentGreen = new EventTester();
10916     parentGreen->setGeometry(QRectF(20, 20, 100, 100));
10917     parentGreen->brush = Qt::green;
10918
10919     EventTester *childYellow = new EventTester(parentGreen);
10920     childYellow->setGeometry(QRectF(10, 10, 50, 50));
10921     childYellow->brush = Qt::yellow;
10922
10923     scene.addItem(parentGreen);
10924
10925     origView.show();
10926     QVERIFY(QTest::qWaitForWindowActive(&origView));
10927     origView.setGeometry(origView.width() + 20, 20,
10928                          origView.width(), origView.height());
10929
10930     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
10931
10932     origView.reset();
10933     childYellow->setOpacity(0.0);
10934
10935     QTRY_COMPARE(origView.repaints, 1);
10936
10937     view.show();
10938     qApp->setActiveWindow(&view);
10939     QVERIFY(QTest::qWaitForWindowActive(&view));
10940     view.reset();
10941     origView.reset();
10942
10943     childYellow->setOpacity(1.0);
10944
10945     QTRY_COMPARE(origView.repaints, 1);
10946     QTRY_COMPARE(view.repaints, 1);
10947 }
10948
10949 void tst_QGraphicsItem::QT_2649_focusScope()
10950 {
10951     QGraphicsScene *scene = new QGraphicsScene;
10952
10953     QGraphicsRectItem *subFocusItem = new QGraphicsRectItem;
10954     subFocusItem->setFlags(QGraphicsItem::ItemIsFocusable);
10955     subFocusItem->setFocus();
10956     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
10957
10958     QGraphicsRectItem *scope = new QGraphicsRectItem;
10959     scope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
10960     scope->setFocus();
10961     subFocusItem->setParentItem(scope);
10962     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
10963     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
10964     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
10965     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
10966
10967     QGraphicsRectItem *rootItem = new QGraphicsRectItem;
10968     rootItem->setFlags(QGraphicsItem::ItemIsFocusable);
10969     scope->setParentItem(rootItem);
10970     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
10971     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
10972     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
10973     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
10974     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
10975     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
10976
10977     scene->addItem(rootItem);
10978
10979     QEvent windowActivate(QEvent::WindowActivate);
10980     qApp->sendEvent(scene, &windowActivate);
10981     scene->setFocus();
10982
10983     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
10984     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
10985     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
10986     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
10987     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
10988     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
10989     QVERIFY(subFocusItem->hasFocus());
10990
10991     scope->hide();
10992
10993     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)0);
10994     QCOMPARE(scope->focusItem(), (QGraphicsItem *)0);
10995     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)0);
10996     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
10997     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
10998     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
10999     QVERIFY(!subFocusItem->hasFocus());
11000
11001     scope->show();
11002
11003     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11004     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11005     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11006     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11007     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11008     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11009     QVERIFY(subFocusItem->hasFocus());
11010
11011     // This should not crash
11012     scope->hide();
11013     delete scene;
11014 }
11015
11016 class MyGraphicsItemWithItemChange : public QGraphicsWidget
11017 {
11018 public:
11019     MyGraphicsItemWithItemChange(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
11020     {}
11021
11022     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
11023     {
11024         if (change == QGraphicsItem::ItemSceneHasChanged) {
11025             foreach (QGraphicsView *view, scene()->views()) {
11026                 //We trigger a sort of unindexed items in the BSP
11027                 view->sceneRect();
11028             }
11029         }
11030         return QGraphicsWidget::itemChange(change, value);
11031     }
11032 };
11033
11034 void tst_QGraphicsItem::sortItemsWhileAdding()
11035 {
11036     QGraphicsScene scene;
11037     QGraphicsView view(&scene);
11038     QGraphicsWidget grandGrandParent;
11039     grandGrandParent.resize(200, 200);
11040     scene.addItem(&grandGrandParent);
11041     QGraphicsWidget grandParent;
11042     grandParent.resize(200, 200);
11043     QGraphicsWidget parent(&grandParent);
11044     parent.resize(200, 200);
11045     MyGraphicsItemWithItemChange item(&parent);
11046     grandParent.setParentItem(&grandGrandParent);
11047 }
11048
11049 void tst_QGraphicsItem::doNotMarkFullUpdateIfNotInScene()
11050 {
11051     struct Item : public QGraphicsTextItem
11052     {
11053         int painted;
11054         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
11055         {
11056             painted++;
11057             QGraphicsTextItem::paint(painter, opt, wid);
11058         }
11059     };
11060     QGraphicsScene scene;
11061     MyGraphicsView view(&scene);
11062     Item *item = new Item;
11063     item->painted = 0;
11064     item->setPlainText("Grandparent");
11065     Item *item2 = new Item;
11066     item2->setPlainText("parent");
11067     item2->painted = 0;
11068     Item *item3 = new Item;
11069     item3->setPlainText("child");
11070     item3->painted = 0;
11071     QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect;
11072     effect->setOpacity(0.5);
11073     item2->setGraphicsEffect(effect);
11074     item3->setParentItem(item2);
11075     item2->setParentItem(item);
11076     scene.addItem(item);
11077     view.show();
11078     QTest::qWaitForWindowActive(view.windowHandle());
11079     view.activateWindow();
11080     QTRY_VERIFY(view.isActiveWindow());
11081     QTRY_VERIFY(view.repaints >= 1);
11082     int count = view.repaints;
11083     QTRY_COMPARE(item->painted, count);
11084     // cached as graphics effects, not painted multiple times
11085     QTRY_COMPARE(item2->painted, 1);
11086     QTRY_COMPARE(item3->painted, 1);
11087     item2->update();
11088     QApplication::processEvents();
11089     QTRY_COMPARE(item->painted, count + 1);
11090     QTRY_COMPARE(item2->painted, 2);
11091     QTRY_COMPARE(item3->painted, 2);
11092     item2->update();
11093     QApplication::processEvents();
11094     QTRY_COMPARE(item->painted, count + 2);
11095     QTRY_COMPARE(item2->painted, 3);
11096     QTRY_COMPARE(item3->painted, 3);
11097 }
11098
11099 void tst_QGraphicsItem::itemDiesDuringDraggingOperation()
11100 {
11101     QGraphicsScene scene;
11102     QGraphicsView view(&scene);
11103     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
11104     item->setFlag(QGraphicsItem::ItemIsMovable);
11105     item->setAcceptDrops(true);
11106     scene.addItem(item);
11107     view.show();
11108     QApplication::setActiveWindow(&view);
11109     QVERIFY(QTest::qWaitForWindowActive(&view));
11110     QCOMPARE(QApplication::activeWindow(), (QWidget *)&view);
11111     QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
11112     dragEnter.setScenePos(item->boundingRect().center());
11113     QApplication::sendEvent(&scene, &dragEnter);
11114     QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragMove);
11115     event.setScenePos(item->boundingRect().center());
11116     QApplication::sendEvent(&scene, &event);
11117     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == item);
11118     delete item;
11119     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == 0);
11120 }
11121
11122 void tst_QGraphicsItem::QTBUG_12112_focusItem()
11123 {
11124     QGraphicsScene scene;
11125     QGraphicsView view(&scene);
11126     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
11127     item1->setFlag(QGraphicsItem::ItemIsFocusable);
11128     QGraphicsRectItem *item2 = new QGraphicsRectItem(20, 20, 20, 20);
11129     item2->setFlag(QGraphicsItem::ItemIsFocusable);
11130     item1->setFocus();
11131     scene.addItem(item2);
11132     scene.addItem(item1);
11133
11134     view.show();
11135     QApplication::setActiveWindow(&view);
11136     QVERIFY(QTest::qWaitForWindowActive(&view));
11137     QCOMPARE(QApplication::activeWindow(), (QWidget *)&view);
11138
11139     QVERIFY(item1->focusItem());
11140     QVERIFY(!item2->focusItem());
11141
11142     item2->setFocus();
11143     QVERIFY(!item1->focusItem());
11144     QVERIFY(item2->focusItem());
11145 }
11146
11147 void tst_QGraphicsItem::QTBUG_13473_sceneposchange()
11148 {
11149     ScenePosChangeTester* parent = new ScenePosChangeTester;
11150     ScenePosChangeTester* child = new ScenePosChangeTester(parent);
11151
11152     // parent's disabled ItemSendsGeometryChanges flag must not affect
11153     // child's scene pos change notifications
11154     parent->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
11155     child->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
11156
11157     QGraphicsScene scene;
11158     scene.addItem(parent);
11159
11160     // ignore uninteresting changes
11161     parent->clear();
11162     child->clear();
11163
11164     // move
11165     parent->moveBy(1.0, 1.0);
11166     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
11167
11168     // transform
11169     parent->setTransform(QTransform::fromScale(0.5, 0.5));
11170     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
11171 }
11172
11173 class MyGraphicsWidget : public QGraphicsWidget {
11174 Q_OBJECT
11175 public:
11176     MyGraphicsWidget()
11177         : QGraphicsWidget(0)
11178     {
11179         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11180         QLatin1String wiseWords("AZ BUKI VEDI");
11181         QString sentence(wiseWords);
11182         QStringList words = sentence.split(QLatin1Char(' '), QString::SkipEmptyParts);
11183         for (int i = 0; i < words.count(); ++i) {
11184             QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(this);
11185             QLabel *label = new QLabel(words.at(i));
11186             proxy->setWidget(label);
11187             proxy->setFocusPolicy(Qt::StrongFocus);
11188             proxy->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
11189             if (i%2 == 0)
11190                 proxy->setVisible(false);
11191             proxy->setFocus();
11192             lay->addItem(proxy);
11193         }
11194         setLayout(lay);
11195     }
11196
11197 };
11198
11199 class MyWidgetWindow : public QGraphicsWidget
11200 {
11201 public:
11202     MyWidgetWindow()
11203         : QGraphicsWidget(0, Qt::Window)
11204     {
11205         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11206         MyGraphicsWidget *widget = new MyGraphicsWidget();
11207         lay->addItem(widget);
11208         setLayout(lay);
11209     }
11210 };
11211
11212 void tst_QGraphicsItem::QTBUG_16374_crashInDestructor()
11213 {
11214     QGraphicsScene scene;
11215     QGraphicsView view(&scene);
11216
11217     MyWidgetWindow win;
11218     scene.addItem(&win);
11219
11220     view.show();
11221     QVERIFY(QTest::qWaitForWindowExposed(&view));
11222 }
11223
11224 void tst_QGraphicsItem::QTBUG_20699_focusScopeCrash()
11225 {
11226     QGraphicsScene scene;
11227     QGraphicsView view(&scene);
11228     QGraphicsPixmapItem fs;
11229     fs.setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11230     scene.addItem(&fs);
11231     QGraphicsPixmapItem* fs2 = new QGraphicsPixmapItem(&fs);
11232     fs2->setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11233     QGraphicsPixmapItem* fi2 = new QGraphicsPixmapItem(&fs);
11234     fi2->setFlags(QGraphicsItem::ItemIsFocusable);
11235     QGraphicsPixmapItem* fi = new QGraphicsPixmapItem(fs2);
11236     fi->setFlags(QGraphicsItem::ItemIsFocusable);
11237     fs.setFocus();
11238     fi->setFocus();
11239
11240     view.show();
11241     QVERIFY(QTest::qWaitForWindowExposed(&view));
11242
11243     fi->setParentItem(fi2);
11244     fi->setFocus();
11245     fs.setFocus();
11246     fi->setParentItem(fs2);
11247     fi->setFocus();
11248     fs2->setFocus();
11249     fs.setFocus();
11250     fi->setParentItem(fi2);
11251     fi->setFocus();
11252     fs.setFocus();
11253 }
11254
11255 QTEST_MAIN(tst_QGraphicsItem)
11256 #include "tst_qgraphicsitem.moc"