Make QPen default to 1-width non-cosmetic.
[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             ((QGraphicsEllipseItem *)item)->setPen(QPen(Qt::black, 0));
495             QCOMPARE(int(item->type()), int(QGraphicsEllipseItem::Type));
496             QCOMPARE(qgraphicsitem_cast<QGraphicsEllipseItem *>(item), (QGraphicsEllipseItem *)item);
497             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
498             QCOMPARE(item->flags(), 0);
499             break;
500         case 1:
501             item = new QGraphicsLineItem;
502             ((QGraphicsLineItem *)item)->setPen(QPen(Qt::black, 0));
503             QCOMPARE(int(item->type()), int(QGraphicsLineItem::Type));
504             QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)item);
505             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
506             QCOMPARE(item->flags(), 0);
507             break;
508         case 2:
509             item = new QGraphicsPathItem;
510             ((QGraphicsPathItem *)item)->setPen(QPen(Qt::black, 0));
511             QCOMPARE(int(item->type()), int(QGraphicsPathItem::Type));
512             QCOMPARE(qgraphicsitem_cast<QGraphicsPathItem *>(item), (QGraphicsPathItem *)item);
513             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
514             QCOMPARE(item->flags(), 0);
515             break;
516         case 3:
517             item = new QGraphicsPixmapItem;
518             QCOMPARE(int(item->type()), int(QGraphicsPixmapItem::Type));
519             QCOMPARE(qgraphicsitem_cast<QGraphicsPixmapItem *>(item), (QGraphicsPixmapItem *)item);
520             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
521             QCOMPARE(item->flags(), 0);
522             break;
523         case 4:
524             item = new QGraphicsPolygonItem;
525             ((QGraphicsPolygonItem *)item)->setPen(QPen(Qt::black, 0));
526             QCOMPARE(int(item->type()), int(QGraphicsPolygonItem::Type));
527             QCOMPARE(qgraphicsitem_cast<QGraphicsPolygonItem *>(item), (QGraphicsPolygonItem *)item);
528             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
529             QCOMPARE(item->flags(), 0);
530             break;
531         case 5:
532             item = new QGraphicsRectItem;
533             ((QGraphicsRectItem *)item)->setPen(QPen(Qt::black, 0));
534             QCOMPARE(int(item->type()), int(QGraphicsRectItem::Type));
535             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)item);
536             QCOMPARE(qgraphicsitem_cast<QGraphicsLineItem *>(item), (QGraphicsLineItem *)0);
537             QCOMPARE(item->flags(), 0);
538             break;
539         case 6:
540             item = new QGraphicsTextItem;
541             QCOMPARE(int(item->type()), int(QGraphicsTextItem::Type));
542             QCOMPARE(qgraphicsitem_cast<QGraphicsTextItem *>(item), (QGraphicsTextItem *)item);
543             QCOMPARE(qgraphicsitem_cast<QGraphicsRectItem *>(item), (QGraphicsRectItem *)0);
544             // This is the only item that uses an extended style option.
545             QCOMPARE(item->flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
546             break;
547         default:
548             qFatal("You broke the logic, please fix!");
549             break;
550         }
551
552         QCOMPARE(item->scene(), (QGraphicsScene *)0);
553         QCOMPARE(item->parentItem(), (QGraphicsItem *)0);
554         QVERIFY(item->children().isEmpty());
555         QVERIFY(item->isVisible());
556         QVERIFY(item->isEnabled());
557         QVERIFY(!item->isSelected());
558         QCOMPARE(item->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
559         if (item->type() == QGraphicsTextItem::Type)
560             QVERIFY(item->acceptsHoverEvents());
561         else
562             QVERIFY(!item->acceptsHoverEvents());
563         QVERIFY(!item->hasFocus());
564         QCOMPARE(item->pos(), QPointF());
565         QCOMPARE(item->matrix(), QMatrix());
566         QCOMPARE(item->sceneMatrix(), QMatrix());
567         QCOMPARE(item->zValue(), qreal(0));
568         QCOMPARE(item->sceneBoundingRect(), QRectF());
569         QCOMPARE(item->shape(), QPainterPath());
570         QVERIFY(!item->contains(QPointF(0, 0)));
571         QVERIFY(!item->collidesWithItem(0));
572         QVERIFY(item->collidesWithItem(item));
573         QVERIFY(!item->collidesWithPath(QPainterPath()));
574         QVERIFY(!item->isAncestorOf(0));
575         QVERIFY(!item->isAncestorOf(item));
576         QCOMPARE(item->data(0), QVariant());
577         delete item;
578     }
579 }
580
581 class BoundingRectItem : public QGraphicsRectItem
582 {
583 public:
584     BoundingRectItem(QGraphicsItem *parent = 0)
585         : QGraphicsRectItem(0, 0, parent ? 200 : 100, parent ? 200 : 100,
586                             parent)
587     {
588         setPen(QPen(Qt::black, 0));
589     }
590
591     QRectF boundingRect() const
592     {
593         QRectF tmp = QGraphicsRectItem::boundingRect();
594         foreach (QGraphicsItem *child, children())
595             tmp |= child->boundingRect(); // <- might be pure virtual
596         return tmp;
597     }
598 };
599
600 void tst_QGraphicsItem::constructionWithParent()
601 {
602     // This test causes a crash if item1 calls item2's pure virtuals before the
603     // object has been constructed.
604     QGraphicsItem *item0 = new BoundingRectItem;
605     QGraphicsItem *item1 = new BoundingRectItem;
606     QGraphicsScene scene;
607     scene.addItem(item0);
608     scene.addItem(item1);
609     QGraphicsItem *item2 = new BoundingRectItem(item1);
610     QCOMPARE(item1->children(), QList<QGraphicsItem *>() << item2);
611     QCOMPARE(item1->boundingRect(), QRectF(0, 0, 200, 200));
612
613     item2->setParentItem(item0);
614     QCOMPARE(item0->children(), QList<QGraphicsItem *>() << item2);
615     QCOMPARE(item0->boundingRect(), QRectF(0, 0, 200, 200));
616 }
617
618 static int itemDeleted = 0;
619 class Item : public QGraphicsRectItem
620 {
621 public:
622     ~Item()
623     { ++itemDeleted; }
624 };
625
626 void tst_QGraphicsItem::destruction()
627 {
628     QCOMPARE(itemDeleted, 0);
629     {
630         QGraphicsItem *parent = new QGraphicsRectItem;
631         Item *child = new Item;
632         child->setParentItem(parent);
633         QCOMPARE(child->parentItem(), parent);
634         delete parent;
635         QCOMPARE(itemDeleted, 1);
636     }
637     {
638         QGraphicsItem *parent = new QGraphicsRectItem;
639         Item *child = new Item;
640         child->setParentItem(parent);
641         QCOMPARE(parent->children().size(), 1);
642         delete child;
643         QCOMPARE(parent->children().size(), 0);
644         delete parent;
645         QCOMPARE(itemDeleted, 2);
646     }
647     {
648         QGraphicsScene scene;
649         QGraphicsItem *parent = new QGraphicsRectItem;
650         Item *child = new Item;
651         QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
652         child->setParentItem(parent);
653         QCOMPARE(child->parentItem(), parent);
654         scene.addItem(parent);
655         QCOMPARE(child->parentItem(), parent);
656         delete parent;
657         QCOMPARE(itemDeleted, 3);
658     }
659     {
660         QGraphicsScene scene;
661         QGraphicsItem *parent = new QGraphicsRectItem;
662         Item *child = new Item;
663         child->setParentItem(parent);
664         scene.addItem(parent);
665         QCOMPARE(child->scene(), &scene);
666         QCOMPARE(parent->children().size(), 1);
667         delete child;
668         QCOMPARE(parent->children().size(), 0);
669         delete parent;
670         QCOMPARE(itemDeleted, 4);
671     }
672     {
673         QGraphicsScene scene;
674         QGraphicsItem *parent = new QGraphicsRectItem;
675         Item *child = new Item;
676         child->setParentItem(parent);
677         scene.addItem(parent);
678         QCOMPARE(child->scene(), &scene);
679         scene.removeItem(parent);
680         QCOMPARE(child->scene(), (QGraphicsScene *)0);
681         delete parent;
682         QCOMPARE(itemDeleted, 5);
683     }
684     {
685         QGraphicsScene scene;
686         QGraphicsItem *parent = new QGraphicsRectItem;
687         Item *child = new Item;
688         child->setParentItem(parent);
689         QCOMPARE(child->scene(), (QGraphicsScene *)0);
690         QCOMPARE(parent->scene(), (QGraphicsScene *)0);
691         scene.addItem(parent);
692         QCOMPARE(child->scene(), &scene);
693         scene.removeItem(child);
694         QCOMPARE(child->scene(), (QGraphicsScene *)0);
695         QCOMPARE(parent->scene(), &scene);
696         QCOMPARE(child->parentItem(), (QGraphicsItem *)0);
697         QVERIFY(parent->children().isEmpty());
698         delete parent;
699         QCOMPARE(itemDeleted, 5);
700         delete child;
701         QCOMPARE(itemDeleted, 6);
702     }
703     {
704         QGraphicsScene scene;
705         QGraphicsItem *parent = new QGraphicsRectItem;
706         Item *child = new Item;
707         child->setParentItem(parent);
708         scene.addItem(parent);
709         scene.removeItem(child);
710         scene.removeItem(parent);
711         delete child;
712         delete parent;
713         QCOMPARE(itemDeleted, 7);
714     }
715     {
716         QGraphicsScene scene;
717         QGraphicsItem *parent = new QGraphicsRectItem;
718         Item *child = new Item;
719         child->setParentItem(parent);
720         scene.addItem(parent);
721         QGraphicsScene scene2;
722         scene2.addItem(parent);
723         delete parent;
724         QCOMPARE(itemDeleted, 8);
725     }
726     {
727         QGraphicsScene scene;
728         QGraphicsItem *parent = new QGraphicsRectItem;
729         Item *child = new Item;
730         child->setParentItem(parent);
731         scene.addItem(parent);
732         QCOMPARE(child->scene(), &scene);
733         QGraphicsScene scene2;
734         scene2.addItem(parent);
735         QCOMPARE(child->scene(), &scene2);
736         scene.addItem(parent);
737         QCOMPARE(child->scene(), &scene);
738         scene2.addItem(parent);
739         QCOMPARE(child->scene(), &scene2);
740         delete parent;
741         QCOMPARE(itemDeleted, 9);
742     }
743     {
744         QGraphicsScene scene;
745         QGraphicsItem *parent = new QGraphicsRectItem;
746         Item *child = new Item;
747         child->setParentItem(parent);
748         scene.addItem(parent);
749         QCOMPARE(child->scene(), &scene);
750         QGraphicsScene scene2;
751         scene2.addItem(child);
752         QCOMPARE(child->scene(), &scene2);
753         delete parent;
754         QCOMPARE(itemDeleted, 9);
755         delete child;
756         QCOMPARE(itemDeleted, 10);
757     }
758     {
759         QGraphicsScene scene;
760         QGraphicsItem *root = new QGraphicsRectItem;
761         QGraphicsItem *parent = root;
762         QGraphicsItem *middleItem = 0;
763         for (int i = 0; i < 99; ++i) {
764             Item *child = new Item;
765             child->setParentItem(parent);
766             parent = child;
767             if (i == 50)
768                 middleItem = parent;
769         }
770         scene.addItem(root);
771
772         QCOMPARE(scene.items().size(), 100);
773
774         QGraphicsScene scene2;
775         scene2.addItem(middleItem);
776
777         delete middleItem;
778         QCOMPARE(itemDeleted, 59);
779     }
780     QCOMPARE(itemDeleted, 109);
781     {
782         QGraphicsScene *scene = new QGraphicsScene;
783         QGraphicsRectItem *parent = new QGraphicsRectItem;
784         Item *child = new Item;
785         child->setParentItem(parent);
786         parent->setVisible(false);
787         scene->addItem(parent);
788         QCOMPARE(child->parentItem(), static_cast<QGraphicsItem*>(parent));
789         delete scene;
790         QCOMPARE(itemDeleted, 110);
791     }
792 }
793
794 void tst_QGraphicsItem::deleteChildItem()
795 {
796     QGraphicsScene scene;
797     QGraphicsItem *rect = scene.addRect(QRectF());
798     QGraphicsItem *child1 = new QGraphicsRectItem(rect);
799     QGraphicsItem *child2 = new QGraphicsRectItem(rect);
800     QGraphicsItem *child3 = new QGraphicsRectItem(rect);
801     Q_UNUSED(child3);
802     delete child1;
803     child2->setParentItem(0);
804     delete child2;
805 }
806
807 void tst_QGraphicsItem::scene()
808 {
809     QGraphicsRectItem *item = new QGraphicsRectItem;
810     QCOMPARE(item->scene(), (QGraphicsScene *)0);
811
812     QGraphicsScene scene;
813     scene.addItem(item);
814     QCOMPARE(item->scene(), (QGraphicsScene *)&scene);
815
816     QGraphicsScene scene2;
817     scene2.addItem(item);
818     QCOMPARE(item->scene(), (QGraphicsScene *)&scene2);
819
820     scene2.removeItem(item);
821     QCOMPARE(item->scene(), (QGraphicsScene *)0);
822
823     delete item;
824 }
825
826 void tst_QGraphicsItem::parentItem()
827 {
828     QGraphicsRectItem item;
829     QCOMPARE(item.parentItem(), (QGraphicsItem *)0);
830
831     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
832     QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
833     item2->setParentItem(&item);
834     QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item);
835     item2->setParentItem(0);
836     QCOMPARE(item2->parentItem(), (QGraphicsItem *)0);
837
838     delete item2;
839 }
840
841 void tst_QGraphicsItem::setParentItem()
842 {
843     QGraphicsScene scene;
844     QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10));
845     QCOMPARE(item->scene(), &scene);
846
847     QGraphicsRectItem *child = new QGraphicsRectItem;
848     QCOMPARE(child->scene(), (QGraphicsScene *)0);
849
850     // This implicitly adds the item to the parent's scene
851     child->setParentItem(item);
852     QCOMPARE(child->scene(), &scene);
853
854     // This just makes it a toplevel
855     child->setParentItem(0);
856     QCOMPARE(child->scene(), &scene);
857
858     // Add the child back to the parent, then remove the parent from the scene
859     child->setParentItem(item);
860     scene.removeItem(item);
861     QCOMPARE(child->scene(), (QGraphicsScene *)0);
862 }
863
864 void tst_QGraphicsItem::children()
865 {
866     QGraphicsRectItem item;
867     QVERIFY(item.children().isEmpty());
868
869     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item);
870     QCOMPARE(item.children().size(), 1);
871     QCOMPARE(item.children().first(), (QGraphicsItem *)item2);
872     QVERIFY(item2->children().isEmpty());
873
874     delete item2;
875     QVERIFY(item.children().isEmpty());
876 }
877
878 void tst_QGraphicsItem::flags()
879 {
880     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
881     QCOMPARE(item->flags(), 0);
882
883     QGraphicsScene scene;
884     QEvent activate(QEvent::WindowActivate);
885     QApplication::sendEvent(&scene, &activate);
886
887     scene.addItem(item);
888
889     {
890         // Focus
891         item->setFlag(QGraphicsItem::ItemIsFocusable, false);
892         QVERIFY(!item->hasFocus());
893         item->setFocus();
894         QVERIFY(!item->hasFocus());
895
896         item->setFlag(QGraphicsItem::ItemIsFocusable, true);
897         QVERIFY(!item->hasFocus());
898         item->setFocus();
899         QVERIFY(item->hasFocus());
900         QVERIFY(scene.hasFocus());
901
902         item->setFlag(QGraphicsItem::ItemIsFocusable, false);
903         QVERIFY(!item->hasFocus());
904         QVERIFY(scene.hasFocus());
905     }
906     {
907         // Selectable
908         item->setFlag(QGraphicsItem::ItemIsSelectable, false);
909         QVERIFY(!item->isSelected());
910         item->setSelected(true);
911         QVERIFY(!item->isSelected());
912
913         item->setFlag(QGraphicsItem::ItemIsSelectable, true);
914         QVERIFY(!item->isSelected());
915         item->setSelected(true);
916         QVERIFY(item->isSelected());
917         item->setFlag(QGraphicsItem::ItemIsSelectable, false);
918         QVERIFY(!item->isSelected());
919     }
920     {
921         // Movable
922         item->setFlag(QGraphicsItem::ItemIsMovable, false);
923         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
924         event.setScenePos(QPointF(0, 0));
925         event.setButton(Qt::LeftButton);
926         event.setButtons(Qt::LeftButton);
927         QApplication::sendEvent(&scene, &event);
928         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); // mouse grabber is reset
929
930         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
931         event2.setScenePos(QPointF(10, 10));
932         event2.setButton(Qt::LeftButton);
933         event2.setButtons(Qt::LeftButton);
934         QApplication::sendEvent(&scene, &event2);
935         QCOMPARE(item->pos(), QPointF());
936
937         QGraphicsSceneMouseEvent event3(QEvent::GraphicsSceneMouseRelease);
938         event3.setScenePos(QPointF(10, 10));
939         event3.setButtons(0);
940         QApplication::sendEvent(&scene, &event3);
941         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
942
943         item->setFlag(QGraphicsItem::ItemIsMovable, true);
944         QGraphicsSceneMouseEvent event4(QEvent::GraphicsSceneMousePress);
945         event4.setScenePos(QPointF(0, 0));
946         event4.setButton(Qt::LeftButton);
947         event4.setButtons(Qt::LeftButton);
948         QApplication::sendEvent(&scene, &event4);
949         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
950         QGraphicsSceneMouseEvent event5(QEvent::GraphicsSceneMouseMove);
951         event5.setScenePos(QPointF(10, 10));
952         event5.setButton(Qt::LeftButton);
953         event5.setButtons(Qt::LeftButton);
954         QApplication::sendEvent(&scene, &event5);
955         QCOMPARE(item->pos(), QPointF(10, 10));
956     }
957     {
958         QGraphicsItem* clippingParent = new QGraphicsRectItem;
959         clippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
960
961         QGraphicsItem* nonClippingParent = new QGraphicsRectItem;
962         nonClippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
963
964         QGraphicsItem* child = new QGraphicsRectItem(nonClippingParent);
965         QVERIFY(!child->isClipped());
966
967         child->setParentItem(clippingParent);
968         QVERIFY(child->isClipped());
969
970         child->setParentItem(nonClippingParent);
971         QVERIFY(!child->isClipped());
972     }
973 }
974
975 class ImhTester : public QGraphicsItem
976 {
977     QRectF boundingRect() const { return QRectF(); }
978     void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
979 };
980
981 void tst_QGraphicsItem::inputMethodHints()
982 {
983     ImhTester *item = new ImhTester;
984     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
985     item->setFlag(QGraphicsItem::ItemIsFocusable, true);
986     QCOMPARE(item->inputMethodHints(), Qt::ImhNone);
987     ImhTester *item2 = new ImhTester;
988     item2->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
989     item2->setFlag(QGraphicsItem::ItemIsFocusable, true);
990     Qt::InputMethodHints imHints = item2->inputMethodHints();
991     imHints |= Qt::ImhHiddenText;
992     item2->setInputMethodHints(imHints);
993     QGraphicsScene scene;
994     scene.addItem(item);
995     scene.addItem(item2);
996     QGraphicsView view(&scene);
997     QApplication::setActiveWindow(&view);
998     view.show();
999     QVERIFY(QTest::qWaitForWindowActive(&view));
1000     item->setFocus();
1001     QTRY_VERIFY(item->hasFocus());
1002     QCOMPARE(view.inputMethodHints(), item->inputMethodHints());
1003     item2->setFocus();
1004     QTRY_VERIFY(item2->hasFocus());
1005     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1006     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, false);
1007     item->setFocus();
1008     QTRY_VERIFY(item->hasFocus());
1009     //Focus has changed but the new item doesn't accept input method, no hints.
1010     QCOMPARE(view.inputMethodHints(), 0);
1011     item2->setFocus();
1012     QTRY_VERIFY(item2->hasFocus());
1013     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1014     imHints = item2->inputMethodHints();
1015     imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
1016     item2->setInputMethodHints(imHints);
1017     QCOMPARE(view.inputMethodHints(), item2->inputMethodHints());
1018     QGraphicsProxyWidget *widget = new QGraphicsProxyWidget;
1019     QLineEdit *edit = new QLineEdit;
1020     edit->setEchoMode(QLineEdit::Password);
1021     scene.addItem(widget);
1022     widget->setFocus();
1023     QTRY_VERIFY(widget->hasFocus());
1024     //No widget on the proxy, so no hints
1025     QCOMPARE(view.inputMethodHints(), 0);
1026     widget->setWidget(edit);
1027     //View should match with the line edit
1028     QCOMPARE(view.inputMethodHints(), edit->inputMethodHints());
1029 }
1030
1031 void tst_QGraphicsItem::toolTip()
1032 {
1033     QString toolTip = "Qt rocks!";
1034
1035     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
1036     item->setPen(QPen(Qt::red, 1));
1037     item->setBrush(QBrush(Qt::blue));
1038     QVERIFY(item->toolTip().isEmpty());
1039     item->setToolTip(toolTip);
1040     QCOMPARE(item->toolTip(), toolTip);
1041
1042     QGraphicsScene scene;
1043     scene.addItem(item);
1044
1045     QGraphicsView view(&scene);
1046     view.setFixedSize(200, 200);
1047     view.show();
1048     QApplication::setActiveWindow(&view);
1049     QVERIFY(QTest::qWaitForWindowActive(&view));
1050     {
1051         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
1052                              view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
1053         QApplication::sendEvent(view.viewport(), &helpEvent);
1054         QTest::qWait(250);
1055
1056         bool foundView = false;
1057         bool foundTipLabel = false;
1058         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1059             if (widget == &view)
1060                 foundView = true;
1061             if (widget->inherits("QTipLabel"))
1062                 foundTipLabel = true;
1063         }
1064         QVERIFY(foundView);
1065         QVERIFY(!foundTipLabel);
1066     }
1067
1068     {
1069         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().center(),
1070                              view.viewport()->mapToGlobal(view.viewport()->rect().center()));
1071         QApplication::sendEvent(view.viewport(), &helpEvent);
1072         QTest::qWait(250);
1073
1074         bool foundView = false;
1075         bool foundTipLabel = false;
1076         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1077             if (widget == &view)
1078                 foundView = true;
1079             if (widget->inherits("QTipLabel"))
1080                 foundTipLabel = true;
1081         }
1082         QVERIFY(foundView);
1083         QVERIFY(foundTipLabel);
1084     }
1085
1086     {
1087         QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(),
1088                              view.viewport()->mapToGlobal(view.viewport()->rect().topLeft()));
1089         QApplication::sendEvent(view.viewport(), &helpEvent);
1090         QTest::qWait(1000);
1091
1092         bool foundView = false;
1093         bool foundTipLabel = false;
1094         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1095             if (widget == &view)
1096                 foundView = true;
1097             if (widget->inherits("QTipLabel") && widget->isVisible())
1098                 foundTipLabel = true;
1099         }
1100         QVERIFY(foundView);
1101         QVERIFY(!foundTipLabel);
1102     }
1103 }
1104
1105 void tst_QGraphicsItem::visible()
1106 {
1107     QGraphicsItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
1108     item->setFlag(QGraphicsItem::ItemIsMovable);
1109     QVERIFY(item->isVisible());
1110     item->setVisible(false);
1111     QVERIFY(!item->isVisible());
1112     item->setVisible(true);
1113     QVERIFY(item->isVisible());
1114
1115     QGraphicsScene scene;
1116     QEvent activate(QEvent::WindowActivate);
1117     QApplication::sendEvent(&scene, &activate);
1118
1119     scene.addItem(item);
1120     QVERIFY(item->isVisible());
1121     QCOMPARE(scene.itemAt(0, 0), item);
1122     item->setVisible(false);
1123     QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)0);
1124     item->setVisible(true);
1125     QCOMPARE(scene.itemAt(0, 0), item);
1126
1127     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1128     event.setButton(Qt::LeftButton);
1129     event.setScenePos(QPointF(0, 0));
1130     QApplication::sendEvent(&scene, &event);
1131     QCOMPARE(scene.mouseGrabberItem(), item);
1132     item->setVisible(false);
1133     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1134     item->setVisible(true);
1135     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1136
1137     item->setFlag(QGraphicsItem::ItemIsFocusable);
1138     item->setFocus();
1139     QVERIFY(item->hasFocus());
1140     item->setVisible(false);
1141     QVERIFY(!item->hasFocus());
1142     item->setVisible(true);
1143     QVERIFY(!item->hasFocus());
1144 }
1145
1146 void tst_QGraphicsItem::isVisibleTo()
1147 {
1148     QGraphicsScene scene;
1149     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1150     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1151     QGraphicsItem *grandChild = scene.addRect(QRectF(50, 50, 50, 50));
1152     QGraphicsItem *stranger = scene.addRect(100, 100, 100, 100);
1153
1154     child->setParentItem(parent);
1155     grandChild->setParentItem(child);
1156
1157     QVERIFY(grandChild->isVisible());
1158     QVERIFY(grandChild->isVisibleTo(grandChild));
1159     QVERIFY(grandChild->isVisibleTo(child));
1160     QVERIFY(grandChild->isVisibleTo(parent));
1161     QVERIFY(grandChild->isVisibleTo(0));
1162     QVERIFY(child->isVisible());
1163     QVERIFY(child->isVisibleTo(child));
1164     QVERIFY(child->isVisibleTo(parent));
1165     QVERIFY(child->isVisibleTo(0));
1166     QVERIFY(parent->isVisible());
1167     QVERIFY(parent->isVisibleTo(parent));
1168     QVERIFY(parent->isVisibleTo(0));
1169     QVERIFY(!parent->isVisibleTo(child));
1170     QVERIFY(!child->isVisibleTo(grandChild));
1171     QVERIFY(!grandChild->isVisibleTo(stranger));
1172     QVERIFY(!child->isVisibleTo(stranger));
1173     QVERIFY(!parent->isVisibleTo(stranger));
1174     QVERIFY(!stranger->isVisibleTo(grandChild));
1175     QVERIFY(!stranger->isVisibleTo(child));
1176     QVERIFY(!stranger->isVisibleTo(parent));
1177
1178     // Case 1: only parent is explicitly hidden
1179     parent->hide();
1180
1181     QVERIFY(!grandChild->isVisible());
1182     QVERIFY(grandChild->isVisibleTo(grandChild));
1183     QVERIFY(grandChild->isVisibleTo(child));
1184     QVERIFY(grandChild->isVisibleTo(parent));
1185     QVERIFY(!grandChild->isVisibleTo(0));
1186     QVERIFY(!child->isVisible());
1187     QVERIFY(child->isVisibleTo(child));
1188     QVERIFY(child->isVisibleTo(parent));
1189     QVERIFY(!child->isVisibleTo(0));
1190     QVERIFY(!parent->isVisible());
1191     QVERIFY(!parent->isVisibleTo(parent));
1192     QVERIFY(!parent->isVisibleTo(0));
1193     QVERIFY(!parent->isVisibleTo(child));
1194     QVERIFY(!child->isVisibleTo(grandChild));
1195     QVERIFY(!grandChild->isVisibleTo(stranger));
1196     QVERIFY(!child->isVisibleTo(stranger));
1197     QVERIFY(!parent->isVisibleTo(stranger));
1198     QVERIFY(!stranger->isVisibleTo(grandChild));
1199     QVERIFY(!stranger->isVisibleTo(child));
1200     QVERIFY(!stranger->isVisibleTo(parent));
1201
1202     // Case 2: only child is hidden
1203     parent->show();
1204     child->hide();
1205
1206     QVERIFY(!grandChild->isVisible());
1207     QVERIFY(grandChild->isVisibleTo(grandChild));
1208     QVERIFY(grandChild->isVisibleTo(child));
1209     QVERIFY(!grandChild->isVisibleTo(parent));
1210     QVERIFY(!grandChild->isVisibleTo(0));
1211     QVERIFY(!child->isVisible());
1212     QVERIFY(!child->isVisibleTo(child));
1213     QVERIFY(!child->isVisibleTo(parent));
1214     QVERIFY(!child->isVisibleTo(0));
1215     QVERIFY(parent->isVisible());
1216     QVERIFY(parent->isVisibleTo(parent));
1217     QVERIFY(parent->isVisibleTo(0));
1218     QVERIFY(!parent->isVisibleTo(child));
1219     QVERIFY(!child->isVisibleTo(grandChild));
1220     QVERIFY(!grandChild->isVisibleTo(stranger));
1221     QVERIFY(!child->isVisibleTo(stranger));
1222     QVERIFY(!parent->isVisibleTo(stranger));
1223     QVERIFY(!stranger->isVisibleTo(grandChild));
1224     QVERIFY(!stranger->isVisibleTo(child));
1225     QVERIFY(!stranger->isVisibleTo(parent));
1226
1227     // Case 3: only grand child is hidden
1228     child->show();
1229     grandChild->hide();
1230
1231     QVERIFY(!grandChild->isVisible());
1232     QVERIFY(!grandChild->isVisibleTo(grandChild));
1233     QVERIFY(!grandChild->isVisibleTo(child));
1234     QVERIFY(!grandChild->isVisibleTo(parent));
1235     QVERIFY(!grandChild->isVisibleTo(0));
1236     QVERIFY(child->isVisible());
1237     QVERIFY(child->isVisibleTo(child));
1238     QVERIFY(child->isVisibleTo(parent));
1239     QVERIFY(child->isVisibleTo(0));
1240     QVERIFY(parent->isVisible());
1241     QVERIFY(parent->isVisibleTo(parent));
1242     QVERIFY(parent->isVisibleTo(0));
1243     QVERIFY(!parent->isVisibleTo(child));
1244     QVERIFY(!child->isVisibleTo(grandChild));
1245     QVERIFY(!grandChild->isVisibleTo(stranger));
1246     QVERIFY(!child->isVisibleTo(stranger));
1247     QVERIFY(!parent->isVisibleTo(stranger));
1248     QVERIFY(!stranger->isVisibleTo(grandChild));
1249     QVERIFY(!stranger->isVisibleTo(child));
1250     QVERIFY(!stranger->isVisibleTo(parent));
1251 }
1252
1253 void tst_QGraphicsItem::explicitlyVisible()
1254 {
1255     QGraphicsScene scene;
1256     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1257     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1258     child->setParentItem(parent);
1259
1260     QVERIFY(parent->isVisible());
1261     QVERIFY(child->isVisible());
1262
1263     parent->hide();
1264
1265     QVERIFY(!parent->isVisible());
1266     QVERIFY(!child->isVisible());
1267
1268     parent->show();
1269     child->hide();
1270
1271     QVERIFY(parent->isVisible());
1272     QVERIFY(!child->isVisible());
1273
1274     parent->hide();
1275
1276     QVERIFY(!parent->isVisible());
1277     QVERIFY(!child->isVisible());
1278
1279     parent->show();
1280
1281     QVERIFY(parent->isVisible());
1282     QVERIFY(!child->isVisible()); // <- explicitly hidden
1283
1284     child->show();
1285
1286     QVERIFY(child->isVisible());
1287
1288     parent->hide();
1289
1290     QVERIFY(!parent->isVisible());
1291     QVERIFY(!child->isVisible()); // <- explicit show doesn't work
1292
1293     parent->show();
1294
1295     QVERIFY(parent->isVisible());
1296     QVERIFY(child->isVisible()); // <- no longer explicitly hidden
1297
1298     // ------------------- Reparenting ------------------------------
1299
1300     QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
1301     QVERIFY(parent2->isVisible());
1302
1303     // Reparent implicitly hidden item to a visible parent.
1304     parent->hide();
1305     QVERIFY(!parent->isVisible());
1306     QVERIFY(!child->isVisible());
1307     child->setParentItem(parent2);
1308     QVERIFY(parent2->isVisible());
1309     QVERIFY(child->isVisible());
1310
1311     // Reparent implicitly hidden item to a hidden parent.
1312     child->setParentItem(parent);
1313     parent2->hide();
1314     child->setParentItem(parent2);
1315     QVERIFY(!parent2->isVisible());
1316     QVERIFY(!child->isVisible());
1317
1318     // Reparent explicitly hidden item to a visible parent.
1319     child->hide();
1320     parent->show();
1321     child->setParentItem(parent);
1322     QVERIFY(parent->isVisible());
1323     QVERIFY(!child->isVisible());
1324
1325     // Reparent explicitly hidden item to a hidden parent.
1326     child->setParentItem(parent2);
1327     QVERIFY(!parent2->isVisible());
1328     QVERIFY(!child->isVisible());
1329
1330     // Reparent explicitly hidden item to a visible parent.
1331     parent->show();
1332     child->setParentItem(parent);
1333     QVERIFY(parent->isVisible());
1334     QVERIFY(!child->isVisible());
1335
1336     // Reparent visible item to a hidden parent.
1337     child->show();
1338     parent2->hide();
1339     child->setParentItem(parent2);
1340     QVERIFY(!parent2->isVisible());
1341     QVERIFY(!child->isVisible());
1342     parent2->show();
1343     QVERIFY(parent2->isVisible());
1344     QVERIFY(child->isVisible());
1345
1346     // Reparent implicitly hidden child to root.
1347     parent2->hide();
1348     QVERIFY(!child->isVisible());
1349     child->setParentItem(0);
1350     QVERIFY(child->isVisible());
1351
1352     // Reparent an explicitly hidden child to root.
1353     child->hide();
1354     child->setParentItem(parent2);
1355     parent2->show();
1356     QVERIFY(!child->isVisible());
1357     child->setParentItem(0);
1358     QVERIFY(!child->isVisible());
1359 }
1360
1361 void tst_QGraphicsItem::enabled()
1362 {
1363     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20));
1364     item->setFlag(QGraphicsItem::ItemIsMovable);
1365     QVERIFY(item->isEnabled());
1366     item->setEnabled(false);
1367     QVERIFY(!item->isEnabled());
1368     item->setEnabled(true);
1369     QVERIFY(item->isEnabled());
1370     item->setEnabled(false);
1371     item->setFlag(QGraphicsItem::ItemIsFocusable);
1372     QGraphicsScene scene;
1373     QEvent activate(QEvent::WindowActivate);
1374     QApplication::sendEvent(&scene, &activate);
1375
1376     scene.addItem(item);
1377     item->setFocus();
1378     QVERIFY(!item->hasFocus());
1379     item->setEnabled(true);
1380     item->setFocus();
1381     QVERIFY(item->hasFocus());
1382     item->setEnabled(false);
1383     QVERIFY(!item->hasFocus());
1384
1385     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1386     event.setButton(Qt::LeftButton);
1387     event.setScenePos(QPointF(0, 0));
1388     QApplication::sendEvent(&scene, &event);
1389     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1390     item->setEnabled(true);
1391     QApplication::sendEvent(&scene, &event);
1392     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
1393     item->setEnabled(false);
1394     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1395 }
1396
1397 void tst_QGraphicsItem::explicitlyEnabled()
1398 {
1399     QGraphicsScene scene;
1400     QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
1401     QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50));
1402     child->setParentItem(parent);
1403
1404     QVERIFY(parent->isEnabled());
1405     QVERIFY(child->isEnabled());
1406
1407     parent->setEnabled(false);
1408
1409     QVERIFY(!parent->isEnabled());
1410     QVERIFY(!child->isEnabled());
1411
1412     parent->setEnabled(true);
1413     child->setEnabled(false);
1414
1415     QVERIFY(parent->isEnabled());
1416     QVERIFY(!child->isEnabled());
1417
1418     parent->setEnabled(false);
1419
1420     QVERIFY(!parent->isEnabled());
1421     QVERIFY(!child->isEnabled());
1422
1423     parent->setEnabled(true);
1424
1425     QVERIFY(parent->isEnabled());
1426     QVERIFY(!child->isEnabled()); // <- explicitly disabled
1427
1428     child->setEnabled(true);
1429
1430     QVERIFY(child->isEnabled());
1431
1432     parent->setEnabled(false);
1433
1434     QVERIFY(!parent->isEnabled());
1435     QVERIFY(!child->isEnabled()); // <- explicit enabled doesn't work
1436
1437     parent->setEnabled(true);
1438
1439     QVERIFY(parent->isEnabled());
1440     QVERIFY(child->isEnabled()); // <- no longer explicitly disabled
1441
1442     // ------------------- Reparenting ------------------------------
1443
1444     QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200);
1445     QVERIFY(parent2->isEnabled());
1446
1447     // Reparent implicitly hidden item to a enabled parent.
1448     parent->setEnabled(false);
1449     QVERIFY(!parent->isEnabled());
1450     QVERIFY(!child->isEnabled());
1451     child->setParentItem(parent2);
1452     QVERIFY(parent2->isEnabled());
1453     QVERIFY(child->isEnabled());
1454
1455     // Reparent implicitly hidden item to a hidden parent.
1456     child->setParentItem(parent);
1457     parent2->setEnabled(false);
1458     child->setParentItem(parent2);
1459     QVERIFY(!parent2->isEnabled());
1460     QVERIFY(!child->isEnabled());
1461
1462     // Reparent explicitly hidden item to a enabled parent.
1463     child->setEnabled(false);
1464     parent->setEnabled(true);
1465     child->setParentItem(parent);
1466     QVERIFY(parent->isEnabled());
1467     QVERIFY(!child->isEnabled());
1468
1469     // Reparent explicitly hidden item to a hidden parent.
1470     child->setParentItem(parent2);
1471     QVERIFY(!parent2->isEnabled());
1472     QVERIFY(!child->isEnabled());
1473
1474     // Reparent explicitly hidden item to a enabled parent.
1475     parent->setEnabled(true);
1476     child->setParentItem(parent);
1477     QVERIFY(parent->isEnabled());
1478     QVERIFY(!child->isEnabled());
1479
1480     // Reparent enabled item to a hidden parent.
1481     child->setEnabled(true);
1482     parent2->setEnabled(false);
1483     child->setParentItem(parent2);
1484     QVERIFY(!parent2->isEnabled());
1485     QVERIFY(!child->isEnabled());
1486     parent2->setEnabled(true);
1487     QVERIFY(parent2->isEnabled());
1488     QVERIFY(child->isEnabled());
1489
1490     // Reparent implicitly hidden child to root.
1491     parent2->setEnabled(false);
1492     QVERIFY(!child->isEnabled());
1493     child->setParentItem(0);
1494     QVERIFY(child->isEnabled());
1495
1496     // Reparent an explicitly hidden child to root.
1497     child->setEnabled(false);
1498     child->setParentItem(parent2);
1499     parent2->setEnabled(true);
1500     QVERIFY(!child->isEnabled());
1501     child->setParentItem(0);
1502     QVERIFY(!child->isEnabled());
1503 }
1504
1505 class SelectChangeItem : public QGraphicsRectItem
1506 {
1507 public:
1508     SelectChangeItem() : QGraphicsRectItem(-50, -50, 100, 100) { setBrush(Qt::blue); }
1509     QList<bool> values;
1510
1511 protected:
1512     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
1513     {
1514         if (change == ItemSelectedChange)
1515             values << value.toBool();
1516         return QGraphicsRectItem::itemChange(change, value);
1517     }
1518 };
1519
1520 void tst_QGraphicsItem::selected()
1521 {
1522     SelectChangeItem *item = new SelectChangeItem;
1523     item->setFlag(QGraphicsItem::ItemIsSelectable);
1524     QVERIFY(!item->isSelected());
1525     QVERIFY(item->values.isEmpty());
1526     item->setSelected(true);
1527     QCOMPARE(item->values.size(), 1);
1528     QCOMPARE(item->values.last(), true);
1529     QVERIFY(item->isSelected());
1530     item->setSelected(false);
1531     QCOMPARE(item->values.size(), 2);
1532     QCOMPARE(item->values.last(), false);
1533     QVERIFY(!item->isSelected());
1534     item->setSelected(true);
1535     QCOMPARE(item->values.size(), 3);
1536     item->setEnabled(false);
1537     QCOMPARE(item->values.size(), 4);
1538     QCOMPARE(item->values.last(), false);
1539     QVERIFY(!item->isSelected());
1540     item->setEnabled(true);
1541     QCOMPARE(item->values.size(), 4);
1542     item->setSelected(true);
1543     QCOMPARE(item->values.size(), 5);
1544     QCOMPARE(item->values.last(), true);
1545     QVERIFY(item->isSelected());
1546     item->setVisible(false);
1547     QCOMPARE(item->values.size(), 6);
1548     QCOMPARE(item->values.last(), false);
1549     QVERIFY(!item->isSelected());
1550     item->setVisible(true);
1551     QCOMPARE(item->values.size(), 6);
1552     item->setSelected(true);
1553     QCOMPARE(item->values.size(), 7);
1554     QCOMPARE(item->values.last(), true);
1555     QVERIFY(item->isSelected());
1556
1557     QGraphicsScene scene(-100, -100, 200, 200);
1558     scene.addItem(item);
1559     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
1560     item->setSelected(false);
1561     QVERIFY(scene.selectedItems().isEmpty());
1562     item->setSelected(true);
1563     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item);
1564     item->setSelected(false);
1565     QVERIFY(scene.selectedItems().isEmpty());
1566
1567     // Interactive selection
1568     QGraphicsView view(&scene);
1569     view.setFixedSize(250, 250);
1570     view.show();
1571
1572     QVERIFY(QTest::qWaitForWindowExposed(&view));
1573     qApp->processEvents();
1574     qApp->processEvents();
1575
1576     scene.clearSelection();
1577     QCOMPARE(item->values.size(), 10);
1578     QCOMPARE(item->values.last(), false);
1579     QVERIFY(!item->isSelected());
1580
1581     // Click inside and check that it's selected
1582     QTest::mouseMove(view.viewport());
1583     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
1584     QCOMPARE(item->values.size(), 11);
1585     QCOMPARE(item->values.last(), true);
1586     QVERIFY(item->isSelected());
1587
1588     // Click outside and check that it's not selected
1589     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos() + QPointF(item->boundingRect().width(), item->boundingRect().height())));
1590     QCOMPARE(item->values.size(), 12);
1591     QCOMPARE(item->values.last(), false);
1592     QVERIFY(!item->isSelected());
1593
1594     SelectChangeItem *item2 = new SelectChangeItem;
1595     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1596     item2->setPos(100, 0);
1597     scene.addItem(item2);
1598
1599     // Click inside and check that it's selected
1600     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
1601     QCOMPARE(item->values.size(), 13);
1602     QCOMPARE(item->values.last(), true);
1603     QVERIFY(item->isSelected());
1604
1605     // Click inside item2 and check that it's selected, and item is not
1606     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1607     QCOMPARE(item->values.size(), 14);
1608     QCOMPARE(item->values.last(), false);
1609     QVERIFY(!item->isSelected());
1610     QCOMPARE(item2->values.size(), 1);
1611     QCOMPARE(item2->values.last(), true);
1612     QVERIFY(item2->isSelected());
1613 }
1614
1615 void tst_QGraphicsItem::selected2()
1616 {
1617     // Selecting an item, then moving another previously caused a crash.
1618     QGraphicsScene scene;
1619     QGraphicsItem *line1 = scene.addRect(QRectF(0, 0, 100, 100));
1620     line1->setPos(-105, 0);
1621     line1->setFlag(QGraphicsItem::ItemIsSelectable);
1622
1623     QGraphicsItem *line2 = scene.addRect(QRectF(0, 0, 100, 100));
1624     line2->setFlag(QGraphicsItem::ItemIsMovable);
1625
1626     line1->setSelected(true);
1627
1628     {
1629         QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
1630         mousePress.setScenePos(QPointF(50, 50));
1631         mousePress.setButton(Qt::LeftButton);
1632         QApplication::sendEvent(&scene, &mousePress);
1633         QVERIFY(mousePress.isAccepted());
1634     }
1635     {
1636         QGraphicsSceneMouseEvent mouseMove(QEvent::GraphicsSceneMouseMove);
1637         mouseMove.setScenePos(QPointF(60, 60));
1638         mouseMove.setButton(Qt::LeftButton);
1639         mouseMove.setButtons(Qt::LeftButton);
1640         QApplication::sendEvent(&scene, &mouseMove);
1641         QVERIFY(mouseMove.isAccepted());
1642     }
1643 }
1644
1645 void tst_QGraphicsItem::selected_group()
1646 {
1647     QGraphicsScene scene;
1648     QGraphicsItem *item1 = scene.addRect(QRectF());
1649     QGraphicsItem *item2 = scene.addRect(QRectF());
1650     item1->setFlag(QGraphicsItem::ItemIsSelectable);
1651     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1652     scene.addRect(QRectF())->setParentItem(item1);
1653     QGraphicsItem *leaf = scene.addRect(QRectF());
1654     leaf->setFlag(QGraphicsItem::ItemIsSelectable);
1655     leaf->setParentItem(item2);
1656
1657     QGraphicsItemGroup *group = scene.createItemGroup(QList<QGraphicsItem *>() << item1 << item2);
1658     QCOMPARE(group->scene(), &scene);
1659     group->setFlag(QGraphicsItem::ItemIsSelectable);
1660     foreach (QGraphicsItem *item, scene.items()) {
1661         if (item == group)
1662             QVERIFY(!item->group());
1663         else
1664             QCOMPARE(item->group(), group);
1665     }
1666
1667     QVERIFY(group->handlesChildEvents());
1668     QVERIFY(!group->isSelected());
1669     group->setSelected(false);
1670     QVERIFY(!group->isSelected());
1671     group->setSelected(true);
1672     QVERIFY(group->isSelected());
1673     foreach (QGraphicsItem *item, scene.items())
1674         QVERIFY(item->isSelected());
1675     group->setSelected(false);
1676     QVERIFY(!group->isSelected());
1677     foreach (QGraphicsItem *item, scene.items())
1678         QVERIFY(!item->isSelected());
1679     leaf->setSelected(true);
1680     foreach (QGraphicsItem *item, scene.items())
1681         QVERIFY(item->isSelected());
1682     leaf->setSelected(false);
1683     foreach (QGraphicsItem *item, scene.items())
1684         QVERIFY(!item->isSelected());
1685
1686     leaf->setSelected(true);
1687     QGraphicsScene scene2;
1688     scene2.addItem(item1);
1689     QVERIFY(!item1->isSelected());
1690     QVERIFY(item2->isSelected());
1691 }
1692
1693 void tst_QGraphicsItem::selected_textItem()
1694 {
1695     QGraphicsScene scene;
1696     QGraphicsTextItem *text = scene.addText(QLatin1String("Text"));
1697     text->setFlag(QGraphicsItem::ItemIsSelectable);
1698
1699     QGraphicsView view(&scene);
1700     view.show();
1701     QVERIFY(QTest::qWaitForWindowExposed(&view));
1702     QTest::qWait(20);
1703
1704     QTRY_VERIFY(!text->isSelected());
1705     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
1706                       view.mapFromScene(text->mapToScene(0, 0)));
1707     QTRY_VERIFY(text->isSelected());
1708
1709     text->setSelected(false);
1710     text->setTextInteractionFlags(Qt::TextEditorInteraction);
1711
1712     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
1713                       view.mapFromScene(text->mapToScene(0, 0)));
1714     QTRY_VERIFY(text->isSelected());
1715 }
1716
1717 void tst_QGraphicsItem::selected_multi()
1718 {
1719     // Test multiselection behavior
1720     QGraphicsScene scene;
1721
1722     // Create two disjoint items
1723     QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
1724     QGraphicsItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
1725     item1->setPos(-15, 0);
1726     item2->setPos(15, 20);
1727
1728     // Make both items selectable
1729     item1->setFlag(QGraphicsItem::ItemIsSelectable);
1730     item2->setFlag(QGraphicsItem::ItemIsSelectable);
1731
1732     // Create and show a view
1733     QGraphicsView view(&scene);
1734     view.show();
1735     view.fitInView(scene.sceneRect());
1736     qApp->processEvents();
1737
1738     QVERIFY(!item1->isSelected());
1739     QVERIFY(!item2->isSelected());
1740
1741     // Start clicking
1742     QTest::qWait(200);
1743
1744     // Click on item1
1745     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1746     QTest::qWait(20);
1747     QVERIFY(item1->isSelected());
1748     QVERIFY(!item2->isSelected());
1749
1750     // Click on item2
1751     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1752     QTest::qWait(20);
1753     QVERIFY(item2->isSelected());
1754     QVERIFY(!item1->isSelected());
1755
1756     // Ctrl-click on item1
1757     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1758     QTest::qWait(20);
1759     QVERIFY(item2->isSelected());
1760     QVERIFY(item1->isSelected());
1761
1762     // Ctrl-click on item1 again
1763     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1764     QTest::qWait(20);
1765     QVERIFY(item2->isSelected());
1766     QVERIFY(!item1->isSelected());
1767
1768     // Ctrl-click on item2
1769     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item2->scenePos()));
1770     QTest::qWait(20);
1771     QVERIFY(!item2->isSelected());
1772     QVERIFY(!item1->isSelected());
1773
1774     // Click on item1
1775     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1776     QTest::qWait(20);
1777     QVERIFY(item1->isSelected());
1778     QVERIFY(!item2->isSelected());
1779
1780     // Click on scene
1781     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(0, 0));
1782     QTest::qWait(20);
1783     QVERIFY(!item1->isSelected());
1784     QVERIFY(!item2->isSelected());
1785
1786     // Click on item1
1787     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1788     QTest::qWait(20);
1789     QVERIFY(item1->isSelected());
1790     QVERIFY(!item2->isSelected());
1791
1792     // Ctrl-click on scene
1793     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(0, 0));
1794     QTest::qWait(20);
1795     QVERIFY(!item1->isSelected());
1796     QVERIFY(!item2->isSelected());
1797
1798     // Click on item1
1799     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1800     QTest::qWait(20);
1801     QVERIFY(item1->isSelected());
1802     QVERIFY(!item2->isSelected());
1803
1804     // Press on item2
1805     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1806     QTest::qWait(20);
1807     QVERIFY(!item1->isSelected());
1808     QVERIFY(item2->isSelected());
1809
1810     // Release on item2
1811     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos()));
1812     QTest::qWait(20);
1813     QVERIFY(!item1->isSelected());
1814     QVERIFY(item2->isSelected());
1815
1816     // Click on item1
1817     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos()));
1818     QTest::qWait(20);
1819     QVERIFY(item1->isSelected());
1820     QVERIFY(!item2->isSelected());
1821
1822     // Ctrl-click on item1
1823     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1824     QTest::qWait(20);
1825     QVERIFY(!item1->isSelected());
1826     QVERIFY(!item2->isSelected());
1827
1828     // Ctrl-press on item1
1829     QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1830     QTest::qWait(20);
1831     QVERIFY(!item1->isSelected());
1832     QVERIFY(!item2->isSelected());
1833
1834     {
1835         // Ctrl-move on item1
1836         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
1837         QApplication::sendEvent(view.viewport(), &event);
1838         QTest::qWait(20);
1839         QVERIFY(!item1->isSelected());
1840         QVERIFY(!item2->isSelected());
1841     }
1842
1843     // Release on item1
1844     QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1845     QTest::qWait(20);
1846     QVERIFY(item1->isSelected());
1847     QVERIFY(!item2->isSelected());
1848
1849     item1->setFlag(QGraphicsItem::ItemIsMovable);
1850     item1->setSelected(false);
1851
1852     // Ctrl-press on item1
1853     QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1854     QTest::qWait(20);
1855     QVERIFY(!item1->isSelected());
1856     QVERIFY(!item2->isSelected());
1857
1858     {
1859         // Ctrl-move on item1
1860         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier);
1861         QApplication::sendEvent(view.viewport(), &event);
1862         QTest::qWait(20);
1863         QVERIFY(item1->isSelected());
1864         QVERIFY(!item2->isSelected());
1865     }
1866
1867     // Release on item1
1868     QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos()));
1869     QTest::qWait(20);
1870     QVERIFY(item1->isSelected());
1871     QVERIFY(!item2->isSelected());
1872 }
1873
1874 void tst_QGraphicsItem::acceptedMouseButtons()
1875 {
1876     QGraphicsScene scene;
1877     QGraphicsRectItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20));
1878     QGraphicsRectItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20));
1879     item2->setZValue(1);
1880
1881     item1->setFlag(QGraphicsItem::ItemIsMovable);
1882     item2->setFlag(QGraphicsItem::ItemIsMovable);
1883
1884     QCOMPARE(item1->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
1885     QCOMPARE(item2->acceptedMouseButtons(), Qt::MouseButtons(0x1f));
1886
1887     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
1888     event.setButton(Qt::LeftButton);
1889     event.setScenePos(QPointF(0, 0));
1890     QApplication::sendEvent(&scene, &event);
1891     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item2);
1892     item2->setAcceptedMouseButtons(0);
1893     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
1894     QApplication::sendEvent(&scene, &event);
1895     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item1);
1896 }
1897
1898 class HoverItem : public QGraphicsRectItem
1899 {
1900 public:
1901     HoverItem(const QRectF &rect)
1902         : QGraphicsRectItem(rect), hoverInCount(0),
1903           hoverMoveCount(0), hoverOutCount(0)
1904     { }
1905
1906     int hoverInCount;
1907     int hoverMoveCount;
1908     int hoverOutCount;
1909 protected:
1910     void hoverEnterEvent(QGraphicsSceneHoverEvent *)
1911     { ++hoverInCount; }
1912
1913     void hoverMoveEvent(QGraphicsSceneHoverEvent *)
1914     { ++hoverMoveCount; }
1915
1916     void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
1917     { ++hoverOutCount; }
1918 };
1919
1920 void tst_QGraphicsItem::acceptsHoverEvents()
1921 {
1922     QGraphicsScene scene;
1923     HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
1924     HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
1925     scene.addItem(item1);
1926     scene.addItem(item2);
1927     item2->setZValue(1);
1928
1929     QVERIFY(!item1->acceptsHoverEvents());
1930     QVERIFY(!item2->acceptsHoverEvents());
1931     item1->setAcceptsHoverEvents(true);
1932     item2->setAcceptsHoverEvents(true);
1933
1934     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
1935     event.setScenePos(QPointF(-100, -100));
1936     QApplication::sendEvent(&scene, &event);
1937     event.setScenePos(QPointF(-2.5, -2.5));
1938     QApplication::sendEvent(&scene, &event);
1939
1940     QCOMPARE(item1->hoverInCount, 0);
1941     QCOMPARE(item2->hoverInCount, 1);
1942
1943     item1->setAcceptsHoverEvents(false);
1944     item2->setAcceptsHoverEvents(false);
1945
1946     event.setScenePos(QPointF(-100, -100));
1947     QApplication::sendEvent(&scene, &event);
1948     event.setScenePos(QPointF(-2.5, -2.5));
1949     QApplication::sendEvent(&scene, &event);
1950
1951     QCOMPARE(item1->hoverInCount, 0);
1952     QCOMPARE(item2->hoverInCount, 1);
1953
1954     item1->setAcceptsHoverEvents(true);
1955     item2->setAcceptsHoverEvents(false);
1956
1957     event.setScenePos(QPointF(-100, -100));
1958     QApplication::sendEvent(&scene, &event);
1959     event.setScenePos(QPointF(-2.5, -2.5));
1960     QApplication::sendEvent(&scene, &event);
1961
1962     QCOMPARE(item1->hoverInCount, 1);
1963     QCOMPARE(item2->hoverInCount, 1);
1964 }
1965
1966 void tst_QGraphicsItem::childAcceptsHoverEvents()
1967 {
1968     QGraphicsScene scene;
1969     HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20));
1970     HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10));
1971
1972     scene.addItem(item1);
1973     scene.addItem(item2);
1974     item2->setParentItem(item1);
1975     item2->setAcceptHoverEvents(true);
1976
1977     QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
1978     event.setScenePos(QPointF(-100, -100));
1979     QApplication::sendEvent(&scene, &event);
1980     QCOMPARE(item2->hoverInCount, 0);
1981     QCOMPARE(item2->hoverMoveCount, 0);
1982     QCOMPARE(item2->hoverOutCount, 0);
1983     QCOMPARE(item1->hoverInCount, 0);
1984     QCOMPARE(item1->hoverMoveCount, 0);
1985     QCOMPARE(item1->hoverOutCount, 0);
1986
1987     event.setScenePos(QPointF(-2.5, -2.5));
1988     QApplication::sendEvent(&scene, &event);
1989
1990     QCOMPARE(item2->hoverInCount, 1);
1991     QCOMPARE(item2->hoverMoveCount, 1);
1992     QCOMPARE(item2->hoverOutCount, 0);
1993     QCOMPARE(item1->hoverInCount, 0);
1994     QCOMPARE(item1->hoverMoveCount, 0);
1995     QCOMPARE(item1->hoverOutCount, 0);
1996
1997     event.setScenePos(QPointF(0, 0));
1998     QApplication::sendEvent(&scene, &event);
1999
2000     QCOMPARE(item2->hoverInCount, 1);
2001     QCOMPARE(item2->hoverMoveCount, 2);
2002     QCOMPARE(item2->hoverOutCount, 0);
2003     QCOMPARE(item1->hoverInCount, 0);
2004     QCOMPARE(item1->hoverMoveCount, 0);
2005     QCOMPARE(item1->hoverOutCount, 0);
2006
2007     event.setScenePos(QPointF(-7, -7));
2008     QApplication::sendEvent(&scene, &event);
2009
2010     QCOMPARE(item2->hoverInCount, 1);
2011     QCOMPARE(item2->hoverMoveCount, 2);
2012     QCOMPARE(item2->hoverOutCount, 1);
2013     QCOMPARE(item1->hoverInCount, 0);
2014     QCOMPARE(item1->hoverMoveCount, 0);
2015     QCOMPARE(item1->hoverOutCount, 0);
2016
2017     event.setScenePos(QPointF(0, 0));
2018     QApplication::sendEvent(&scene, &event);
2019
2020     QCOMPARE(item2->hoverInCount, 2);
2021     QCOMPARE(item2->hoverMoveCount, 3);
2022     QCOMPARE(item2->hoverOutCount, 1);
2023     QCOMPARE(item1->hoverInCount, 0);
2024     QCOMPARE(item1->hoverMoveCount, 0);
2025     QCOMPARE(item1->hoverOutCount, 0);
2026
2027     HoverItem *item0 = new HoverItem(QRectF(-20, -20, 20, 20));
2028     scene.addItem(item0);
2029     item1->setParentItem(item0);
2030     item0->setAcceptHoverEvents(true);
2031
2032     event.setScenePos(QPointF(-100, -100));
2033     QApplication::sendEvent(&scene, &event);
2034
2035     event.setScenePos(QPointF(-15, -15));
2036     QApplication::sendEvent(&scene, &event);
2037
2038     QCOMPARE(item2->hoverInCount, 2);
2039     QCOMPARE(item2->hoverMoveCount, 3);
2040     QCOMPARE(item2->hoverOutCount, 2);
2041     QCOMPARE(item1->hoverInCount, 0);
2042     QCOMPARE(item1->hoverMoveCount, 0);
2043     QCOMPARE(item1->hoverOutCount, 0);
2044     QCOMPARE(item0->hoverInCount, 1);
2045     QCOMPARE(item0->hoverMoveCount, 1);
2046     QCOMPARE(item0->hoverOutCount, 0);
2047 }
2048
2049 void tst_QGraphicsItem::hasFocus()
2050 {
2051     QGraphicsLineItem *line = new QGraphicsLineItem;
2052     QVERIFY(!line->hasFocus());
2053     line->setFocus();
2054     QVERIFY(!line->hasFocus());
2055
2056     QGraphicsScene scene;
2057     QEvent activate(QEvent::WindowActivate);
2058     QApplication::sendEvent(&scene, &activate);
2059
2060     scene.addItem(line);
2061
2062     line->setFocus();
2063     QVERIFY(!line->hasFocus());
2064     line->setFlag(QGraphicsItem::ItemIsFocusable);
2065     line->setFocus();
2066     QVERIFY(line->hasFocus());
2067
2068     QGraphicsScene scene2;
2069     QApplication::sendEvent(&scene2, &activate);
2070
2071     scene2.addItem(line);
2072     QVERIFY(!line->hasFocus());
2073
2074     QCOMPARE(scene.focusItem(), (QGraphicsItem *)0);
2075     QCOMPARE(scene2.focusItem(), (QGraphicsItem *)0);
2076
2077     line->setFocus();
2078     QVERIFY(line->hasFocus());
2079     line->clearFocus();
2080     QVERIFY(!line->hasFocus());
2081
2082     QGraphicsLineItem *line2 = new QGraphicsLineItem;
2083     line2->setFlag(QGraphicsItem::ItemIsFocusable);
2084     scene2.addItem(line2);
2085
2086     line2->setFocus();
2087     QVERIFY(!line->hasFocus());
2088     QVERIFY(line2->hasFocus());
2089     line->setFocus();
2090     QVERIFY(line->hasFocus());
2091     QVERIFY(!line2->hasFocus());
2092 }
2093
2094 void tst_QGraphicsItem::pos()
2095 {
2096     QGraphicsItem *child = new QGraphicsLineItem;
2097     QGraphicsItem *parent = new QGraphicsLineItem;
2098
2099     QCOMPARE(child->pos(), QPointF());
2100     QCOMPARE(parent->pos(), QPointF());
2101
2102     child->setParentItem(parent);
2103     child->setPos(10, 10);
2104
2105     QCOMPARE(child->pos(), QPointF(10, 10));
2106
2107     parent->setPos(10, 10);
2108
2109     QCOMPARE(parent->pos(), QPointF(10, 10));
2110     QCOMPARE(child->pos(), QPointF(10, 10));
2111
2112     delete child;
2113     delete parent;
2114 }
2115
2116 void tst_QGraphicsItem::scenePos()
2117 {
2118     QGraphicsItem *child = new QGraphicsLineItem;
2119     QGraphicsItem *parent = new QGraphicsLineItem;
2120
2121     QCOMPARE(child->scenePos(), QPointF());
2122     QCOMPARE(parent->scenePos(), QPointF());
2123
2124     child->setParentItem(parent);
2125     child->setPos(10, 10);
2126
2127     QCOMPARE(child->scenePos(), QPointF(10, 10));
2128
2129     parent->setPos(10, 10);
2130
2131     QCOMPARE(parent->scenePos(), QPointF(10, 10));
2132     QCOMPARE(child->scenePos(), QPointF(20, 20));
2133
2134     parent->setPos(20, 20);
2135
2136     QCOMPARE(parent->scenePos(), QPointF(20, 20));
2137     QCOMPARE(child->scenePos(), QPointF(30, 30));
2138
2139     delete child;
2140     delete parent;
2141 }
2142
2143 void tst_QGraphicsItem::matrix()
2144 {
2145     QGraphicsLineItem line;
2146     QCOMPARE(line.matrix(), QMatrix());
2147     line.setMatrix(QMatrix().rotate(90));
2148     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2149     line.setMatrix(QMatrix().rotate(90));
2150     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2151     line.setMatrix(QMatrix().rotate(90), true);
2152     QCOMPARE(line.matrix(), QMatrix().rotate(180));
2153     line.setMatrix(QMatrix().rotate(-90), true);
2154     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2155     line.resetMatrix();
2156     QCOMPARE(line.matrix(), QMatrix());
2157
2158     line.rotate(90);
2159     QCOMPARE(line.matrix(), QMatrix().rotate(90));
2160     line.rotate(90);
2161     QCOMPARE(line.matrix(), QMatrix().rotate(90).rotate(90));
2162     line.resetMatrix();
2163
2164     line.scale(2, 4);
2165     QCOMPARE(line.matrix(), QMatrix().scale(2, 4));
2166     line.scale(2, 4);
2167     QCOMPARE(line.matrix(), QMatrix().scale(2, 4).scale(2, 4));
2168     line.resetMatrix();
2169
2170     line.shear(2, 4);
2171     QCOMPARE(line.matrix(), QMatrix().shear(2, 4));
2172     line.shear(2, 4);
2173     QCOMPARE(line.matrix(), QMatrix().shear(2, 4).shear(2, 4));
2174     line.resetMatrix();
2175
2176     line.translate(10, 10);
2177     QCOMPARE(line.matrix(), QMatrix().translate(10, 10));
2178     line.translate(10, 10);
2179     QCOMPARE(line.matrix(), QMatrix().translate(10, 10).translate(10, 10));
2180     line.resetMatrix();
2181 }
2182
2183 void tst_QGraphicsItem::sceneMatrix()
2184 {
2185     QGraphicsLineItem *parent = new QGraphicsLineItem;
2186     QGraphicsLineItem *child = new QGraphicsLineItem(QLineF(), parent);
2187
2188     QCOMPARE(parent->sceneMatrix(), QMatrix());
2189     QCOMPARE(child->sceneMatrix(), QMatrix());
2190
2191     parent->translate(10, 10);
2192     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
2193     QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10));
2194
2195     child->translate(10, 10);
2196     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10));
2197     QCOMPARE(child->sceneMatrix(), QMatrix().translate(20, 20));
2198
2199     parent->rotate(90);
2200     QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10).rotate(90));
2201     QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10).rotate(90).translate(10, 10));
2202
2203     delete child;
2204     delete parent;
2205 }
2206
2207 void tst_QGraphicsItem::setMatrix()
2208 {
2209     QGraphicsScene scene;
2210     qRegisterMetaType<QList<QRectF> >("QList<QRectF>");
2211     QSignalSpy spy(&scene, SIGNAL(changed(QList<QRectF>)));
2212     QRectF unrotatedRect(-12, -34, 56, 78);
2213     QGraphicsRectItem item(unrotatedRect, 0);
2214     item.setPen(QPen(Qt::black, 0));
2215     scene.addItem(&item);
2216     scene.update(scene.sceneRect());
2217     QApplication::instance()->processEvents();
2218
2219     QCOMPARE(spy.count(), 1);
2220
2221     item.setMatrix(QMatrix().rotate(qreal(12.34)));
2222     QRectF rotatedRect = scene.sceneRect();
2223     QVERIFY(unrotatedRect != rotatedRect);
2224     scene.update(scene.sceneRect());
2225     QApplication::instance()->processEvents();
2226
2227     QCOMPARE(spy.count(), 2);
2228
2229     item.setMatrix(QMatrix());
2230
2231     scene.update(scene.sceneRect());
2232     QApplication::instance()->processEvents();
2233
2234     QCOMPARE(spy.count(), 3);
2235     QList<QRectF> rlist = qvariant_cast<QList<QRectF> >(spy.last().at(0));
2236
2237     QCOMPARE(rlist.size(), 3);
2238     QCOMPARE(rlist.at(0), rotatedRect);   // From item.setMatrix() (clearing rotated rect)
2239     QCOMPARE(rlist.at(1), rotatedRect);   // From scene.update()   (updating scene rect)
2240     QCOMPARE(rlist.at(2), unrotatedRect); // From post-update      (update current state)
2241 }
2242
2243 static QList<QGraphicsItem *> _paintedItems;
2244 class PainterItem : public QGraphicsItem
2245 {
2246 protected:
2247     QRectF boundingRect() const
2248     { return QRectF(-10, -10, 20, 20); }
2249
2250     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
2251     { _paintedItems << this; painter->fillRect(boundingRect(), Qt::red); }
2252 };
2253
2254 void tst_QGraphicsItem::zValue()
2255 {
2256     Q_CHECK_PAINTEVENTS
2257
2258     QGraphicsScene scene;
2259
2260     QGraphicsItem *item1 = new PainterItem;
2261     QGraphicsItem *item2 = new PainterItem;
2262     QGraphicsItem *item3 = new PainterItem;
2263     QGraphicsItem *item4 = new PainterItem;
2264     scene.addItem(item1);
2265     scene.addItem(item2);
2266     scene.addItem(item3);
2267     scene.addItem(item4);
2268     item2->setZValue(-3);
2269     item4->setZValue(-2);
2270     item1->setZValue(-1);
2271     item3->setZValue(0);
2272
2273     QGraphicsView view(&scene);
2274     view.show();
2275     QVERIFY(QTest::qWaitForWindowExposed(&view));
2276
2277     QApplication::processEvents();
2278
2279     QTRY_VERIFY(!_paintedItems.isEmpty());
2280     QVERIFY((_paintedItems.size() % 4) == 0);
2281     for (int i = 0; i < 3; ++i)
2282         QVERIFY(_paintedItems.at(i)->zValue() < _paintedItems.at(i + 1)->zValue());
2283 }
2284
2285 void tst_QGraphicsItem::shape()
2286 {
2287     QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
2288     line.setPen(QPen(Qt::black, 0));
2289
2290     // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
2291     // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
2292     const qreal penWidthZero = qreal(0.00000001);
2293
2294     QPainterPathStroker ps;
2295     ps.setWidth(penWidthZero);
2296
2297     QPainterPath path(line.line().p1());
2298     path.lineTo(line.line().p2());
2299     QPainterPath p = ps.createStroke(path);
2300     p.addPath(path);
2301     QCOMPARE(line.shape(), p);
2302
2303     QPen linePen;
2304     linePen.setWidthF(5.0);
2305     linePen.setCapStyle(Qt::RoundCap);
2306     line.setPen(linePen);
2307
2308     ps.setCapStyle(line.pen().capStyle());
2309     ps.setWidth(line.pen().widthF());
2310     p = ps.createStroke(path);
2311     p.addPath(path);
2312     QCOMPARE(line.shape(), p);
2313
2314     linePen.setCapStyle(Qt::FlatCap);
2315     line.setPen(linePen);
2316     ps.setCapStyle(line.pen().capStyle());
2317     p = ps.createStroke(path);
2318     p.addPath(path);
2319     QCOMPARE(line.shape(), p);
2320
2321     linePen.setCapStyle(Qt::SquareCap);
2322     line.setPen(linePen);
2323     ps.setCapStyle(line.pen().capStyle());
2324     p = ps.createStroke(path);
2325     p.addPath(path);
2326     QCOMPARE(line.shape(), p);
2327
2328     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2329     rect.setPen(QPen(Qt::black, 0));
2330     QPainterPathStroker ps1;
2331     ps1.setWidth(penWidthZero);
2332     path = QPainterPath();
2333     path.addRect(rect.rect());
2334     p = ps1.createStroke(path);
2335     p.addPath(path);
2336     QCOMPARE(rect.shape(), p);
2337
2338     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2339     ellipse.setPen(QPen(Qt::black, 0));
2340     QPainterPathStroker ps2;
2341     ps2.setWidth(ellipse.pen().widthF() <= 0.0 ? penWidthZero : ellipse.pen().widthF());
2342     path = QPainterPath();
2343     path.addEllipse(ellipse.rect());
2344     p = ps2.createStroke(path);
2345     p.addPath(path);
2346     QCOMPARE(ellipse.shape(), p);
2347
2348     QPainterPathStroker ps3;
2349     ps3.setWidth(penWidthZero);
2350     p = ps3.createStroke(path);
2351     p.addPath(path);
2352     QGraphicsPathItem pathItem(path);
2353     pathItem.setPen(QPen(Qt::black, 0));
2354     QCOMPARE(pathItem.shape(), p);
2355
2356     QRegion region(QRect(0, 0, 300, 200));
2357     region = region.subtracted(QRect(50, 50, 200, 100));
2358
2359     QImage image(300, 200, QImage::Format_ARGB32_Premultiplied);
2360     image.fill(0);
2361     QPainter painter(&image);
2362     painter.setClipRegion(region);
2363     painter.fillRect(0, 0, 300, 200, Qt::green);
2364     painter.end();
2365     QPixmap pixmap = QPixmap::fromImage(image);
2366
2367     QGraphicsPixmapItem pixmapItem(pixmap);
2368     path = QPainterPath();
2369     path.addRegion(region);
2370
2371     {
2372         QBitmap bitmap(300, 200);
2373         bitmap.clear();
2374         QPainter painter(&bitmap);
2375         painter.setClipRegion(region);
2376         painter.fillRect(0, 0, 300, 200, Qt::color1);
2377         painter.end();
2378
2379         QBitmap bitmap2(300, 200);
2380         bitmap2.clear();
2381         painter.begin(&bitmap2);
2382         painter.setClipPath(pixmapItem.shape());
2383         painter.fillRect(0, 0, 300, 200, Qt::color1);
2384         painter.end();
2385
2386         QCOMPARE(bitmap.toImage(), bitmap2.toImage());
2387     }
2388
2389     QPolygonF poly;
2390     poly << QPointF(0, 0) << QPointF(10, 0) << QPointF(0, 10);
2391     QGraphicsPolygonItem polygon(poly);
2392     polygon.setPen(QPen(Qt::black, 0));
2393     path = QPainterPath();
2394     path.addPolygon(poly);
2395
2396     QPainterPathStroker ps4;
2397     ps4.setWidth(penWidthZero);
2398     p = ps4.createStroke(path);
2399     p.addPath(path);
2400     QCOMPARE(polygon.shape(), p);
2401 }
2402
2403 void tst_QGraphicsItem::contains()
2404 {
2405     if (sizeof(qreal) != sizeof(double))
2406         QSKIP("Skipped due to rounding errors");
2407
2408     // Rect
2409     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2410     QVERIFY(!rect.contains(QPointF(-11, -10)));
2411     QVERIFY(rect.contains(QPointF(-10, -10)));
2412     QVERIFY(!rect.contains(QPointF(-11, 0)));
2413     QVERIFY(rect.contains(QPointF(-10, 0)));
2414     QVERIFY(rect.contains(QPointF(0, -10)));
2415     QVERIFY(rect.contains(QPointF(0, 0)));
2416     QVERIFY(rect.contains(QPointF(9, 9)));
2417
2418     // Ellipse
2419     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2420     QVERIFY(!ellipse.contains(QPointF(-10, -10)));
2421     QVERIFY(ellipse.contains(QPointF(-9, 0)));
2422     QVERIFY(ellipse.contains(QPointF(0, -9)));
2423     QVERIFY(ellipse.contains(QPointF(0, 0)));
2424     QVERIFY(!ellipse.contains(QPointF(9, 9)));
2425
2426     // Line
2427     QGraphicsLineItem line(QLineF(-10, -10, 20, 20));
2428     QVERIFY(!line.contains(QPointF(-10, 0)));
2429     QVERIFY(!line.contains(QPointF(0, -10)));
2430     QVERIFY(!line.contains(QPointF(10, 0)));
2431     QVERIFY(!line.contains(QPointF(0, 10)));
2432     QVERIFY(line.contains(QPointF(0, 0)));
2433     QVERIFY(line.contains(QPointF(-9, -9)));
2434     QVERIFY(line.contains(QPointF(9, 9)));
2435
2436     // Polygon
2437     QGraphicsPolygonItem polygon(QPolygonF()
2438                                  << QPointF(0, 0)
2439                                  << QPointF(10, 0)
2440                                  << QPointF(0, 10));
2441     QVERIFY(polygon.contains(QPointF(1, 1)));
2442     QVERIFY(polygon.contains(QPointF(4, 4)));
2443     QVERIFY(polygon.contains(QPointF(1, 4)));
2444     QVERIFY(polygon.contains(QPointF(4, 1)));
2445     QVERIFY(!polygon.contains(QPointF(8, 8)));
2446     QVERIFY(polygon.contains(QPointF(1, 8)));
2447     QVERIFY(polygon.contains(QPointF(8, 1)));
2448 }
2449
2450 void tst_QGraphicsItem::collidesWith_item()
2451 {
2452     // Rectangle
2453     QGraphicsRectItem rect(QRectF(-10, -10, 20, 20));
2454     QGraphicsRectItem rect2(QRectF(-10, -10, 20, 20));
2455     QVERIFY(rect.collidesWithItem(&rect2));
2456     QVERIFY(rect2.collidesWithItem(&rect));
2457     rect2.setPos(21, 21);
2458     QVERIFY(!rect.collidesWithItem(&rect2));
2459     QVERIFY(!rect2.collidesWithItem(&rect));
2460     rect2.setPos(-21, -21);
2461     QVERIFY(!rect.collidesWithItem(&rect2));
2462     QVERIFY(!rect2.collidesWithItem(&rect));
2463     rect2.setPos(-17, -17);
2464     QVERIFY(rect.collidesWithItem(&rect2));
2465     QVERIFY(rect2.collidesWithItem(&rect));
2466
2467     QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20));
2468     QGraphicsEllipseItem ellipse2(QRectF(-10, -10, 20, 20));
2469     QVERIFY(ellipse.collidesWithItem(&ellipse2));
2470     QVERIFY(ellipse2.collidesWithItem(&ellipse));
2471     ellipse2.setPos(21, 21);
2472     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2473     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2474     ellipse2.setPos(-21, -21);
2475     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2476     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2477
2478     ellipse2.setPos(-17, -17);
2479     QVERIFY(!ellipse.collidesWithItem(&ellipse2));
2480     QVERIFY(!ellipse2.collidesWithItem(&ellipse));
2481
2482     {
2483         QGraphicsScene scene;
2484         QGraphicsRectItem rect(20, 20, 100, 100, 0);
2485         scene.addItem(&rect);
2486         QGraphicsRectItem rect2(40, 40, 50, 50, 0);
2487         scene.addItem(&rect2);
2488         rect2.setZValue(1);
2489         QGraphicsLineItem line(0, 0, 200, 200, 0);
2490         scene.addItem(&line);
2491         line.setZValue(2);
2492
2493         QCOMPARE(scene.items().size(), 3);
2494
2495         QList<QGraphicsItem *> col1 = rect.collidingItems();
2496         QCOMPARE(col1.size(), 2);
2497         QCOMPARE(col1.first(), static_cast<QGraphicsItem *>(&line));
2498         QCOMPARE(col1.last(), static_cast<QGraphicsItem *>(&rect2));
2499
2500         QList<QGraphicsItem *> col2 = rect2.collidingItems();
2501         QCOMPARE(col2.size(), 2);
2502         QCOMPARE(col2.first(), static_cast<QGraphicsItem *>(&line));
2503         QCOMPARE(col2.last(), static_cast<QGraphicsItem *>(&rect));
2504
2505         QList<QGraphicsItem *> col3 = line.collidingItems();
2506         QCOMPARE(col3.size(), 2);
2507         QCOMPARE(col3.first(), static_cast<QGraphicsItem *>(&rect2));
2508         QCOMPARE(col3.last(), static_cast<QGraphicsItem *>(&rect));
2509     }
2510 }
2511
2512 void tst_QGraphicsItem::collidesWith_path_data()
2513 {
2514     QTest::addColumn<QPointF>("pos");
2515     QTest::addColumn<QMatrix>("matrix");
2516     QTest::addColumn<QPainterPath>("shape");
2517     QTest::addColumn<bool>("rectCollides");
2518     QTest::addColumn<bool>("ellipseCollides");
2519
2520     QTest::newRow("nothing") << QPointF(0, 0) << QMatrix() << QPainterPath() << false << false;
2521
2522     QPainterPath rect;
2523     rect.addRect(0, 0, 20, 20);
2524
2525     QTest::newRow("rect1") << QPointF(0, 0) << QMatrix() << rect << true << true;
2526     QTest::newRow("rect2") << QPointF(0, 0) << QMatrix().translate(21, 21) << rect << false << false;
2527     QTest::newRow("rect3") << QPointF(21, 21) << QMatrix() << rect << false << false;
2528 }
2529
2530 void tst_QGraphicsItem::collidesWith_path()
2531 {
2532     QFETCH(QPointF, pos);
2533     QFETCH(QMatrix, matrix);
2534     QFETCH(QPainterPath, shape);
2535     QFETCH(bool, rectCollides);
2536     QFETCH(bool, ellipseCollides);
2537
2538     QGraphicsRectItem rect(QRectF(0, 0, 20, 20));
2539     QGraphicsEllipseItem ellipse(QRectF(0, 0, 20, 20));
2540
2541     rect.setPos(pos);
2542     rect.setMatrix(matrix);
2543
2544     ellipse.setPos(pos);
2545     ellipse.setMatrix(matrix);
2546
2547     QPainterPath mappedShape = rect.sceneMatrix().inverted().map(shape);
2548
2549     if (rectCollides)
2550         QVERIFY(rect.collidesWithPath(mappedShape));
2551     else
2552         QVERIFY(!rect.collidesWithPath(mappedShape));
2553
2554     if (ellipseCollides)
2555         QVERIFY(ellipse.collidesWithPath(mappedShape));
2556     else
2557         QVERIFY(!ellipse.collidesWithPath(mappedShape));
2558 }
2559
2560 void tst_QGraphicsItem::collidesWithItemWithClip()
2561 {
2562     QGraphicsScene scene;
2563
2564     QGraphicsEllipseItem *ellipse = scene.addEllipse(0, 0, 100, 100);
2565     ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
2566     QGraphicsEllipseItem *ellipse2 = scene.addEllipse(0, 0, 10, 10);
2567     ellipse2->setParentItem(ellipse);
2568     QGraphicsEllipseItem *ellipse3 = scene.addEllipse(0, 0, 10, 10);
2569     ellipse3->setParentItem(ellipse);
2570     QGraphicsEllipseItem *ellipse5 = scene.addEllipse(50, 50, 10, 10);
2571     ellipse5->setParentItem(ellipse);
2572     QGraphicsEllipseItem *ellipse4 = scene.addEllipse(0, 0, 10, 10);
2573
2574     QVERIFY(ellipse2->collidesWithItem(ellipse3));
2575     QVERIFY(ellipse3->collidesWithItem(ellipse2));
2576     QVERIFY(!ellipse2->collidesWithItem(ellipse));
2577     QVERIFY(!ellipse->collidesWithItem(ellipse2));
2578     QVERIFY(!ellipse4->collidesWithItem(ellipse));
2579     QVERIFY(!ellipse4->collidesWithItem(ellipse2));
2580     QVERIFY(!ellipse4->collidesWithItem(ellipse3));
2581     QVERIFY(!ellipse->collidesWithItem(ellipse4));
2582     QVERIFY(!ellipse2->collidesWithItem(ellipse4));
2583     QVERIFY(!ellipse3->collidesWithItem(ellipse4));
2584     QVERIFY(ellipse->collidesWithItem(ellipse5));
2585     QVERIFY(ellipse5->collidesWithItem(ellipse));
2586 }
2587
2588 class MyItem : public QGraphicsEllipseItem
2589 {
2590 public:
2591     bool isObscuredBy(const QGraphicsItem *item) const
2592     {
2593         const MyItem *myItem = qgraphicsitem_cast<const MyItem *>(item);
2594         if (myItem) {
2595             if (item->zValue() > zValue()) {
2596                 QRectF r = rect();
2597                 QPointF topMid = (r.topRight()+r.topLeft())/2;
2598                 QPointF botMid = (r.bottomRight()+r.bottomLeft())/2;
2599                 QPointF leftMid = (r.topLeft()+r.bottomLeft())/2;
2600                 QPointF rightMid = (r.topRight()+r.bottomRight())/2;
2601
2602                 QPainterPath mappedShape = item->mapToItem(this, item->opaqueArea());
2603
2604                 if (mappedShape.contains(topMid) &&
2605                     mappedShape.contains(botMid) &&
2606                     mappedShape.contains(leftMid) &&
2607                     mappedShape.contains(rightMid))
2608                     return true;
2609                 else
2610                     return false;
2611             }
2612             else return false;
2613         }
2614         else
2615             return QGraphicsItem::isObscuredBy(item);
2616     }
2617
2618     QPainterPath opaqueArea() const
2619     {
2620         return shape();
2621     }
2622
2623     enum {
2624         Type = UserType+1
2625     };
2626     int type() const { return Type; }
2627 };
2628
2629 void tst_QGraphicsItem::isObscuredBy()
2630 {
2631     QGraphicsScene scene;
2632
2633     MyItem myitem1, myitem2;
2634
2635     myitem1.setRect(QRectF(50, 50, 40, 200));
2636     myitem1.rotate(67);
2637
2638     myitem2.setRect(QRectF(25, 25, 20, 20));
2639     myitem2.setZValue(-1.0);
2640     scene.addItem(&myitem1);
2641     scene.addItem(&myitem2);
2642
2643     QVERIFY(!myitem2.isObscuredBy(&myitem1));
2644     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2645
2646     myitem2.setRect(QRectF(-50, 85, 20, 20));
2647     QVERIFY(myitem2.isObscuredBy(&myitem1));
2648     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2649
2650     myitem2.setRect(QRectF(-30, 70, 20, 20));
2651     QVERIFY(!myitem2.isObscuredBy(&myitem1));
2652     QVERIFY(!myitem1.isObscuredBy(&myitem2));
2653
2654     QGraphicsRectItem rect1, rect2;
2655
2656     rect1.setRect(QRectF(-40, -40, 50, 50));
2657     rect1.setBrush(QBrush(Qt::red));
2658     rect2.setRect(QRectF(-30, -20, 20, 20));
2659     rect2.setZValue(-1.0);
2660     rect2.setBrush(QBrush(Qt::blue));
2661
2662     QVERIFY(rect2.isObscuredBy(&rect1));
2663     QVERIFY(!rect1.isObscuredBy(&rect2));
2664
2665     rect2.setPos(QPointF(-20, -25));
2666
2667     QVERIFY(!rect2.isObscuredBy(&rect1));
2668     QVERIFY(!rect1.isObscuredBy(&rect2));
2669
2670     rect2.setPos(QPointF(-100, -100));
2671
2672     QVERIFY(!rect2.isObscuredBy(&rect1));
2673     QVERIFY(!rect1.isObscuredBy(&rect2));
2674 }
2675
2676 class OpaqueItem : public QGraphicsRectItem
2677 {
2678 protected:
2679     QPainterPath opaqueArea() const
2680     {
2681         return shape();
2682     }
2683 };
2684
2685 void tst_QGraphicsItem::isObscured()
2686 {
2687     if (sizeof(qreal) != sizeof(double))
2688         QSKIP("Skipped due to rounding errors");
2689
2690     OpaqueItem *item1 = new OpaqueItem;
2691     item1->setRect(0, 0, 100, 100);
2692     item1->setZValue(0);
2693
2694     OpaqueItem *item2 = new OpaqueItem;
2695     item2->setZValue(1);
2696     item2->setRect(0, 0, 100, 100);
2697
2698     QGraphicsScene scene;
2699     scene.addItem(item1);
2700     scene.addItem(item2);
2701
2702     QVERIFY(item1->isObscured());
2703     QVERIFY(item1->isObscuredBy(item2));
2704     QVERIFY(item1->isObscured(QRectF(0, 0, 50, 50)));
2705     QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
2706     QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
2707     QVERIFY(item1->isObscured(QRectF(0, 50, 50, 50)));
2708     QVERIFY(item1->isObscured(0, 0, 50, 50));
2709     QVERIFY(item1->isObscured(50, 0, 50, 50));
2710     QVERIFY(item1->isObscured(50, 50, 50, 50));
2711     QVERIFY(item1->isObscured(0, 50, 50, 50));
2712     QVERIFY(!item2->isObscured());
2713     QVERIFY(!item2->isObscuredBy(item1));
2714     QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
2715     QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
2716     QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
2717     QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
2718     QVERIFY(!item2->isObscured(0, 0, 50, 50));
2719     QVERIFY(!item2->isObscured(50, 0, 50, 50));
2720     QVERIFY(!item2->isObscured(50, 50, 50, 50));
2721     QVERIFY(!item2->isObscured(0, 50, 50, 50));
2722
2723     item2->moveBy(50, 0);
2724
2725     QVERIFY(!item1->isObscured());
2726     QVERIFY(!item1->isObscuredBy(item2));
2727     QVERIFY(!item1->isObscured(QRectF(0, 0, 50, 50)));
2728     QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50)));
2729     QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50)));
2730     QVERIFY(!item1->isObscured(QRectF(0, 50, 50, 50)));
2731     QVERIFY(!item1->isObscured(0, 0, 50, 50));
2732     QVERIFY(item1->isObscured(50, 0, 50, 50));
2733     QVERIFY(item1->isObscured(50, 50, 50, 50));
2734     QVERIFY(!item1->isObscured(0, 50, 50, 50));
2735     QVERIFY(!item2->isObscured());
2736     QVERIFY(!item2->isObscuredBy(item1));
2737     QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50)));
2738     QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50)));
2739     QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50)));
2740     QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50)));
2741     QVERIFY(!item2->isObscured(0, 0, 50, 50));
2742     QVERIFY(!item2->isObscured(50, 0, 50, 50));
2743     QVERIFY(!item2->isObscured(50, 50, 50, 50));
2744     QVERIFY(!item2->isObscured(0, 50, 50, 50));
2745 }
2746
2747 void tst_QGraphicsItem::mapFromToParent()
2748 {
2749     QPainterPath path1;
2750     path1.addRect(0, 0, 200, 200);
2751
2752     QPainterPath path2;
2753     path2.addRect(0, 0, 100, 100);
2754
2755     QPainterPath path3;
2756     path3.addRect(0, 0, 50, 50);
2757
2758     QPainterPath path4;
2759     path4.addRect(0, 0, 25, 25);
2760
2761     QGraphicsItem *item1 = new QGraphicsPathItem(path1);
2762     QGraphicsItem *item2 = new QGraphicsPathItem(path2, item1);
2763     QGraphicsItem *item3 = new QGraphicsPathItem(path3, item2);
2764     QGraphicsItem *item4 = new QGraphicsPathItem(path4, item3);
2765
2766     item1->setPos(10, 10);
2767     item2->setPos(10, 10);
2768     item3->setPos(10, 10);
2769     item4->setPos(10, 10);
2770
2771     for (int i = 0; i < 4; ++i) {
2772         QMatrix matrix;
2773         matrix.rotate(i * 90);
2774         matrix.translate(i * 100, -i * 100);
2775         matrix.scale(2, 4);
2776         item1->setMatrix(matrix);
2777
2778         QCOMPARE(item1->mapToParent(QPointF(0, 0)), item1->pos() + matrix.map(QPointF(0, 0)));
2779         QCOMPARE(item2->mapToParent(QPointF(0, 0)), item2->pos());
2780         QCOMPARE(item3->mapToParent(QPointF(0, 0)), item3->pos());
2781         QCOMPARE(item4->mapToParent(QPointF(0, 0)), item4->pos());
2782         QCOMPARE(item1->mapToParent(QPointF(10, -10)), item1->pos() + matrix.map(QPointF(10, -10)));
2783         QCOMPARE(item2->mapToParent(QPointF(10, -10)), item2->pos() + QPointF(10, -10));
2784         QCOMPARE(item3->mapToParent(QPointF(10, -10)), item3->pos() + QPointF(10, -10));
2785         QCOMPARE(item4->mapToParent(QPointF(10, -10)), item4->pos() + QPointF(10, -10));
2786         QCOMPARE(item1->mapToParent(QPointF(-10, 10)), item1->pos() + matrix.map(QPointF(-10, 10)));
2787         QCOMPARE(item2->mapToParent(QPointF(-10, 10)), item2->pos() + QPointF(-10, 10));
2788         QCOMPARE(item3->mapToParent(QPointF(-10, 10)), item3->pos() + QPointF(-10, 10));
2789         QCOMPARE(item4->mapToParent(QPointF(-10, 10)), item4->pos() + QPointF(-10, 10));
2790         QCOMPARE(item1->mapFromParent(item1->pos()), matrix.inverted().map(QPointF(0, 0)));
2791         QCOMPARE(item2->mapFromParent(item2->pos()), QPointF(0, 0));
2792         QCOMPARE(item3->mapFromParent(item3->pos()), QPointF(0, 0));
2793         QCOMPARE(item4->mapFromParent(item4->pos()), QPointF(0, 0));
2794         QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(10, -10)),
2795                  matrix.inverted().map(QPointF(10, -10)));
2796         QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(10, -10)), QPointF(10, -10));
2797         QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(10, -10)), QPointF(10, -10));
2798         QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(10, -10)), QPointF(10, -10));
2799         QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(-10, 10)),
2800                  matrix.inverted().map(QPointF(-10, 10)));
2801         QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2802         QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2803         QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(-10, 10)), QPointF(-10, 10));
2804     }
2805
2806     delete item1;
2807 }
2808
2809 void tst_QGraphicsItem::mapFromToScene()
2810 {
2811     QGraphicsItem *item1 = new QGraphicsPathItem(QPainterPath());
2812     QGraphicsItem *item2 = new QGraphicsPathItem(QPainterPath(), item1);
2813     QGraphicsItem *item3 = new QGraphicsPathItem(QPainterPath(), item2);
2814     QGraphicsItem *item4 = new QGraphicsPathItem(QPainterPath(), item3);
2815
2816     item1->setPos(100, 100);
2817     item2->setPos(100, 100);
2818     item3->setPos(100, 100);
2819     item4->setPos(100, 100);
2820     QCOMPARE(item1->pos(), QPointF(100, 100));
2821     QCOMPARE(item2->pos(), QPointF(100, 100));
2822     QCOMPARE(item3->pos(), QPointF(100, 100));
2823     QCOMPARE(item4->pos(), QPointF(100, 100));
2824     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2825     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2826     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2827     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2828     QCOMPARE(item1->mapToParent(10, 10), QPointF(110, 110));
2829     QCOMPARE(item2->mapToParent(10, 10), QPointF(110, 110));
2830     QCOMPARE(item3->mapToParent(10, 10), QPointF(110, 110));
2831     QCOMPARE(item4->mapToParent(10, 10), QPointF(110, 110));
2832     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2833     QCOMPARE(item2->mapToScene(0, 0), QPointF(200, 200));
2834     QCOMPARE(item3->mapToScene(0, 0), QPointF(300, 300));
2835     QCOMPARE(item4->mapToScene(0, 0), QPointF(400, 400));
2836     QCOMPARE(item1->mapToScene(10, 0), QPointF(110, 100));
2837     QCOMPARE(item2->mapToScene(10, 0), QPointF(210, 200));
2838     QCOMPARE(item3->mapToScene(10, 0), QPointF(310, 300));
2839     QCOMPARE(item4->mapToScene(10, 0), QPointF(410, 400));
2840     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2841     QCOMPARE(item2->mapFromScene(200, 200), QPointF(0, 0));
2842     QCOMPARE(item3->mapFromScene(300, 300), QPointF(0, 0));
2843     QCOMPARE(item4->mapFromScene(400, 400), QPointF(0, 0));
2844     QCOMPARE(item1->mapFromScene(110, 100), QPointF(10, 0));
2845     QCOMPARE(item2->mapFromScene(210, 200), QPointF(10, 0));
2846     QCOMPARE(item3->mapFromScene(310, 300), QPointF(10, 0));
2847     QCOMPARE(item4->mapFromScene(410, 400), QPointF(10, 0));
2848
2849     // Rotate item1 90 degrees clockwise
2850     QMatrix matrix; matrix.rotate(90);
2851     item1->setMatrix(matrix);
2852     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2853     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2854     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2855     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2856     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2857     QCOMPARE(item2->mapToParent(10, 0), QPointF(110, 100));
2858     QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
2859     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2860     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2861     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2862     QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 300));
2863     QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 400));
2864     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2865     QCOMPARE(item2->mapToScene(10, 0), QPointF(0, 210));
2866     QCOMPARE(item3->mapToScene(10, 0), QPointF(-100, 310));
2867     QCOMPARE(item4->mapToScene(10, 0), QPointF(-200, 410));
2868     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2869     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2870     QCOMPARE(item3->mapFromScene(-100, 300), QPointF(0, 0));
2871     QCOMPARE(item4->mapFromScene(-200, 400), QPointF(0, 0));
2872     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2873     QCOMPARE(item2->mapFromScene(0, 210), QPointF(10, 0));
2874     QCOMPARE(item3->mapFromScene(-100, 310), QPointF(10, 0));
2875     QCOMPARE(item4->mapFromScene(-200, 410), QPointF(10, 0));
2876
2877     // Rotate item2 90 degrees clockwise
2878     item2->setMatrix(matrix);
2879     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2880     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2881     QCOMPARE(item3->pos(), item3->mapToParent(0, 0));
2882     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2883     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2884     QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
2885     QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100));
2886     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2887     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2888     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2889     QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 100));
2890     QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 0));
2891     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2892     QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
2893     QCOMPARE(item3->mapToScene(10, 0), QPointF(-110, 100));
2894     QCOMPARE(item4->mapToScene(10, 0), QPointF(-210, 0));
2895     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2896     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2897     QCOMPARE(item3->mapFromScene(-100, 100), QPointF(0, 0));
2898     QCOMPARE(item4->mapFromScene(-200, 0), QPointF(0, 0));
2899     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2900     QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
2901     QCOMPARE(item3->mapFromScene(-110, 100), QPointF(10, 0));
2902     QCOMPARE(item4->mapFromScene(-210, 0), QPointF(10, 0));
2903
2904     // Translate item3 50 points, then rotate 90 degrees counterclockwise
2905     QMatrix matrix2;
2906     matrix2.translate(50, 0);
2907     matrix2.rotate(-90);
2908     item3->setMatrix(matrix2);
2909     QCOMPARE(item1->pos(), item1->mapToParent(0, 0));
2910     QCOMPARE(item2->pos(), item2->mapToParent(0, 0));
2911     QCOMPARE(item3->pos(), item3->mapToParent(0, 0) - QPointF(50, 0));
2912     QCOMPARE(item4->pos(), item4->mapToParent(0, 0));
2913     QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110));
2914     QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110));
2915     QCOMPARE(item3->mapToParent(10, 0), QPointF(150, 90));
2916     QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100));
2917     QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100));
2918     QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200));
2919     QCOMPARE(item3->mapToScene(0, 0), QPointF(-150, 100));
2920     QCOMPARE(item4->mapToScene(0, 0), QPointF(-250, 200));
2921     QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110));
2922     QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200));
2923     QCOMPARE(item3->mapToScene(10, 0), QPointF(-150, 110));
2924     QCOMPARE(item4->mapToScene(10, 0), QPointF(-250, 210));
2925     QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0));
2926     QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0));
2927     QCOMPARE(item3->mapFromScene(-150, 100), QPointF(0, 0));
2928     QCOMPARE(item4->mapFromScene(-250, 200), QPointF(0, 0));
2929     QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0));
2930     QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0));
2931     QCOMPARE(item3->mapFromScene(-150, 110), QPointF(10, 0));
2932     QCOMPARE(item4->mapFromScene(-250, 210), QPointF(10, 0));
2933
2934     delete item1;
2935 }
2936
2937 void tst_QGraphicsItem::mapFromToItem()
2938 {
2939     QGraphicsItem *item1 = new QGraphicsPathItem;
2940     QGraphicsItem *item2 = new QGraphicsPathItem;
2941     QGraphicsItem *item3 = new QGraphicsPathItem;
2942     QGraphicsItem *item4 = new QGraphicsPathItem;
2943
2944     item1->setPos(-100, -100);
2945     item2->setPos(100, -100);
2946     item3->setPos(100, 100);
2947     item4->setPos(-100, 100);
2948
2949     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(200, 0));
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(0, -200));
2953     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(0, 200));
2954     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-200, 0));
2955     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
2956     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
2957
2958     QMatrix matrix;
2959     matrix.translate(100, 100);
2960     item1->setMatrix(matrix);
2961
2962     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(100, -100));
2963     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200));
2964     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0));
2965     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(100, -100));
2966     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(-100, 100));
2967     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-100, 100));
2968     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200));
2969     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0));
2970
2971     matrix.rotate(90);
2972     item1->setMatrix(matrix);
2973     item2->setMatrix(matrix);
2974     item3->setMatrix(matrix);
2975     item4->setMatrix(matrix);
2976
2977     QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(0, -200));
2978     QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(200, 0));
2979     QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(0, 200));
2980     QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(-200, 0));
2981     QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(200, 0));
2982     QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(0, 200));
2983     QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(-200, 0));
2984     QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(0, -200));
2985     QCOMPARE(item1->mapFromItem(item2, 10, -5), QPointF(10, -205));
2986     QCOMPARE(item2->mapFromItem(item3, 10, -5), QPointF(210, -5));
2987     QCOMPARE(item3->mapFromItem(item4, 10, -5), QPointF(10, 195));
2988     QCOMPARE(item4->mapFromItem(item1, 10, -5), QPointF(-190, -5));
2989     QCOMPARE(item1->mapFromItem(item4, 10, -5), QPointF(210, -5));
2990     QCOMPARE(item2->mapFromItem(item1, 10, -5), QPointF(10, 195));
2991     QCOMPARE(item3->mapFromItem(item2, 10, -5), QPointF(-190, -5));
2992     QCOMPARE(item4->mapFromItem(item3, 10, -5), QPointF(10, -205));
2993
2994     QCOMPARE(item1->mapFromItem(0, 10, -5), item1->mapFromScene(10, -5));
2995     QCOMPARE(item2->mapFromItem(0, 10, -5), item2->mapFromScene(10, -5));
2996     QCOMPARE(item3->mapFromItem(0, 10, -5), item3->mapFromScene(10, -5));
2997     QCOMPARE(item4->mapFromItem(0, 10, -5), item4->mapFromScene(10, -5));
2998     QCOMPARE(item1->mapToItem(0, 10, -5), item1->mapToScene(10, -5));
2999     QCOMPARE(item2->mapToItem(0, 10, -5), item2->mapToScene(10, -5));
3000     QCOMPARE(item3->mapToItem(0, 10, -5), item3->mapToScene(10, -5));
3001     QCOMPARE(item4->mapToItem(0, 10, -5), item4->mapToScene(10, -5));
3002
3003     delete item1;
3004     delete item2;
3005     delete item3;
3006     delete item4;
3007 }
3008
3009 void tst_QGraphicsItem::mapRectFromToParent_data()
3010 {
3011     QTest::addColumn<bool>("parent");
3012     QTest::addColumn<QPointF>("parentPos");
3013     QTest::addColumn<QTransform>("parentTransform");
3014     QTest::addColumn<QPointF>("pos");
3015     QTest::addColumn<QTransform>("transform");
3016     QTest::addColumn<QRectF>("inputRect");
3017     QTest::addColumn<QRectF>("outputRect");
3018
3019     QTest::newRow("nil") << false << QPointF() << QTransform() << QPointF() << QTransform() << QRectF() << QRectF();
3020     QTest::newRow("simple") << false << QPointF() << QTransform() << QPointF() << QTransform()
3021                             << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3022     QTest::newRow("simple w/parent") << true
3023                                      << QPointF() << QTransform()
3024                                      << QPointF() << QTransform()
3025                                      << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3026     QTest::newRow("simple w/parent parentPos") << true
3027                                                << QPointF(50, 50) << QTransform()
3028                                                << QPointF() << QTransform()
3029                                                << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3030     QTest::newRow("simple w/parent parentPos parentRotation") << true
3031                                                               << QPointF(50, 50) << QTransform().rotate(45)
3032                                                               << QPointF() << QTransform()
3033                                                               << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10);
3034     QTest::newRow("pos w/parent") << true
3035                                   << QPointF() << QTransform()
3036                                   << QPointF(50, 50) << QTransform()
3037                                   << QRectF(0, 0, 10, 10) << QRectF(50, 50, 10, 10);
3038     QTest::newRow("rotation w/parent") << true
3039                                        << QPointF() << QTransform()
3040                                        << QPointF() << QTransform().rotate(90)
3041                                        << QRectF(0, 0, 10, 10) << QRectF(-10, 0, 10, 10);
3042     QTest::newRow("pos rotation w/parent") << true
3043                                            << QPointF() << QTransform()
3044                                            << QPointF(50, 50) << QTransform().rotate(90)
3045                                            << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
3046     QTest::newRow("pos rotation w/parent parentPos parentRotation") << true
3047                                                                     << QPointF(-170, -190) << QTransform().rotate(90)
3048                                                                     << QPointF(50, 50) << QTransform().rotate(90)
3049                                                                     << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10);
3050 }
3051
3052 void tst_QGraphicsItem::mapRectFromToParent()
3053 {
3054     QFETCH(bool, parent);
3055     QFETCH(QPointF, parentPos);
3056     QFETCH(QTransform, parentTransform);
3057     QFETCH(QPointF, pos);
3058     QFETCH(QTransform, transform);
3059     QFETCH(QRectF, inputRect);
3060     QFETCH(QRectF, outputRect);
3061
3062     QGraphicsRectItem *rect = new QGraphicsRectItem;
3063     rect->setPos(pos);
3064     rect->setTransform(transform);
3065
3066     if (parent) {
3067         QGraphicsRectItem *rectParent = new QGraphicsRectItem;
3068         rect->setParentItem(rectParent);
3069         rectParent->setPos(parentPos);
3070         rectParent->setTransform(parentTransform);
3071     }
3072
3073     // Make sure we use non-destructive transform operations (e.g., 90 degree
3074     // rotations).
3075     QCOMPARE(rect->mapRectToParent(inputRect), outputRect);
3076     QCOMPARE(rect->mapRectFromParent(outputRect), inputRect);
3077     QCOMPARE(rect->itemTransform(rect->parentItem()).mapRect(inputRect), outputRect);
3078     QCOMPARE(rect->mapToParent(inputRect).boundingRect(), outputRect);
3079     QCOMPARE(rect->mapToParent(QPolygonF(inputRect)).boundingRect(), outputRect);
3080     QCOMPARE(rect->mapFromParent(outputRect).boundingRect(), inputRect);
3081     QCOMPARE(rect->mapFromParent(QPolygonF(outputRect)).boundingRect(), inputRect);
3082     QPainterPath inputPath;
3083     inputPath.addRect(inputRect);
3084     QPainterPath outputPath;
3085     outputPath.addRect(outputRect);
3086     QCOMPARE(rect->mapToParent(inputPath).boundingRect(), outputPath.boundingRect());
3087     QCOMPARE(rect->mapFromParent(outputPath).boundingRect(), inputPath.boundingRect());
3088 }
3089
3090 void tst_QGraphicsItem::isAncestorOf()
3091 {
3092     QGraphicsItem *grandPa = new QGraphicsRectItem;
3093     QGraphicsItem *parent = new QGraphicsRectItem;
3094     QGraphicsItem *child = new QGraphicsRectItem;
3095
3096     QVERIFY(!parent->isAncestorOf(0));
3097     QVERIFY(!child->isAncestorOf(0));
3098     QVERIFY(!parent->isAncestorOf(child));
3099     QVERIFY(!child->isAncestorOf(parent));
3100     QVERIFY(!parent->isAncestorOf(parent));
3101
3102     child->setParentItem(parent);
3103     parent->setParentItem(grandPa);
3104
3105     QVERIFY(parent->isAncestorOf(child));
3106     QVERIFY(grandPa->isAncestorOf(parent));
3107     QVERIFY(grandPa->isAncestorOf(child));
3108     QVERIFY(!child->isAncestorOf(parent));
3109     QVERIFY(!parent->isAncestorOf(grandPa));
3110     QVERIFY(!child->isAncestorOf(grandPa));
3111     QVERIFY(!child->isAncestorOf(child));
3112     QVERIFY(!parent->isAncestorOf(parent));
3113     QVERIFY(!grandPa->isAncestorOf(grandPa));
3114
3115     parent->setParentItem(0);
3116
3117     delete child;
3118     delete parent;
3119     delete grandPa;
3120 }
3121
3122 void tst_QGraphicsItem::commonAncestorItem()
3123 {
3124     QGraphicsItem *ancestor = new QGraphicsRectItem;
3125     QGraphicsItem *grandMa = new QGraphicsRectItem;
3126     QGraphicsItem *grandPa = new QGraphicsRectItem;
3127     QGraphicsItem *brotherInLaw = new QGraphicsRectItem;
3128     QGraphicsItem *cousin = new QGraphicsRectItem;
3129     QGraphicsItem *husband = new QGraphicsRectItem;
3130     QGraphicsItem *child = new QGraphicsRectItem;
3131     QGraphicsItem *wife = new QGraphicsRectItem;
3132
3133     child->setParentItem(husband);
3134     husband->setParentItem(grandPa);
3135     brotherInLaw->setParentItem(grandPa);
3136     cousin->setParentItem(brotherInLaw);
3137     wife->setParentItem(grandMa);
3138     grandMa->setParentItem(ancestor);
3139     grandPa->setParentItem(ancestor);
3140
3141     QCOMPARE(grandMa->commonAncestorItem(grandMa), grandMa);
3142     QCOMPARE(grandMa->commonAncestorItem(0), (QGraphicsItem *)0);
3143     QCOMPARE(grandMa->commonAncestorItem(grandPa), ancestor);
3144     QCOMPARE(grandPa->commonAncestorItem(grandMa), ancestor);
3145     QCOMPARE(grandPa->commonAncestorItem(husband), grandPa);
3146     QCOMPARE(grandPa->commonAncestorItem(wife), ancestor);
3147     QCOMPARE(grandMa->commonAncestorItem(husband), ancestor);
3148     QCOMPARE(grandMa->commonAncestorItem(wife), grandMa);
3149     QCOMPARE(wife->commonAncestorItem(grandMa), grandMa);
3150     QCOMPARE(child->commonAncestorItem(cousin), grandPa);
3151     QCOMPARE(cousin->commonAncestorItem(child), grandPa);
3152     QCOMPARE(wife->commonAncestorItem(child), ancestor);
3153     QCOMPARE(child->commonAncestorItem(wife), ancestor);
3154 }
3155
3156 void tst_QGraphicsItem::data()
3157 {
3158     QGraphicsTextItem text;
3159
3160     QCOMPARE(text.data(0), QVariant());
3161     text.setData(0, "TextItem");
3162     QCOMPARE(text.data(0), QVariant(QString("TextItem")));
3163     text.setData(0, QVariant());
3164     QCOMPARE(text.data(0), QVariant());
3165 }
3166
3167 void tst_QGraphicsItem::type()
3168 {
3169     QCOMPARE(int(QGraphicsItem::Type), 1);
3170     QCOMPARE(int(QGraphicsPathItem::Type), 2);
3171     QCOMPARE(int(QGraphicsRectItem::Type), 3);
3172     QCOMPARE(int(QGraphicsEllipseItem::Type), 4);
3173     QCOMPARE(int(QGraphicsPolygonItem::Type), 5);
3174     QCOMPARE(int(QGraphicsLineItem::Type), 6);
3175     QCOMPARE(int(QGraphicsPixmapItem::Type), 7);
3176     QCOMPARE(int(QGraphicsTextItem::Type), 8);
3177
3178     QCOMPARE(QGraphicsPathItem().type(), 2);
3179     QCOMPARE(QGraphicsRectItem().type(), 3);
3180     QCOMPARE(QGraphicsEllipseItem().type(), 4);
3181     QCOMPARE(QGraphicsPolygonItem().type(), 5);
3182     QCOMPARE(QGraphicsLineItem().type(), 6);
3183     QCOMPARE(QGraphicsPixmapItem().type(), 7);
3184     QCOMPARE(QGraphicsTextItem().type(), 8);
3185 }
3186
3187 void tst_QGraphicsItem::graphicsitem_cast()
3188 {
3189     QGraphicsPathItem pathItem;
3190     const QGraphicsPathItem *pPathItem = &pathItem;
3191     QGraphicsRectItem rectItem;
3192     const QGraphicsRectItem *pRectItem = &rectItem;
3193     QGraphicsEllipseItem ellipseItem;
3194     const QGraphicsEllipseItem *pEllipseItem = &ellipseItem;
3195     QGraphicsPolygonItem polygonItem;
3196     const QGraphicsPolygonItem *pPolygonItem = &polygonItem;
3197     QGraphicsLineItem lineItem;
3198     const QGraphicsLineItem *pLineItem = &lineItem;
3199     QGraphicsPixmapItem pixmapItem;
3200     const QGraphicsPixmapItem *pPixmapItem = &pixmapItem;
3201     QGraphicsTextItem textItem;
3202     const QGraphicsTextItem *pTextItem = &textItem;
3203
3204     QVERIFY(qgraphicsitem_cast<QGraphicsPathItem *>(&pathItem));
3205     //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&pathItem));
3206     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pathItem));
3207     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPathItem));
3208     QVERIFY(qgraphicsitem_cast<const QGraphicsPathItem *>(pPathItem));
3209
3210     QVERIFY(qgraphicsitem_cast<QGraphicsRectItem *>(&rectItem));
3211     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&rectItem));
3212     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pRectItem));
3213     QVERIFY(qgraphicsitem_cast<const QGraphicsRectItem *>(pRectItem));
3214
3215     QVERIFY(qgraphicsitem_cast<QGraphicsEllipseItem *>(&ellipseItem));
3216     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&ellipseItem));
3217     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pEllipseItem));
3218     QVERIFY(qgraphicsitem_cast<const QGraphicsEllipseItem *>(pEllipseItem));
3219
3220     QVERIFY(qgraphicsitem_cast<QGraphicsPolygonItem *>(&polygonItem));
3221     //QVERIFY(qgraphicsitem_cast<QAbstractGraphicsPathItem *>(&polygonItem));
3222     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&polygonItem));
3223     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPolygonItem));
3224     QVERIFY(qgraphicsitem_cast<const QGraphicsPolygonItem *>(pPolygonItem));
3225
3226     QVERIFY(qgraphicsitem_cast<QGraphicsLineItem *>(&lineItem));
3227     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&lineItem));
3228     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pLineItem));
3229     QVERIFY(qgraphicsitem_cast<const QGraphicsLineItem *>(pLineItem));
3230
3231     QVERIFY(qgraphicsitem_cast<QGraphicsPixmapItem *>(&pixmapItem));
3232     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&pixmapItem));
3233     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pPixmapItem));
3234     QVERIFY(qgraphicsitem_cast<const QGraphicsPixmapItem *>(pPixmapItem));
3235
3236     QVERIFY(qgraphicsitem_cast<QGraphicsTextItem *>(&textItem));
3237     QVERIFY(qgraphicsitem_cast<QGraphicsItem *>(&textItem));
3238     QVERIFY(qgraphicsitem_cast<const QGraphicsItem *>(pTextItem));
3239     QVERIFY(qgraphicsitem_cast<const QGraphicsTextItem *>(pTextItem));
3240
3241     // and some casts that _should_ fail:
3242     QVERIFY(!qgraphicsitem_cast<QGraphicsEllipseItem *>(&pathItem));
3243     QVERIFY(!qgraphicsitem_cast<const QGraphicsTextItem *>(pPolygonItem));
3244
3245     // and this shouldn't crash
3246     QGraphicsItem *ptr = 0;
3247     QVERIFY(!qgraphicsitem_cast<QGraphicsTextItem *>(ptr));
3248     QVERIFY(!qgraphicsitem_cast<QGraphicsItem *>(ptr));
3249 }
3250
3251 void tst_QGraphicsItem::hoverEventsGenerateRepaints()
3252 {
3253     Q_CHECK_PAINTEVENTS
3254
3255     QGraphicsScene scene;
3256     QGraphicsView view(&scene);
3257     view.show();
3258     QVERIFY(QTest::qWaitForWindowActive(&view));
3259
3260     EventTester *tester = new EventTester;
3261     scene.addItem(tester);
3262     tester->setAcceptsHoverEvents(true);
3263
3264     QTRY_COMPARE(tester->repaints, 1);
3265
3266     // Send a hover enter event
3267     QGraphicsSceneHoverEvent hoverEnterEvent(QEvent::GraphicsSceneHoverEnter);
3268     hoverEnterEvent.setScenePos(QPointF(0, 0));
3269     hoverEnterEvent.setPos(QPointF(0, 0));
3270     QApplication::sendEvent(&scene, &hoverEnterEvent);
3271
3272     // Check that we get a repaint
3273     int npaints = tester->repaints;
3274     qApp->processEvents();
3275     qApp->processEvents();
3276     QCOMPARE(tester->events.size(), 2); //  enter + move
3277     QCOMPARE(tester->repaints, npaints + 1);
3278     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
3279
3280     // Send a hover move event
3281     QGraphicsSceneHoverEvent hoverMoveEvent(QEvent::GraphicsSceneHoverMove);
3282     hoverMoveEvent.setScenePos(QPointF(0, 0));
3283     hoverMoveEvent.setPos(QPointF(0, 0));
3284     QApplication::sendEvent(&scene, &hoverMoveEvent);
3285
3286     // Check that we don't get a repaint
3287     qApp->processEvents();
3288     qApp->processEvents();
3289
3290     QCOMPARE(tester->events.size(), 3);
3291     QCOMPARE(tester->repaints, npaints + 1);
3292     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove);
3293
3294     // Send a hover leave event
3295     QGraphicsSceneHoverEvent hoverLeaveEvent(QEvent::GraphicsSceneHoverLeave);
3296     hoverLeaveEvent.setScenePos(QPointF(-100, -100));
3297     hoverLeaveEvent.setPos(QPointF(0, 0));
3298     QApplication::sendEvent(&scene, &hoverLeaveEvent);
3299
3300     // Check that we get a repaint
3301     qApp->processEvents();
3302     qApp->processEvents();
3303
3304     QCOMPARE(tester->events.size(), 4);
3305     QCOMPARE(tester->repaints, npaints + 2);
3306     QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverLeave);
3307 }
3308
3309 void tst_QGraphicsItem::boundingRects_data()
3310 {
3311     QTest::addColumn<QGraphicsItem *>("item");
3312     QTest::addColumn<QRectF>("boundingRect");
3313
3314     QRectF rect(0, 0, 100, 100);
3315     QPainterPath path;
3316     path.addRect(rect);
3317
3318     QRectF adjustedRect(-0.5, -0.5, 101, 101);
3319
3320     QTest::newRow("path") << (QGraphicsItem *)new QGraphicsPathItem(path) << adjustedRect;
3321     QTest::newRow("rect") << (QGraphicsItem *)new QGraphicsRectItem(rect) << adjustedRect;
3322     QTest::newRow("ellipse") << (QGraphicsItem *)new QGraphicsEllipseItem(rect) << adjustedRect;
3323     QTest::newRow("polygon") << (QGraphicsItem *)new QGraphicsPolygonItem(rect) << adjustedRect;
3324 }
3325
3326 void tst_QGraphicsItem::boundingRects()
3327 {
3328     QFETCH(QGraphicsItem *, item);
3329     QFETCH(QRectF, boundingRect);
3330
3331     ((QAbstractGraphicsShapeItem *)item)->setPen(QPen(Qt::black, 1));
3332     QCOMPARE(item->boundingRect(), boundingRect);
3333 }
3334
3335 void tst_QGraphicsItem::boundingRects2()
3336 {
3337     QGraphicsPixmapItem pixmap(QPixmap::fromImage(QImage(100, 100, QImage::Format_ARGB32_Premultiplied)));
3338     QCOMPARE(pixmap.boundingRect(), QRectF(0, 0, 100, 100));
3339
3340     QGraphicsLineItem line(0, 0, 100, 0);
3341     line.setPen(QPen(Qt::black, 1));
3342     QCOMPARE(line.boundingRect(), QRectF(-0.5, -0.5, 101, 1));
3343 }
3344
3345 void tst_QGraphicsItem::sceneBoundingRect()
3346 {
3347     QGraphicsScene scene;
3348     QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3349     item->setPos(100, 100);
3350
3351     QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
3352     QCOMPARE(item->sceneBoundingRect(), QRectF(100, 100, 100, 100));
3353
3354     item->rotate(90);
3355
3356     QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100));
3357     QCOMPARE(item->sceneBoundingRect(), QRectF(0, 100, 100, 100));
3358 }
3359
3360 void tst_QGraphicsItem::childrenBoundingRect()
3361 {
3362     QGraphicsScene scene;
3363     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3364     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3365     child->setParentItem(parent);
3366     parent->setPos(100, 100);
3367     child->setPos(100, 100);
3368
3369     QCOMPARE(parent->boundingRect(), QRectF(0, 0, 100, 100));
3370     QCOMPARE(child->boundingRect(), QRectF(0, 0, 100, 100));
3371     QCOMPARE(child->childrenBoundingRect(), QRectF());
3372     QCOMPARE(parent->childrenBoundingRect(), QRectF(100, 100, 100, 100));
3373
3374     QGraphicsRectItem *child2 = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3375     child2->setParentItem(parent);
3376     child2->setPos(-100, -100);
3377     QCOMPARE(parent->childrenBoundingRect(), QRectF(-100, -100, 300, 300));
3378
3379     QGraphicsRectItem *childChild = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0));
3380     childChild->setParentItem(child);
3381     childChild->setPos(500, 500);
3382     child->rotate(90);
3383
3384     scene.addPolygon(parent->mapToScene(parent->boundingRect() | parent->childrenBoundingRect()))->setPen(QPen(Qt::red));;
3385
3386     QGraphicsView view(&scene);
3387     view.show();
3388
3389     QVERIFY(QTest::qWaitForWindowExposed(&view));
3390     QTest::qWait(30);
3391
3392     QCOMPARE(parent->childrenBoundingRect(), QRectF(-500, -100, 600, 800));
3393 }
3394
3395 void tst_QGraphicsItem::childrenBoundingRectTransformed()
3396 {
3397     QGraphicsScene scene;
3398
3399     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
3400     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
3401     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
3402     QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
3403     QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
3404     rect2->setParentItem(rect);
3405     rect3->setParentItem(rect2);
3406     rect4->setParentItem(rect3);
3407     rect5->setParentItem(rect4);
3408
3409     rect->setPen(QPen(Qt::black, 0));
3410     rect2->setPen(QPen(Qt::black, 0));
3411     rect3->setPen(QPen(Qt::black, 0));
3412     rect4->setPen(QPen(Qt::black, 0));
3413     rect5->setPen(QPen(Qt::black, 0));
3414
3415     rect2->setTransform(QTransform().translate(50, 50).rotate(45));
3416     rect2->setPos(25, 25);
3417     rect3->setTransform(QTransform().translate(50, 50).rotate(45));
3418     rect3->setPos(25, 25);
3419     rect4->setTransform(QTransform().translate(50, 50).rotate(45));
3420     rect4->setPos(25, 25);
3421     rect5->setTransform(QTransform().translate(50, 50).rotate(45));
3422     rect5->setPos(25, 25);
3423
3424     QRectF subTreeRect = rect->childrenBoundingRect();
3425     QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
3426     QCOMPARE(subTreeRect.top(), qreal(75.0));
3427     QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
3428     QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
3429
3430     rect->rotate(45);
3431     rect2->rotate(-45);
3432     rect3->rotate(45);
3433     rect4->rotate(-45);
3434     rect5->rotate(45);
3435
3436     subTreeRect = rect->childrenBoundingRect();
3437     QCOMPARE(rect->childrenBoundingRect(), QRectF(-100, 75, 275, 250));
3438 }
3439
3440 void tst_QGraphicsItem::childrenBoundingRect2()
3441 {
3442     QGraphicsItemGroup box;
3443     QGraphicsLineItem l1(0, 0, 100, 0, &box);
3444     QGraphicsLineItem l2(100, 0, 100, 100, &box);
3445     QGraphicsLineItem l3(0, 0, 0, 100, &box);
3446     // Make sure lines (zero with/height) are included in the childrenBoundingRect.
3447     l1.setPen(QPen(Qt::black, 0));
3448     l2.setPen(QPen(Qt::black, 0));
3449     l3.setPen(QPen(Qt::black, 0));
3450     QCOMPARE(box.childrenBoundingRect(), QRectF(0, 0, 100, 100));
3451 }
3452
3453 void tst_QGraphicsItem::childrenBoundingRect3()
3454 {
3455     QGraphicsScene scene;
3456
3457     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
3458     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100));
3459     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100));
3460     QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100));
3461     QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100));
3462     rect2->setParentItem(rect);
3463     rect3->setParentItem(rect2);
3464     rect4->setParentItem(rect3);
3465     rect5->setParentItem(rect4);
3466
3467     rect->setPen(QPen(Qt::black, 0));
3468     rect2->setPen(QPen(Qt::black, 0));
3469     rect3->setPen(QPen(Qt::black, 0));
3470     rect4->setPen(QPen(Qt::black, 0));
3471     rect5->setPen(QPen(Qt::black, 0));
3472
3473     rect2->setTransform(QTransform().translate(50, 50).rotate(45));
3474     rect2->setPos(25, 25);
3475     rect3->setTransform(QTransform().translate(50, 50).rotate(45));
3476     rect3->setPos(25, 25);
3477     rect4->setTransform(QTransform().translate(50, 50).rotate(45));
3478     rect4->setPos(25, 25);
3479     rect5->setTransform(QTransform().translate(50, 50).rotate(45));
3480     rect5->setPos(25, 25);
3481
3482     // Try to mess up the cached bounding rect.
3483     (void)rect2->childrenBoundingRect();
3484
3485     QRectF subTreeRect = rect->childrenBoundingRect();
3486     QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821));
3487     QCOMPARE(subTreeRect.top(), qreal(75.0));
3488     QCOMPARE(subTreeRect.width(), qreal(351.7766952966369));
3489     QCOMPARE(subTreeRect.height(), qreal(251.7766952966369));
3490 }
3491
3492 void tst_QGraphicsItem::childrenBoundingRect4()
3493 {
3494     QGraphicsScene scene;
3495
3496     QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 10, 10));
3497     QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 20, 20));
3498     QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 30, 30));
3499     rect2->setParentItem(rect);
3500     rect3->setParentItem(rect);
3501
3502     QGraphicsView view(&scene);
3503     view.show();
3504
3505     QVERIFY(QTest::qWaitForWindowExposed(&view));
3506
3507     // Try to mess up the cached bounding rect.
3508     rect->childrenBoundingRect();
3509     rect2->childrenBoundingRect();
3510
3511     rect3->setOpacity(0.0);
3512     rect3->setParentItem(rect2);
3513
3514     QCOMPARE(rect->childrenBoundingRect(), rect3->boundingRect());
3515     QCOMPARE(rect2->childrenBoundingRect(), rect3->boundingRect());
3516 }
3517
3518 void tst_QGraphicsItem::childrenBoundingRect5()
3519 {
3520     QGraphicsScene scene;
3521
3522     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100));
3523     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100));
3524     child->setParentItem(parent);
3525
3526     parent->setPen(QPen(Qt::black, 0));
3527     child->setPen(QPen(Qt::black, 0));
3528
3529     QGraphicsView view(&scene);
3530     view.show();
3531
3532     QVERIFY(QTest::qWaitForWindowExposed(&view));
3533
3534     // Try to mess up the cached bounding rect.
3535     QRectF expectedChildrenBoundingRect = parent->boundingRect();
3536     QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect);
3537
3538     // Apply some effects.
3539     QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect;
3540     dropShadow->setOffset(25, 25);
3541     child->setGraphicsEffect(dropShadow);
3542     parent->setGraphicsEffect(new QGraphicsOpacityEffect);
3543
3544     QVERIFY(parent->childrenBoundingRect() != expectedChildrenBoundingRect);
3545     expectedChildrenBoundingRect |= dropShadow->boundingRect();
3546     QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect);
3547 }
3548
3549 void tst_QGraphicsItem::group()
3550 {
3551     QGraphicsScene scene;
3552     QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::green));
3553     QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::blue));
3554     QGraphicsRectItem *parent2 = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::red));
3555     parent2->setPos(-50, 50);
3556     child->rotate(45);
3557     child->setParentItem(parent);
3558     parent->setPos(25, 25);
3559     child->setPos(25, 25);
3560
3561     QCOMPARE(parent->group(), (QGraphicsItemGroup *)0);
3562     QCOMPARE(parent2->group(), (QGraphicsItemGroup *)0);
3563     QCOMPARE(child->group(), (QGraphicsItemGroup *)0);
3564
3565     QGraphicsView view(&scene);
3566     view.show();
3567     QVERIFY(QTest::qWaitForWindowExposed(&view));
3568
3569     QGraphicsItemGroup *group = new QGraphicsItemGroup;
3570     group->setSelected(true);
3571     scene.addItem(group);
3572
3573     QRectF parentSceneBoundingRect = parent->sceneBoundingRect();
3574     group->addToGroup(parent);
3575     QCOMPARE(parent->group(), group);
3576     QCOMPARE(parent->sceneBoundingRect(), parentSceneBoundingRect);
3577
3578     QCOMPARE(parent->parentItem(), (QGraphicsItem *)group);
3579     QCOMPARE(group->children().size(), 1);
3580     QCOMPARE(scene.items().size(), 4);
3581     QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 3);
3582
3583     QTest::qWait(25);
3584
3585     QRectF parent2SceneBoundingRect = parent2->sceneBoundingRect();
3586     group->addToGroup(parent2);
3587     QCOMPARE(parent2->group(), group);
3588     QCOMPARE(parent2->sceneBoundingRect(), parent2SceneBoundingRect);
3589
3590     QCOMPARE(parent2->parentItem(), (QGraphicsItem *)group);
3591     QCOMPARE(group->children().size(), 2);
3592     QCOMPARE(scene.items().size(), 4);
3593     QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 4);
3594
3595     QTest::qWait(25);
3596
3597     QList<QGraphicsItem *> newItems;
3598     for (int i = 0; i < 100; ++i) {
3599         QGraphicsItem *item = scene.addRect(QRectF(-25, -25, 50, 50), QPen(Qt::black, 0),
3600                                             QBrush(QColor(rand() % 255, rand() % 255,
3601                                                           rand() % 255, rand() % 255)));
3602         newItems << item;
3603         item->setPos(-1000 + rand() % 2000,
3604                      -1000 + rand() % 2000);
3605         item->rotate(rand() % 90);
3606     }
3607
3608     view.fitInView(scene.itemsBoundingRect());
3609
3610     int n = 0;
3611     foreach (QGraphicsItem *item, newItems) {
3612         group->addToGroup(item);
3613         QCOMPARE(item->group(), group);
3614         if ((n++ % 100) == 0)
3615             QTest::qWait(10);
3616     }
3617 }
3618
3619 void tst_QGraphicsItem::setGroup()
3620 {
3621     QGraphicsItemGroup group1;
3622     QGraphicsItemGroup group2;
3623
3624     QGraphicsRectItem *rect = new QGraphicsRectItem;
3625     QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
3626     QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
3627     rect->setGroup(&group1);
3628     QCOMPARE(rect->group(), &group1);
3629     QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group1);
3630     rect->setGroup(&group2);
3631     QCOMPARE(rect->group(), &group2);
3632     QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group2);
3633     rect->setGroup(0);
3634     QCOMPARE(rect->group(), (QGraphicsItemGroup *)0);
3635     QCOMPARE(rect->parentItem(), (QGraphicsItem *)0);
3636 }
3637
3638 void tst_QGraphicsItem::setGroup2()
3639 {
3640     QGraphicsScene scene;
3641     QGraphicsItemGroup group;
3642     scene.addItem(&group);
3643
3644     QGraphicsRectItem *rect = scene.addRect(50,50,50,50,Qt::NoPen,Qt::black);
3645     rect->setTransformOriginPoint(50,50);
3646     rect->setRotation(45);
3647     rect->setScale(1.5);
3648     rect->translate(20,20);
3649     group.translate(-30,-40);
3650     group.setRotation(180);
3651     group.setScale(0.5);
3652
3653     QTransform oldSceneTransform = rect->sceneTransform();
3654     rect->setGroup(&group);
3655     QCOMPARE(rect->sceneTransform(), oldSceneTransform);
3656
3657     group.setRotation(20);
3658     group.setScale(2);
3659     rect->setRotation(90);
3660     rect->setScale(0.8);
3661
3662     oldSceneTransform = rect->sceneTransform();
3663     rect->setGroup(0);
3664     QCOMPARE(rect->sceneTransform(), oldSceneTransform);
3665 }
3666
3667 void tst_QGraphicsItem::nestedGroups()
3668 {
3669     QGraphicsItemGroup *group1 = new QGraphicsItemGroup;
3670     QGraphicsItemGroup *group2 = new QGraphicsItemGroup;
3671
3672     QGraphicsRectItem *rect = new QGraphicsRectItem;
3673     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
3674     rect2->setParentItem(rect);
3675
3676     group1->addToGroup(rect);
3677     QCOMPARE(rect->group(), group1);
3678     QCOMPARE(rect2->group(), group1);
3679
3680     group2->addToGroup(group1);
3681     QCOMPARE(rect->group(), group1);
3682     QCOMPARE(rect2->group(), group1);
3683     QCOMPARE(group1->group(), group2);
3684     QCOMPARE(group2->group(), (QGraphicsItemGroup *)0);
3685
3686     QGraphicsScene scene;
3687     scene.addItem(group1);
3688
3689     QCOMPARE(rect->group(), group1);
3690     QCOMPARE(rect2->group(), group1);
3691     QCOMPARE(group1->group(), (QGraphicsItemGroup *)0);
3692     QVERIFY(group2->children().isEmpty());
3693
3694     delete group2;
3695 }
3696
3697 void tst_QGraphicsItem::warpChildrenIntoGroup()
3698 {
3699     QGraphicsScene scene;
3700     QGraphicsRectItem *parentRectItem = scene.addRect(QRectF(0, 0, 100, 100));
3701     QGraphicsRectItem *childRectItem = scene.addRect(QRectF(0, 0, 100, 100));
3702     parentRectItem->rotate(90);
3703     childRectItem->setPos(-50, -25);
3704     childRectItem->setParentItem(parentRectItem);
3705
3706     QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
3707     QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
3708
3709     QGraphicsRectItem *parentOfGroup = scene.addRect(QRectF(0, 0, 100, 100));
3710     parentOfGroup->setPos(-200, -200);
3711     parentOfGroup->scale(2, 2);
3712
3713     QGraphicsItemGroup *group = new QGraphicsItemGroup;
3714     group->setPos(50, 50);
3715     group->setParentItem(parentOfGroup);
3716
3717     QCOMPARE(group->scenePos(), QPointF(-100, -100));
3718
3719     group->addToGroup(childRectItem);
3720
3721     QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0));
3722     QCOMPARE(childRectItem->scenePos(), QPointF(25, -50));
3723 }
3724
3725 void tst_QGraphicsItem::removeFromGroup()
3726 {
3727     QGraphicsScene scene;
3728     QGraphicsRectItem *rect1 = scene.addRect(QRectF(-100, -100, 200, 200));
3729     QGraphicsRectItem *rect2 = scene.addRect(QRectF(100, 100, 200, 200));
3730     rect1->setFlag(QGraphicsItem::ItemIsSelectable);
3731     rect2->setFlag(QGraphicsItem::ItemIsSelectable);
3732     rect1->setSelected(true);
3733     rect2->setSelected(true);
3734
3735     QGraphicsView view(&scene);
3736     view.show();
3737
3738     qApp->processEvents(); // index items
3739     qApp->processEvents(); // emit changed
3740
3741     QGraphicsItemGroup *group = scene.createItemGroup(scene.selectedItems());
3742     QVERIFY(group);
3743     QCOMPARE(group->children().size(), 2);
3744     qApp->processEvents(); // index items
3745     qApp->processEvents(); // emit changed
3746
3747     scene.destroyItemGroup(group); // calls removeFromGroup.
3748
3749     qApp->processEvents(); // index items
3750     qApp->processEvents(); // emit changed
3751
3752     QCOMPARE(scene.items().size(), 2);
3753     QVERIFY(!rect1->group());
3754     QVERIFY(!rect2->group());
3755 }
3756
3757 class ChildEventTester : public QGraphicsRectItem
3758 {
3759 public:
3760     ChildEventTester(const QRectF &rect, QGraphicsItem *parent = 0)
3761         : QGraphicsRectItem(rect, parent), counter(0)
3762     { }
3763
3764     int counter;
3765
3766 protected:
3767     void focusInEvent(QFocusEvent *event)
3768     { ++counter; QGraphicsRectItem::focusInEvent(event); }
3769     void mousePressEvent(QGraphicsSceneMouseEvent *)
3770     { ++counter; }
3771     void mouseMoveEvent(QGraphicsSceneMouseEvent *)
3772     { ++counter; }
3773     void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
3774     { ++counter; }
3775 };
3776
3777 void tst_QGraphicsItem::handlesChildEvents()
3778 {
3779     ChildEventTester *blue = new ChildEventTester(QRectF(0, 0, 100, 100));
3780     ChildEventTester *red = new ChildEventTester(QRectF(0, 0, 50, 50));
3781     ChildEventTester *green = new ChildEventTester(QRectF(0, 0, 25, 25));
3782     ChildEventTester *gray = new ChildEventTester(QRectF(0, 0, 25, 25));
3783     ChildEventTester *yellow = new ChildEventTester(QRectF(0, 0, 50, 50));
3784
3785     blue->setBrush(QBrush(Qt::blue));
3786     red->setBrush(QBrush(Qt::red));
3787     yellow->setBrush(QBrush(Qt::yellow));
3788     green->setBrush(QBrush(Qt::green));
3789     gray->setBrush(QBrush(Qt::gray));
3790     red->setPos(50, 0);
3791     yellow->setPos(50, 50);
3792     green->setPos(25, 0);
3793     gray->setPos(25, 25);
3794     red->setParentItem(blue);
3795     yellow->setParentItem(blue);
3796     green->setParentItem(red);
3797     gray->setParentItem(red);
3798
3799     QGraphicsScene scene;
3800     scene.addItem(blue);
3801
3802     QGraphicsView view(&scene);
3803     view.show();
3804     QVERIFY(QTest::qWaitForWindowExposed(&view));
3805     QTest::qWait(20);
3806
3807     // Pull out the items, closest item first
3808     QList<QGraphicsItem *> items = scene.items(scene.itemsBoundingRect());
3809     QCOMPARE(items.at(0), (QGraphicsItem *)yellow);
3810     QCOMPARE(items.at(1), (QGraphicsItem *)gray);
3811     QCOMPARE(items.at(2), (QGraphicsItem *)green);
3812     QCOMPARE(items.at(3), (QGraphicsItem *)red);
3813     QCOMPARE(items.at(4), (QGraphicsItem *)blue);
3814
3815     QCOMPARE(blue->counter, 0);
3816
3817     // Send events to the toplevel item
3818     QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
3819     QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
3820
3821     pressEvent.setButton(Qt::LeftButton);
3822     pressEvent.setScenePos(blue->mapToScene(5, 5));
3823     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3824     releaseEvent.setButton(Qt::LeftButton);
3825     releaseEvent.setScenePos(blue->mapToScene(5, 5));
3826     releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3827     QApplication::sendEvent(&scene, &pressEvent);
3828     QApplication::sendEvent(&scene, &releaseEvent);
3829
3830     QCOMPARE(blue->counter, 2);
3831
3832     // Send events to a level1 item
3833     pressEvent.setScenePos(red->mapToScene(5, 5));
3834     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3835     releaseEvent.setScenePos(red->mapToScene(5, 5));
3836     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3837     QApplication::sendEvent(&scene, &pressEvent);
3838     QApplication::sendEvent(&scene, &releaseEvent);
3839
3840     QCOMPARE(blue->counter, 2);
3841     QCOMPARE(red->counter, 2);
3842
3843     // Send events to a level2 item
3844     pressEvent.setScenePos(green->mapToScene(5, 5));
3845     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3846     releaseEvent.setScenePos(green->mapToScene(5, 5));
3847     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3848     QApplication::sendEvent(&scene, &pressEvent);
3849     QApplication::sendEvent(&scene, &releaseEvent);
3850
3851     QCOMPARE(blue->counter, 2);
3852     QCOMPARE(red->counter, 2);
3853     QCOMPARE(green->counter, 2);
3854
3855     blue->setHandlesChildEvents(true);
3856
3857     // Send events to a level1 item
3858     pressEvent.setScenePos(red->mapToScene(5, 5));
3859     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3860     releaseEvent.setScenePos(red->mapToScene(5, 5));
3861     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3862     QApplication::sendEvent(&scene, &pressEvent);
3863     QApplication::sendEvent(&scene, &releaseEvent);
3864
3865     QCOMPARE(blue->counter, 4);
3866     QCOMPARE(red->counter, 2);
3867
3868     // Send events to a level2 item
3869     pressEvent.setScenePos(green->mapToScene(5, 5));
3870     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3871     releaseEvent.setScenePos(green->mapToScene(5, 5));
3872     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3873     QApplication::sendEvent(&scene, &pressEvent);
3874     QApplication::sendEvent(&scene, &releaseEvent);
3875
3876     QCOMPARE(blue->counter, 6);
3877     QCOMPARE(red->counter, 2);
3878     QCOMPARE(green->counter, 2);
3879
3880     blue->setHandlesChildEvents(false);
3881
3882     // Send events to a level1 item
3883     pressEvent.setScenePos(red->mapToScene(5, 5));
3884     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3885     releaseEvent.setScenePos(red->mapToScene(5, 5));
3886     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3887     QApplication::sendEvent(&scene, &pressEvent);
3888     QApplication::sendEvent(&scene, &releaseEvent);
3889
3890     QCOMPARE(blue->counter, 6);
3891     QCOMPARE(red->counter, 4);
3892
3893     // Send events to a level2 item
3894     pressEvent.setScenePos(green->mapToScene(5, 5));
3895     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
3896     releaseEvent.setScenePos(green->mapToScene(5, 5));
3897     releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos()));
3898     QApplication::sendEvent(&scene, &pressEvent);
3899     QApplication::sendEvent(&scene, &releaseEvent);
3900
3901     QCOMPARE(blue->counter, 6);
3902     QCOMPARE(red->counter, 4);
3903     QCOMPARE(green->counter, 4);
3904 }
3905
3906 void tst_QGraphicsItem::handlesChildEvents2()
3907 {
3908     ChildEventTester *root = new ChildEventTester(QRectF(0, 0, 10, 10));
3909     root->setHandlesChildEvents(true);
3910     QVERIFY(root->handlesChildEvents());
3911
3912     ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
3913     QVERIFY(!child->handlesChildEvents());
3914
3915     ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10));
3916     ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2);
3917     ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3);
3918     child2->setParentItem(root);
3919     QVERIFY(!child2->handlesChildEvents());
3920     QVERIFY(!child3->handlesChildEvents());
3921     QVERIFY(!child4->handlesChildEvents());
3922
3923     QGraphicsScene scene;
3924     scene.addItem(root);
3925
3926     QGraphicsView view(&scene);
3927     view.show();
3928     QVERIFY(QTest::qWaitForWindowExposed(&view));
3929     QApplication::processEvents();
3930
3931     QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
3932                       view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
3933     QApplication::sendEvent(view.viewport(), &event);
3934
3935     QTRY_COMPARE(root->counter, 1);
3936 }
3937
3938 void tst_QGraphicsItem::handlesChildEvents3()
3939 {
3940     QGraphicsScene scene;
3941     QEvent activate(QEvent::WindowActivate);
3942     QApplication::sendEvent(&scene, &activate);
3943
3944     ChildEventTester *group2 = new ChildEventTester(QRectF(), 0);
3945     ChildEventTester *group1 = new ChildEventTester(QRectF(), group2);
3946     ChildEventTester *leaf = new ChildEventTester(QRectF(), group1);
3947     scene.addItem(group2);
3948
3949     leaf->setFlag(QGraphicsItem::ItemIsFocusable);
3950     group1->setFlag(QGraphicsItem::ItemIsFocusable);
3951     group1->setHandlesChildEvents(true);
3952     group2->setFlag(QGraphicsItem::ItemIsFocusable);
3953     group2->setHandlesChildEvents(true);
3954
3955     leaf->setFocus();
3956     QVERIFY(leaf->hasFocus()); // group2 stole the event, but leaf still got focus
3957     QVERIFY(!group1->hasFocus());
3958     QVERIFY(!group2->hasFocus());
3959     QCOMPARE(leaf->counter, 0);
3960     QCOMPARE(group1->counter, 0);
3961     QCOMPARE(group2->counter, 1);
3962
3963     group1->setFocus();
3964     QVERIFY(group1->hasFocus()); // group2 stole the event, but group1 still got focus
3965     QVERIFY(!leaf->hasFocus());
3966     QVERIFY(!group2->hasFocus());
3967     QCOMPARE(leaf->counter, 0);
3968     QCOMPARE(group1->counter, 0);
3969     QCOMPARE(group2->counter, 2);
3970
3971     group2->setFocus();
3972     QVERIFY(group2->hasFocus()); // group2 stole the event, and now group2 also has focus
3973     QVERIFY(!leaf->hasFocus());
3974     QVERIFY(!group1->hasFocus());
3975     QCOMPARE(leaf->counter, 0);
3976     QCOMPARE(group1->counter, 0);
3977     QCOMPARE(group2->counter, 3);
3978 }
3979
3980
3981 class ChildEventFilterTester : public ChildEventTester
3982 {
3983 public:
3984     ChildEventFilterTester(const QRectF &rect, QGraphicsItem *parent = 0)
3985         : ChildEventTester(rect, parent), filter(QEvent::None)
3986     { }
3987
3988     QEvent::Type filter;
3989
3990 protected:
3991     bool sceneEventFilter(QGraphicsItem *item, QEvent *event)
3992     {
3993         Q_UNUSED(item);
3994         if (event->type() == filter) {
3995             ++counter;
3996             return true;
3997         }
3998         return false;
3999     }
4000 };
4001
4002 void tst_QGraphicsItem::filtersChildEvents()
4003 {
4004     QGraphicsScene scene;
4005     ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
4006     ChildEventFilterTester *filter = new ChildEventFilterTester(QRectF(10, 10, 10, 10), root);
4007     ChildEventTester *child = new ChildEventTester(QRectF(20, 20, 10, 10), filter);
4008
4009     // setup filter
4010     filter->setFiltersChildEvents(true);
4011     filter->filter = QEvent::GraphicsSceneMousePress;
4012
4013     scene.addItem(root);
4014
4015     QGraphicsView view(&scene);
4016     view.show();
4017     QVERIFY(QTest::qWaitForWindowExposed(&view));
4018     QTest::qWait(20);
4019
4020     QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
4021     QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
4022
4023     // send event to child
4024     pressEvent.setButton(Qt::LeftButton);
4025     pressEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
4026     pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
4027     releaseEvent.setButton(Qt::LeftButton);
4028     releaseEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5));
4029     releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos()));
4030     QApplication::sendEvent(&scene, &pressEvent);
4031     QApplication::sendEvent(&scene, &releaseEvent);
4032
4033     QTRY_COMPARE(child->counter, 1);  // mouse release is not filtered
4034     QCOMPARE(filter->counter, 1); // mouse press is filtered
4035     QCOMPARE(root->counter, 0);
4036
4037     // add another filter
4038     root->setFiltersChildEvents(true);
4039     root->filter = QEvent::GraphicsSceneMouseRelease;
4040
4041     // send event to child
4042     QApplication::sendEvent(&scene, &pressEvent);
4043     QApplication::sendEvent(&scene, &releaseEvent);
4044
4045     QCOMPARE(child->counter, 1);
4046     QCOMPARE(filter->counter, 2); // mouse press is filtered
4047     QCOMPARE(root->counter, 1); // mouse release is filtered
4048
4049     // reparent to another sub-graph
4050     ChildEventTester *parent = new ChildEventTester(QRectF(10, 10, 10, 10), root);
4051     child->setParentItem(parent);
4052
4053     // send event to child
4054     QApplication::sendEvent(&scene, &pressEvent);
4055     QApplication::sendEvent(&scene, &releaseEvent);
4056
4057     QCOMPARE(child->counter, 2); // mouse press is _not_ filtered
4058     QCOMPARE(parent->counter, 0);
4059     QCOMPARE(filter->counter, 2);
4060     QCOMPARE(root->counter, 2); // mouse release is filtered
4061 }
4062
4063 void tst_QGraphicsItem::filtersChildEvents2()
4064 {
4065     ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10));
4066     root->setFiltersChildEvents(true);
4067     root->filter = QEvent::GraphicsSceneMousePress;
4068     QVERIFY(root->filtersChildEvents());
4069
4070     ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root);
4071     QVERIFY(!child->filtersChildEvents());
4072
4073     ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10));
4074     ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2);
4075     ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3);
4076
4077     child2->setParentItem(root);
4078     QVERIFY(!child2->filtersChildEvents());
4079     QVERIFY(!child3->filtersChildEvents());
4080     QVERIFY(!child4->filtersChildEvents());
4081
4082     QGraphicsScene scene;
4083     scene.addItem(root);
4084
4085     QGraphicsView view(&scene);
4086     view.show();
4087
4088     QVERIFY(QTest::qWaitForWindowExposed(&view));
4089     QApplication::processEvents();
4090
4091     QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5),
4092                       view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0);
4093     QApplication::sendEvent(view.viewport(), &event);
4094
4095     QTRY_COMPARE(root->counter, 1);
4096     QCOMPARE(child->counter, 0);
4097     QCOMPARE(child2->counter, 0);
4098     QCOMPARE(child3->counter, 0);
4099     QCOMPARE(child4->counter, 0);
4100 }
4101
4102 class CustomItem : public QGraphicsItem
4103 {
4104 public:
4105     QRectF boundingRect() const
4106     { return QRectF(-110, -110, 220, 220); }
4107
4108     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
4109     {
4110         for (int x = -100; x <= 100; x += 25)
4111             painter->drawLine(x, -100, x, 100);
4112         for (int y = -100; y <= 100; y += 25)
4113             painter->drawLine(-100, y, 100, y);
4114
4115         QFont font = painter->font();
4116         font.setPointSize(4);
4117         painter->setFont(font);
4118         for (int x = -100; x < 100; x += 25) {
4119             for (int y = -100; y < 100; y += 25) {
4120                 painter->drawText(QRectF(x, y, 25, 25), Qt::AlignCenter, QString("%1x%2").arg(x).arg(y));
4121             }
4122         }
4123     }
4124 };
4125
4126 void tst_QGraphicsItem::ensureVisible()
4127 {
4128     QGraphicsScene scene;
4129     scene.setSceneRect(-200, -200, 400, 400);
4130     QGraphicsItem *item = new CustomItem;
4131     scene.addItem(item);
4132
4133     QGraphicsView view(&scene);
4134     view.setFixedSize(300, 300);
4135     view.show();
4136     QVERIFY(QTest::qWaitForWindowExposed(&view));
4137
4138     for (int i = 0; i < 25; ++i) {
4139         view.scale(qreal(1.06), qreal(1.06));
4140         QApplication::processEvents();
4141     }
4142
4143     item->ensureVisible(-100, -100, 25, 25);
4144     QTest::qWait(25);
4145
4146     for (int x = -100; x < 100; x += 25) {
4147         for (int y = -100; y < 100; y += 25) {
4148             int xmargin = rand() % 75;
4149             int ymargin = rand() % 75;
4150             item->ensureVisible(x, y, 25, 25, xmargin, ymargin);
4151             QApplication::processEvents();
4152
4153             QPolygonF viewScenePoly;
4154             viewScenePoly << view.mapToScene(view.rect().topLeft())
4155                           << view.mapToScene(view.rect().topRight())
4156                           << view.mapToScene(view.rect().bottomRight())
4157                           << view.mapToScene(view.rect().bottomLeft());
4158
4159             QVERIFY(scene.items(viewScenePoly).contains(item));
4160
4161             QPainterPath path;
4162             path.addPolygon(viewScenePoly);
4163             QVERIFY(path.contains(item->mapToScene(x + 12, y + 12)));
4164
4165             QPolygonF viewScenePolyMinusMargins;
4166             viewScenePolyMinusMargins << view.mapToScene(view.rect().topLeft() + QPoint(xmargin, ymargin))
4167                           << view.mapToScene(view.rect().topRight() + QPoint(-xmargin, ymargin))
4168                           << view.mapToScene(view.rect().bottomRight() + QPoint(-xmargin, -ymargin))
4169                           << view.mapToScene(view.rect().bottomLeft() + QPoint(xmargin, -ymargin));
4170
4171             QPainterPath path2;
4172             path2.addPolygon(viewScenePolyMinusMargins);
4173             QVERIFY(path2.contains(item->mapToScene(x + 12, y + 12)));
4174         }
4175     }
4176
4177     item->ensureVisible(100, 100, 25, 25);
4178     QTest::qWait(25);
4179 }
4180
4181 #ifndef QTEST_NO_CURSOR
4182 void tst_QGraphicsItem::cursor()
4183 {
4184     QGraphicsScene scene;
4185     QGraphicsRectItem *item1 = scene.addRect(QRectF(0, 0, 50, 50));
4186     QGraphicsRectItem *item2 = scene.addRect(QRectF(0, 0, 50, 50));
4187     item1->setPos(-100, 0);
4188     item2->setPos(50, 0);
4189
4190     QVERIFY(!item1->hasCursor());
4191     QVERIFY(!item2->hasCursor());
4192
4193     item1->setCursor(Qt::IBeamCursor);
4194     item2->setCursor(Qt::PointingHandCursor);
4195
4196     QVERIFY(item1->hasCursor());
4197     QVERIFY(item2->hasCursor());
4198
4199     item1->setCursor(QCursor());
4200     item2->setCursor(QCursor());
4201
4202     QVERIFY(item1->hasCursor());
4203     QVERIFY(item2->hasCursor());
4204
4205     item1->unsetCursor();
4206     item2->unsetCursor();
4207
4208     QVERIFY(!item1->hasCursor());
4209     QVERIFY(!item2->hasCursor());
4210
4211     item1->setCursor(Qt::IBeamCursor);
4212     item2->setCursor(Qt::PointingHandCursor);
4213
4214     QWidget topLevel;
4215     QGraphicsView view(&scene,&topLevel);
4216     view.setFixedSize(200, 100);
4217     topLevel.show();
4218     QTest::mouseMove(&view, view.rect().center());
4219
4220     QTest::qWait(25);
4221
4222     QCursor cursor = view.viewport()->cursor();
4223
4224     {
4225         QMouseEvent event(QEvent::MouseMove, QPoint(100, 50), Qt::NoButton, 0, 0);
4226         QApplication::sendEvent(view.viewport(), &event);
4227     }
4228
4229     QTest::qWait(25);
4230
4231     QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
4232
4233     {
4234         QTest::mouseMove(view.viewport(), view.mapFromScene(item1->sceneBoundingRect().center()));
4235         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
4236         QApplication::sendEvent(view.viewport(), &event);
4237     }
4238
4239     QCOMPARE(view.viewport()->cursor().shape(), item1->cursor().shape());
4240
4241     {
4242         QTest::mouseMove(view.viewport(), view.mapFromScene(item2->sceneBoundingRect().center()));
4243         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item2->sceneBoundingRect().center()), Qt::NoButton, 0, 0);
4244         QApplication::sendEvent(view.viewport(), &event);
4245     }
4246
4247     QTest::qWait(25);
4248
4249     QCOMPARE(view.viewport()->cursor().shape(), item2->cursor().shape());
4250
4251     {
4252         QTest::mouseMove(view.viewport(), view.rect().center());
4253         QMouseEvent event(QEvent::MouseMove, QPoint(100, 25), Qt::NoButton, 0, 0);
4254         QApplication::sendEvent(view.viewport(), &event);
4255     }
4256
4257     QTest::qWait(25);
4258
4259     QCOMPARE(view.viewport()->cursor().shape(), cursor.shape());
4260 }
4261 #endif
4262 /*
4263 void tst_QGraphicsItem::textControlGetterSetter()
4264 {
4265     QGraphicsTextItem *item = new QGraphicsTextItem;
4266     QVERIFY(item->textControl()->parent() == item);
4267     QPointer<QWidgetTextControl> control = item->textControl();
4268     delete item;
4269     QVERIFY(!control);
4270
4271     item = new QGraphicsTextItem;
4272
4273     QPointer<QWidgetTextControl> oldControl = control;
4274     control = new QWidgetTextControl;
4275
4276     item->setTextControl(control);
4277     QVERIFY(item->textControl() == control);
4278     QVERIFY(!control->parent());
4279     QVERIFY(!oldControl);
4280
4281     // set some text to give it a size, to test that
4282     // setTextControl (re)connects signals
4283     const QRectF oldBoundingRect = item->boundingRect();
4284     QVERIFY(oldBoundingRect.isValid());
4285     item->setPlainText("Some text");
4286     item->adjustSize();
4287     QVERIFY(item->boundingRect().isValid());
4288     QVERIFY(item->boundingRect() != oldBoundingRect);
4289
4290     // test that on setting a control the item size
4291     // is adjusted
4292     oldControl = control;
4293     control = new QWidgetTextControl;
4294     control->setPlainText("foo!");
4295     item->setTextControl(control);
4296     QCOMPARE(item->boundingRect().size(), control->document()->documentLayout()->documentSize());
4297
4298     QVERIFY(oldControl);
4299     delete oldControl;
4300
4301     delete item;
4302     QVERIFY(control);
4303     delete control;
4304 }
4305 */
4306
4307 void tst_QGraphicsItem::defaultItemTest_QGraphicsLineItem()
4308 {
4309     QGraphicsLineItem item;
4310     QCOMPARE(item.line(), QLineF());
4311     QCOMPARE(item.pen(), QPen());
4312     QCOMPARE(item.shape(), QPainterPath());
4313
4314     item.setPen(QPen(Qt::black, 1));
4315     QCOMPARE(item.pen(), QPen(Qt::black, 1));
4316     item.setLine(QLineF(0, 0, 10, 0));
4317     QCOMPARE(item.line(), QLineF(0, 0, 10, 0));
4318     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 11, 1));
4319     QCOMPARE(item.shape().elementCount(), 11);
4320
4321     QPainterPath path;
4322     path.moveTo(0, -0.5);
4323     path.lineTo(10, -0.5);
4324     path.lineTo(10.5, -0.5);
4325     path.lineTo(10.5, 0.5);
4326     path.lineTo(10, 0.5);
4327     path.lineTo(0, 0.5);
4328     path.lineTo(-0.5, 0.5);
4329     path.lineTo(-0.5, -0.5);
4330     path.lineTo(0, -0.5);
4331     path.lineTo(0, 0);
4332     path.lineTo(10, 0);
4333     path.closeSubpath();
4334
4335     for (int i = 0; i < 11; ++i)
4336         QCOMPARE(QPointF(item.shape().elementAt(i)), QPointF(path.elementAt(i)));
4337 }
4338
4339 void tst_QGraphicsItem::defaultItemTest_QGraphicsPixmapItem()
4340 {
4341     QGraphicsPixmapItem item;
4342     QVERIFY(item.pixmap().isNull());
4343     QCOMPARE(item.offset(), QPointF());
4344     QCOMPARE(item.transformationMode(), Qt::FastTransformation);
4345
4346     QPixmap pixmap(300, 200);
4347     pixmap.fill(Qt::red);
4348     item.setPixmap(pixmap);
4349     QCOMPARE(item.pixmap(), pixmap);
4350
4351     item.setTransformationMode(Qt::FastTransformation);
4352     QCOMPARE(item.transformationMode(), Qt::FastTransformation);
4353     item.setTransformationMode(Qt::SmoothTransformation);
4354     QCOMPARE(item.transformationMode(), Qt::SmoothTransformation);
4355
4356     item.setOffset(-15, -15);
4357     QCOMPARE(item.offset(), QPointF(-15, -15));
4358     item.setOffset(QPointF(-10, -10));
4359     QCOMPARE(item.offset(), QPointF(-10, -10));
4360
4361     QCOMPARE(item.boundingRect(), QRectF(-10, -10, 300, 200));
4362 }
4363
4364 void tst_QGraphicsItem::defaultItemTest_QGraphicsTextItem()
4365 {
4366     QGraphicsTextItem *text = new QGraphicsTextItem;
4367     QVERIFY(!text->openExternalLinks());
4368     QVERIFY(text->textCursor().isNull());
4369     QCOMPARE(text->defaultTextColor(), QPalette().color(QPalette::Text));
4370     QVERIFY(text->document() != 0);
4371     QCOMPARE(text->font(), QApplication::font());
4372     QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::NoTextInteraction));
4373     QCOMPARE(text->textWidth(), -1.0);
4374     QCOMPARE(text->toPlainText(), QString(""));
4375
4376     QGraphicsScene scene;
4377     scene.addItem(text);
4378     text->setPlainText("Hello world");
4379     text->setFlag(QGraphicsItem::ItemIsMovable);
4380
4381     {
4382         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
4383         event.setScenePos(QPointF(1, 1));
4384         event.setButton(Qt::LeftButton);
4385         event.setButtons(Qt::LeftButton);
4386         QApplication::sendEvent(&scene, &event);
4387         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
4388         event2.setScenePos(QPointF(11, 11));
4389         event2.setButton(Qt::LeftButton);
4390         event2.setButtons(Qt::LeftButton);
4391         QApplication::sendEvent(&scene, &event2);
4392     }
4393
4394     QCOMPARE(text->pos(), QPointF(10, 10));
4395
4396     text->setTextInteractionFlags(Qt::NoTextInteraction);
4397     QVERIFY(!(text->flags() & QGraphicsItem::ItemAcceptsInputMethod));
4398     text->setTextInteractionFlags(Qt::TextEditorInteraction);
4399     QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::TextEditorInteraction));
4400     QVERIFY(text->flags() & QGraphicsItem::ItemAcceptsInputMethod);
4401
4402     {
4403         QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
4404         event2.setScenePos(QPointF(21, 21));
4405         event2.setButton(Qt::LeftButton);
4406         event2.setButtons(Qt::LeftButton);
4407         QApplication::sendEvent(&scene, &event2);
4408     }
4409
4410     QCOMPARE(text->pos(), QPointF(20, 20)); // clicked on edge, item moved
4411 }
4412
4413 void tst_QGraphicsItem::defaultItemTest_QGraphicsEllipseItem()
4414 {
4415     QGraphicsEllipseItem item;
4416     item.setPen(QPen(Qt::black, 0));
4417     QVERIFY(item.rect().isNull());
4418     QVERIFY(item.boundingRect().isNull());
4419     QVERIFY(item.shape().isEmpty());
4420     QCOMPARE(item.spanAngle(), 360 * 16);
4421     QCOMPARE(item.startAngle(), 0);
4422
4423     item.setRect(0, 0, 100, 100);
4424     QCOMPARE(item.boundingRect(), QRectF(0, 0, 100, 100));
4425
4426     item.setSpanAngle(90 * 16);
4427     qFuzzyCompare(item.boundingRect().left(), qreal(50.0));
4428     qFuzzyCompare(item.boundingRect().top(), qreal(0.0));
4429     qFuzzyCompare(item.boundingRect().width(), qreal(50.0));
4430     qFuzzyCompare(item.boundingRect().height(), qreal(50.0));
4431
4432     item.setPen(QPen(Qt::black, 1));
4433     QCOMPARE(item.boundingRect(), QRectF(49.5, -0.5, 51, 51));
4434
4435     item.setSpanAngle(180 * 16);
4436     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 51));
4437
4438     item.setSpanAngle(360 * 16);
4439     QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 101));
4440 }
4441
4442 class ItemChangeTester : public QGraphicsRectItem
4443 {
4444 public:
4445     ItemChangeTester()
4446     { setFlag(ItemSendsGeometryChanges); clear(); }
4447     ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent)
4448     { setFlag(ItemSendsGeometryChanges); clear(); }
4449
4450     void clear()
4451     {
4452         itemChangeReturnValue = QVariant();
4453         itemSceneChangeTargetScene = 0;
4454         changes.clear();
4455         values.clear();
4456         oldValues.clear();
4457     }
4458
4459     QVariant itemChangeReturnValue;
4460     QGraphicsScene *itemSceneChangeTargetScene;
4461
4462     QList<GraphicsItemChange> changes;
4463     QList<QVariant> values;
4464     QList<QVariant> oldValues;
4465 protected:
4466     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
4467     {
4468         changes << change;
4469         values << value;
4470         switch (change) {
4471         case QGraphicsItem::ItemPositionChange:
4472             oldValues << pos();
4473             break;
4474         case QGraphicsItem::ItemPositionHasChanged:
4475             break;
4476         case QGraphicsItem::ItemMatrixChange: {
4477             QVariant variant;
4478             variant.setValue<QMatrix>(matrix());
4479             oldValues << variant;
4480         }
4481             break;
4482         case QGraphicsItem::ItemTransformChange: {
4483             QVariant variant;
4484             variant.setValue<QTransform>(transform());
4485             oldValues << variant;
4486         }
4487             break;
4488         case QGraphicsItem::ItemTransformHasChanged:
4489             break;
4490         case QGraphicsItem::ItemVisibleChange:
4491             oldValues << isVisible();
4492             break;
4493         case QGraphicsItem::ItemVisibleHasChanged:
4494             break;
4495         case QGraphicsItem::ItemEnabledChange:
4496             oldValues << isEnabled();
4497             break;
4498         case QGraphicsItem::ItemEnabledHasChanged:
4499             break;
4500         case QGraphicsItem::ItemSelectedChange:
4501             oldValues << isSelected();
4502             break;
4503         case QGraphicsItem::ItemSelectedHasChanged:
4504             break;
4505         case QGraphicsItem::ItemParentChange:
4506             oldValues << QVariant::fromValue<void *>(parentItem());
4507             break;
4508         case QGraphicsItem::ItemParentHasChanged:
4509             break;
4510         case QGraphicsItem::ItemChildAddedChange:
4511             oldValues << children().size();
4512             break;
4513         case QGraphicsItem::ItemChildRemovedChange:
4514             oldValues << children().size();
4515             break;
4516         case QGraphicsItem::ItemSceneChange:
4517             oldValues << QVariant::fromValue<QGraphicsScene *>(scene());
4518             if (itemSceneChangeTargetScene
4519                 && qvariant_cast<QGraphicsScene *>(value)
4520                 && itemSceneChangeTargetScene != qvariant_cast<QGraphicsScene *>(value)) {
4521                 return QVariant::fromValue<QGraphicsScene *>(itemSceneChangeTargetScene);
4522             }
4523             return value;
4524         case QGraphicsItem::ItemSceneHasChanged:
4525             break;
4526         case QGraphicsItem::ItemCursorChange:
4527 #ifndef QTEST_NO_CURSOR
4528             oldValues << cursor();
4529 #endif
4530             break;
4531         case QGraphicsItem::ItemCursorHasChanged:
4532             break;
4533         case QGraphicsItem::ItemToolTipChange:
4534             oldValues << toolTip();
4535             break;
4536         case QGraphicsItem::ItemToolTipHasChanged:
4537             break;
4538         case QGraphicsItem::ItemFlagsChange:
4539             oldValues << quint32(flags());
4540             break;
4541         case QGraphicsItem::ItemFlagsHaveChanged:
4542             break;
4543         case QGraphicsItem::ItemZValueChange:
4544             oldValues << zValue();
4545             break;
4546         case QGraphicsItem::ItemZValueHasChanged:
4547             break;
4548         case QGraphicsItem::ItemOpacityChange:
4549             oldValues << opacity();
4550             break;
4551         case QGraphicsItem::ItemOpacityHasChanged:
4552             break;
4553         case QGraphicsItem::ItemScenePositionHasChanged:
4554             break;
4555         case QGraphicsItem::ItemRotationChange:
4556             oldValues << rotation();
4557             break;
4558         case QGraphicsItem::ItemRotationHasChanged:
4559             break;
4560         case QGraphicsItem::ItemScaleChange:
4561             oldValues << scale();
4562             break;
4563         case QGraphicsItem::ItemScaleHasChanged:
4564             break;
4565         case QGraphicsItem::ItemTransformOriginPointChange:
4566             oldValues << transformOriginPoint();
4567             break;
4568         case QGraphicsItem::ItemTransformOriginPointHasChanged:
4569             break;
4570         }
4571         return itemChangeReturnValue.isValid() ? itemChangeReturnValue : value;
4572     }
4573 };
4574
4575 void tst_QGraphicsItem::itemChange()
4576 {
4577     ItemChangeTester tester;
4578     tester.itemSceneChangeTargetScene = 0;
4579
4580     ItemChangeTester testerHelper;
4581     QVERIFY(tester.changes.isEmpty());
4582     QVERIFY(tester.values.isEmpty());
4583
4584     int changeCount = 0;
4585     {
4586         // ItemEnabledChange
4587         tester.itemChangeReturnValue = true;
4588         tester.setEnabled(false);
4589         ++changeCount;
4590         ++changeCount; // HasChanged
4591         QCOMPARE(tester.changes.size(), changeCount);
4592         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemEnabledChange);
4593         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemEnabledHasChanged);
4594         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
4595         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
4596         QCOMPARE(tester.oldValues.last(), QVariant(true));
4597         QCOMPARE(tester.isEnabled(), true);
4598     }
4599     {
4600         // ItemMatrixChange / ItemTransformHasChanged
4601         tester.itemChangeReturnValue.setValue<QMatrix>(QMatrix().rotate(90));
4602         tester.setMatrix(QMatrix().translate(50, 0), true);
4603         ++changeCount; // notification sent too
4604         QCOMPARE(tester.changes.size(), ++changeCount);
4605         QCOMPARE(int(tester.changes.at(tester.changes.size() - 2)), int(QGraphicsItem::ItemMatrixChange));
4606         QCOMPARE(int(tester.changes.last()), int(QGraphicsItem::ItemTransformHasChanged));
4607         QCOMPARE(qvariant_cast<QMatrix>(tester.values.at(tester.values.size() - 2)),
4608                  QMatrix().translate(50, 0));
4609         QCOMPARE(tester.values.last(), QVariant(QTransform(QMatrix().rotate(90))));
4610         QVariant variant;
4611         variant.setValue<QMatrix>(QMatrix());
4612         QCOMPARE(tester.oldValues.last(), variant);
4613         QCOMPARE(tester.matrix(), QMatrix().rotate(90));
4614     }
4615     {
4616         tester.resetTransform();
4617         ++changeCount;
4618         ++changeCount; // notification sent too
4619
4620         // ItemTransformChange / ItemTransformHasChanged
4621         tester.itemChangeReturnValue.setValue<QTransform>(QTransform().rotate(90));
4622         tester.translate(50, 0);
4623         ++changeCount; // notification sent too
4624         ++changeCount;
4625         QCOMPARE(tester.changes.size(), changeCount);
4626         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformChange);
4627         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformHasChanged);
4628         QCOMPARE(qvariant_cast<QTransform>(tester.values.at(tester.values.size() - 2)),
4629                  QTransform().translate(50, 0));
4630         QCOMPARE(qvariant_cast<QTransform>(tester.values.at(tester.values.size() - 1)),
4631                  QTransform().rotate(90));
4632         QVariant variant;
4633         variant.setValue<QTransform>(QTransform());
4634         QCOMPARE(tester.oldValues.last(), variant);
4635         QCOMPARE(tester.transform(), QTransform().rotate(90));
4636     }
4637     {
4638         // ItemPositionChange / ItemPositionHasChanged
4639         tester.itemChangeReturnValue = QPointF(42, 0);
4640         tester.setPos(0, 42);
4641         ++changeCount; // notification sent too
4642         ++changeCount;
4643         QCOMPARE(tester.changes.size(), changeCount);
4644         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemPositionChange);
4645         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemPositionHasChanged);
4646         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(0, 42)));
4647         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(42, 0)));
4648         QCOMPARE(tester.oldValues.last(), QVariant(QPointF()));
4649         QCOMPARE(tester.pos(), QPointF(42, 0));
4650     }
4651     {
4652         // ItemZValueChange / ItemZValueHasChanged
4653         tester.itemChangeReturnValue = qreal(2.0);
4654         tester.setZValue(1.0);
4655         ++changeCount; // notification sent too
4656         ++changeCount;
4657         QCOMPARE(tester.changes.size(), changeCount);
4658         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemZValueChange);
4659         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemZValueHasChanged);
4660         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.0)));
4661         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0)));
4662         QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0)));
4663         QCOMPARE(tester.zValue(), qreal(2.0));
4664     }
4665     {
4666         // ItemRotationChange / ItemRotationHasChanged
4667         tester.itemChangeReturnValue = qreal(15.0);
4668         tester.setRotation(10.0);
4669         ++changeCount; // notification sent too
4670         ++changeCount;
4671         QCOMPARE(tester.changes.size(), changeCount);
4672         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemRotationChange);
4673         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemRotationHasChanged);
4674         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(10.0)));
4675         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(15.0)));
4676         QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0)));
4677         QCOMPARE(tester.rotation(), qreal(15.0));
4678     }
4679     {
4680         // ItemScaleChange / ItemScaleHasChanged
4681         tester.itemChangeReturnValue = qreal(2.0);
4682         tester.setScale(1.5);
4683         ++changeCount; // notification sent too
4684         ++changeCount;
4685         QCOMPARE(tester.changes.size(), changeCount);
4686         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemScaleChange);
4687         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemScaleHasChanged);
4688         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.5)));
4689         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0)));
4690         QCOMPARE(tester.oldValues.last(), QVariant(qreal(1.0)));
4691         QCOMPARE(tester.scale(), qreal(2.0));
4692     }
4693     {
4694         // ItemTransformOriginPointChange / ItemTransformOriginPointHasChanged
4695         tester.itemChangeReturnValue = QPointF(2.0, 2.0);
4696         tester.setTransformOriginPoint(1.0, 1.0);
4697         ++changeCount; // notification sent too
4698         ++changeCount;
4699         QCOMPARE(tester.changes.size(), changeCount);
4700         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformOriginPointChange);
4701         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformOriginPointHasChanged);
4702         QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(1.0, 1.0)));
4703         QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(2.0, 2.0)));
4704         QCOMPARE(tester.oldValues.last(), QVariant(QPointF(0.0, 0.0)));
4705         QCOMPARE(tester.transformOriginPoint(), QPointF(2.0, 2.0));
4706     }
4707     {
4708         // ItemFlagsChange
4709         tester.itemChangeReturnValue = QGraphicsItem::ItemIsSelectable;
4710         tester.setFlag(QGraphicsItem::ItemIsSelectable, false);
4711         QCOMPARE(tester.changes.size(), changeCount);  // No change
4712         tester.setFlag(QGraphicsItem::ItemIsSelectable, true);
4713         ++changeCount;
4714         ++changeCount; // ItemFlagsHasChanged
4715         QCOMPARE(tester.changes.size(), changeCount);
4716         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemFlagsChange);
4717         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemFlagsHaveChanged);
4718         QVariant expectedFlags = QVariant::fromValue<quint32>(QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges));
4719         QCOMPARE(tester.values.at(tester.values.size() - 2), expectedFlags);
4720         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant::fromValue<quint32>((quint32)QGraphicsItem::ItemIsSelectable));
4721     }
4722     {
4723         // ItemSelectedChange
4724         tester.setSelected(false);
4725         QCOMPARE(tester.changes.size(), changeCount); // No change :-)
4726         tester.itemChangeReturnValue = true;
4727         tester.setSelected(true);
4728         ++changeCount;
4729         ++changeCount; // ItemSelectedHasChanged
4730         QCOMPARE(tester.changes.size(), changeCount);
4731         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedChange);
4732         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSelectedHasChanged);
4733         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(true));
4734         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true));
4735         QCOMPARE(tester.oldValues.last(), QVariant(false));
4736         QCOMPARE(tester.isSelected(), true);
4737
4738         tester.itemChangeReturnValue = false;
4739         tester.setSelected(true);
4740
4741         // the value hasn't changed to the itemChange return value
4742         // bacause itemChange is never called (true -> true is a noop).
4743         QCOMPARE(tester.isSelected(), true);
4744     }
4745     {
4746         // ItemVisibleChange
4747         tester.itemChangeReturnValue = false;
4748         QVERIFY(tester.isVisible());
4749         tester.setVisible(false);
4750         ++changeCount; // ItemVisibleChange
4751         ++changeCount; // ItemSelectedChange
4752         ++changeCount; // ItemSelectedHasChanged
4753         ++changeCount; // ItemVisibleHasChanged
4754         QCOMPARE(tester.changes.size(), changeCount);
4755         QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemVisibleChange);
4756         QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSelectedChange);
4757         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedHasChanged);
4758         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemVisibleHasChanged);
4759         QCOMPARE(tester.values.at(tester.values.size() - 4), QVariant(false));
4760         QCOMPARE(tester.values.at(tester.values.size() - 3), QVariant(false));
4761         QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false));
4762         QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(false));
4763         QCOMPARE(tester.isVisible(), false);
4764     }
4765     {
4766         // ItemParentChange
4767         tester.itemChangeReturnValue.setValue<QGraphicsItem *>(0);
4768         tester.setParentItem(&testerHelper);
4769         QCOMPARE(tester.changes.size(), ++changeCount);
4770         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemParentChange);
4771         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4772         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.oldValues.last()), (QGraphicsItem *)0);
4773         QCOMPARE(tester.parentItem(), (QGraphicsItem *)0);
4774     }
4775     {
4776         // ItemOpacityChange
4777         tester.itemChangeReturnValue = 1.0;
4778         tester.setOpacity(0.7);
4779         QCOMPARE(tester.changes.size(), ++changeCount);
4780         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemOpacityChange);
4781         QVERIFY(qFuzzyCompare(qreal(tester.values.last().toDouble()), qreal(0.7)));
4782         QCOMPARE(tester.oldValues.last().toDouble(), double(1.0));
4783         QCOMPARE(tester.opacity(), qreal(1.0));
4784         tester.itemChangeReturnValue = 0.7;
4785         tester.setOpacity(0.7);
4786         ++changeCount; // ItemOpacityChange
4787         ++changeCount; // ItemOpacityHasChanged
4788         QCOMPARE(tester.changes.size(), changeCount);
4789         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemOpacityChange);
4790         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemOpacityHasChanged);
4791         QCOMPARE(tester.opacity(), qreal(0.7));
4792     }
4793     {
4794         // ItemChildAddedChange
4795         tester.itemChangeReturnValue.clear();
4796         testerHelper.setParentItem(&tester);
4797         QCOMPARE(tester.changes.size(), ++changeCount);
4798         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildAddedChange);
4799         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4800     }
4801     {
4802         // ItemChildRemovedChange 1
4803         testerHelper.setParentItem(0);
4804         QCOMPARE(tester.changes.size(), ++changeCount);
4805         QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildRemovedChange);
4806         QCOMPARE(qvariant_cast<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper);
4807
4808         // ItemChildRemovedChange 1
4809         ItemChangeTester *test = new ItemChangeTester;
4810         test->itemSceneChangeTargetScene = 0;
4811         int count = 0;
4812         QGraphicsScene *scene = new QGraphicsScene;
4813         scene->addItem(test);
4814         count = test->changes.size();
4815         //We test here the fact that when a child is deleted the parent receive only one ItemChildRemovedChange
4816         QGraphicsRectItem *child = new QGraphicsRectItem(test);
4817         //We received ItemChildAddedChange
4818         QCOMPARE(test->changes.size(), ++count);
4819         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildAddedChange);
4820         delete child;
4821         child = 0;
4822         QCOMPARE(test->changes.size(), ++count);
4823         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
4824
4825         ItemChangeTester *childTester = new ItemChangeTester(test);
4826         //Changes contains all sceneHasChanged and so on, we don't want to test that
4827         int childCount = childTester->changes.size();
4828         //We received ItemChildAddedChange
4829         QCOMPARE(test->changes.size(), ++count);
4830         child = new QGraphicsRectItem(childTester);
4831         //We received ItemChildAddedChange
4832         QCOMPARE(childTester->changes.size(), ++childCount);
4833         QCOMPARE(childTester->changes.last(), QGraphicsItem::ItemChildAddedChange);
4834         //Delete the child of the top level with all its children
4835         delete childTester;
4836         //Only one removal
4837         QCOMPARE(test->changes.size(), ++count);
4838         QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange);
4839         delete scene;
4840     }
4841     {
4842         // ItemChildRemovedChange 2
4843         ItemChangeTester parent;
4844         ItemChangeTester *child = new ItemChangeTester;
4845         child->setParentItem(&parent);
4846         QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildAddedChange);
4847         QCOMPARE(qvariant_cast<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
4848         delete child;
4849         QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildRemovedChange);
4850         QCOMPARE(qvariant_cast<QGraphicsItem *>(parent.values.last()), (QGraphicsItem *)child);
4851     }
4852     {
4853         // !!! Note: If this test crashes because of double-deletion, there's
4854         // a bug somewhere in QGraphicsScene or QGraphicsItem.
4855
4856         // ItemSceneChange
4857         QGraphicsScene scene;
4858         QGraphicsScene scene2;
4859         scene.addItem(&tester);
4860         ++changeCount; // ItemSceneChange (scene)
4861         ++changeCount; // ItemSceneHasChanged (scene)
4862         QCOMPARE(tester.changes.size(), changeCount);
4863
4864         QCOMPARE(tester.scene(), &scene);
4865         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4866         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4867         // Item's old value was 0
4868         // Item's current value is scene
4869         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
4870         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene);
4871         scene2.addItem(&tester);
4872         ++changeCount; // ItemSceneChange (0) was: (scene)
4873         ++changeCount; // ItemSceneHasChanged (0)
4874         ++changeCount; // ItemSceneChange (scene2) was: (0)
4875         ++changeCount; // ItemSceneHasChanged (scene2)
4876         QCOMPARE(tester.changes.size(), changeCount);
4877
4878         QCOMPARE(tester.scene(), &scene2);
4879         QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemSceneChange);
4880         QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSceneHasChanged);
4881         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4882         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4883         // Item's last old value was scene
4884         // Item's last current value is 0
4885
4886         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 2)), (QGraphicsScene *)&scene);
4887         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.at(tester.oldValues.size() - 1)), (QGraphicsScene *)0);
4888         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 4)), (QGraphicsScene *)0);
4889         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)0);
4890         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene2);
4891         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene2);
4892         // Item's last old value was 0
4893         // Item's last current value is scene2
4894         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)0);
4895         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.last()), (QGraphicsScene *)&scene2);
4896
4897         scene2.removeItem(&tester);
4898         ++changeCount; // ItemSceneChange (0) was: (scene2)
4899         ++changeCount; // ItemSceneHasChanged (0)
4900         QCOMPARE(tester.changes.size(), changeCount);
4901
4902         QCOMPARE(tester.scene(), (QGraphicsScene *)0);
4903         QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange);
4904         QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged);
4905         // Item's last old value was scene2
4906         // Item's last current value is 0
4907         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.oldValues.last()), (QGraphicsScene *)&scene2);
4908         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)0);
4909         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)0);
4910
4911         tester.itemSceneChangeTargetScene = &scene;
4912         scene2.addItem(&tester);
4913         ++changeCount; // ItemSceneChange (scene2) was: (0)
4914         ++changeCount; // ItemSceneChange (scene) was: (0)
4915         ++changeCount; // ItemSceneHasChanged (scene)
4916         QCOMPARE(tester.values.size(), changeCount);
4917
4918         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)&scene2);
4919         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene);
4920         QCOMPARE(qvariant_cast<QGraphicsScene *>(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene);
4921
4922         QCOMPARE(tester.scene(), &scene);
4923         tester.itemSceneChangeTargetScene = 0;
4924         tester.itemChangeReturnValue = QVariant();
4925         scene.removeItem(&tester);
4926         ++changeCount; // ItemSceneChange
4927         ++changeCount; // ItemSceneHasChanged
4928         QCOMPARE(tester.scene(), (QGraphicsScene *)0);
4929     }
4930     {
4931         // ItemToolTipChange/ItemToolTipHasChanged
4932         const QString toolTip(QLatin1String("I'm soo cool"));
4933         const QString overridenToolTip(QLatin1String("No, you are not soo cool"));
4934         tester.itemChangeReturnValue = overridenToolTip;
4935         tester.setToolTip(toolTip);
4936         ++changeCount; // ItemToolTipChange
4937         ++changeCount; // ItemToolTipHasChanged
4938         QCOMPARE(tester.changes.size(), changeCount);
4939         QCOMPARE(tester.changes.at(changeCount - 2), QGraphicsItem::ItemToolTipChange);
4940         QCOMPARE(tester.values.at(changeCount - 2).toString(), toolTip);
4941         QCOMPARE(tester.changes.at(changeCount - 1), QGraphicsItem::ItemToolTipHasChanged);
4942         QCOMPARE(tester.values.at(changeCount - 1).toString(), overridenToolTip);
4943         QCOMPARE(tester.toolTip(), overridenToolTip);
4944         tester.itemChangeReturnValue = QVariant();
4945     }
4946 }
4947
4948 class EventFilterTesterItem : public QGraphicsLineItem
4949 {
4950 public:
4951     QList<QEvent::Type> filteredEvents;
4952     QList<QGraphicsItem *> filteredEventReceivers;
4953     bool handlesSceneEvents;
4954
4955     QList<QEvent::Type> receivedEvents;
4956
4957     EventFilterTesterItem() : handlesSceneEvents(false) {}
4958
4959 protected:
4960     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
4961     {
4962         filteredEvents << event->type();
4963         filteredEventReceivers << watched;
4964         return handlesSceneEvents;
4965     }
4966
4967     bool sceneEvent(QEvent *event)
4968     {
4969         return QGraphicsLineItem::sceneEvent(event);
4970     }
4971 };
4972
4973 void tst_QGraphicsItem::sceneEventFilter()
4974 {
4975     QGraphicsScene scene;
4976
4977     QGraphicsView view(&scene);
4978     view.show();
4979     QApplication::setActiveWindow(&view);
4980     QVERIFY(QTest::qWaitForWindowActive(&view));
4981
4982     QGraphicsTextItem *text1 = scene.addText(QLatin1String("Text1"));
4983     QGraphicsTextItem *text2 = scene.addText(QLatin1String("Text2"));
4984     QGraphicsTextItem *text3 = scene.addText(QLatin1String("Text3"));
4985     text1->setFlag(QGraphicsItem::ItemIsFocusable);
4986     text2->setFlag(QGraphicsItem::ItemIsFocusable);
4987     text3->setFlag(QGraphicsItem::ItemIsFocusable);
4988
4989     EventFilterTesterItem *tester = new EventFilterTesterItem;
4990     scene.addItem(tester);
4991
4992     QTRY_VERIFY(!text1->hasFocus());
4993     text1->installSceneEventFilter(tester);
4994     text1->setFocus();
4995     QTRY_VERIFY(text1->hasFocus());
4996
4997     QCOMPARE(tester->filteredEvents.size(), 1);
4998     QCOMPARE(tester->filteredEvents.at(0), QEvent::FocusIn);
4999     QCOMPARE(tester->filteredEventReceivers.at(0), static_cast<QGraphicsItem *>(text1));
5000
5001     text2->installSceneEventFilter(tester);
5002     text3->installSceneEventFilter(tester);
5003
5004     text2->setFocus();
5005     text3->setFocus();
5006
5007     QCOMPARE(tester->filteredEvents.size(), 5);
5008     QCOMPARE(tester->filteredEvents.at(1), QEvent::FocusOut);
5009     QCOMPARE(tester->filteredEventReceivers.at(1), static_cast<QGraphicsItem *>(text1));
5010     QCOMPARE(tester->filteredEvents.at(2), QEvent::FocusIn);
5011     QCOMPARE(tester->filteredEventReceivers.at(2), static_cast<QGraphicsItem *>(text2));
5012     QCOMPARE(tester->filteredEvents.at(3), QEvent::FocusOut);
5013     QCOMPARE(tester->filteredEventReceivers.at(3), static_cast<QGraphicsItem *>(text2));
5014     QCOMPARE(tester->filteredEvents.at(4), QEvent::FocusIn);
5015     QCOMPARE(tester->filteredEventReceivers.at(4), static_cast<QGraphicsItem *>(text3));
5016
5017     text1->removeSceneEventFilter(tester);
5018     text1->setFocus();
5019
5020     QCOMPARE(tester->filteredEvents.size(), 6);
5021     QCOMPARE(tester->filteredEvents.at(5), QEvent::FocusOut);
5022     QCOMPARE(tester->filteredEventReceivers.at(5), static_cast<QGraphicsItem *>(text3));
5023
5024     tester->handlesSceneEvents = true;
5025     text2->setFocus();
5026
5027     QCOMPARE(tester->filteredEvents.size(), 7);
5028     QCOMPARE(tester->filteredEvents.at(6), QEvent::FocusIn);
5029     QCOMPARE(tester->filteredEventReceivers.at(6), static_cast<QGraphicsItem *>(text2));
5030
5031     QVERIFY(text2->hasFocus());
5032
5033     //Let check if the items are correctly removed from the sceneEventFilters array
5034     //to avoid stale pointers.
5035     QGraphicsView gv;
5036     QGraphicsScene *anotherScene = new QGraphicsScene;
5037     QGraphicsTextItem *ti = anotherScene->addText("This is a test #1");
5038     ti->moveBy(50, 50);
5039     QGraphicsTextItem *ti2 = anotherScene->addText("This is a test #2");
5040     QGraphicsTextItem *ti3 = anotherScene->addText("This is a test #3");
5041     gv.setScene(anotherScene);
5042     gv.show();
5043     QVERIFY(QTest::qWaitForWindowExposed(&gv));
5044     QTest::qWait(25);
5045     ti->installSceneEventFilter(ti2);
5046     ti3->installSceneEventFilter(ti);
5047     delete ti2;
5048     //we souldn't crash
5049     QTest::mouseMove(gv.viewport(), gv.mapFromScene(ti->scenePos()));
5050     QTest::qWait(30);
5051     delete ti;
5052 }
5053
5054 class GeometryChanger : public QGraphicsItem
5055 {
5056 public:
5057     void changeGeometry()
5058     { prepareGeometryChange(); }
5059 };
5060
5061 void tst_QGraphicsItem::prepareGeometryChange()
5062 {
5063     {
5064         QGraphicsScene scene;
5065         QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
5066         QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
5067         ((GeometryChanger *)item)->changeGeometry();
5068         QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item));
5069     }
5070 }
5071
5072
5073 class PaintTester : public QGraphicsRectItem
5074 {
5075 public:
5076     PaintTester() : widget(NULL), painted(0) { setRect(QRectF(10, 10, 20, 20));}
5077
5078     void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *w)
5079     {
5080         widget = w;
5081         painted++;
5082     }
5083
5084     QWidget*  widget;
5085     int painted;
5086 };
5087
5088 void tst_QGraphicsItem::paint()
5089 {
5090     QGraphicsScene scene;
5091
5092     PaintTester paintTester;
5093     scene.addItem(&paintTester);
5094
5095     QGraphicsView view(&scene);
5096     view.show();
5097     QVERIFY(QTest::qWaitForWindowExposed(&view));
5098     QApplication::processEvents();
5099 #ifdef Q_OS_WIN32
5100     //we try to switch the desktop: if it fails, we skip the test
5101     if (::SwitchDesktop( ::GetThreadDesktop( ::GetCurrentThreadId() ) ) == 0) {
5102         QSKIP("The Graphics View doesn't get the paint events");
5103     }
5104 #endif
5105
5106     QTRY_COMPARE(paintTester.widget, view.viewport());
5107
5108     view.hide();
5109
5110     QGraphicsScene scene2;
5111     QGraphicsView view2(&scene2);
5112     view2.show();
5113     QVERIFY(QTest::qWaitForWindowExposed(&view2));
5114     QTest::qWait(25);
5115
5116     PaintTester tester2;
5117     scene2.addItem(&tester2);
5118     qApp->processEvents();
5119
5120     //First show one paint
5121     QTRY_COMPARE(tester2.painted, 1);
5122
5123     //nominal case, update call paint
5124     tester2.update();
5125     qApp->processEvents();
5126     QTRY_VERIFY(tester2.painted == 2);
5127
5128     //we remove the item from the scene, number of updates is still the same
5129     tester2.update();
5130     scene2.removeItem(&tester2);
5131     qApp->processEvents();
5132     QTRY_VERIFY(tester2.painted == 2);
5133
5134     //We re-add the item, the number of paint should increase
5135     scene2.addItem(&tester2);
5136     tester2.update();
5137     qApp->processEvents();
5138     QTRY_VERIFY(tester2.painted == 3);
5139 }
5140
5141 class HarakiriItem : public QGraphicsRectItem
5142 {
5143 public:
5144     HarakiriItem(int harakiriPoint)
5145         : QGraphicsRectItem(QRectF(0, 0, 100, 100)), harakiri(harakiriPoint)
5146     { dead = 0; }
5147
5148     static int dead;
5149
5150     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
5151     {
5152         QGraphicsRectItem::paint(painter, option, widget);
5153         if (harakiri == 0) {
5154             // delete unsupported since 4.5
5155             /*
5156             dead = 1;
5157             delete this;
5158             */
5159         }
5160     }
5161
5162     void advance(int n)
5163     {
5164         if (harakiri == 1 && n == 0) {
5165             // delete unsupported
5166             /*
5167             dead = 1;
5168             delete this;
5169             */
5170         }
5171         if (harakiri == 2 && n == 1) {
5172             dead = 1;
5173             delete this;
5174         }
5175     }
5176
5177 protected:
5178     void contextMenuEvent(QGraphicsSceneContextMenuEvent *)
5179     {
5180         if (harakiri == 3) {
5181             dead = 1;
5182             delete this;
5183         }
5184     }
5185
5186     void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
5187     {
5188         // ??
5189         QGraphicsRectItem::dragEnterEvent(event);
5190     }
5191
5192     void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
5193     {
5194         // ??
5195         QGraphicsRectItem::dragLeaveEvent(event);
5196     }
5197
5198     void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
5199     {
5200         // ??
5201         QGraphicsRectItem::dragMoveEvent(event);
5202     }
5203
5204     void dropEvent(QGraphicsSceneDragDropEvent *event)
5205     {
5206         // ??
5207         QGraphicsRectItem::dropEvent(event);
5208     }
5209
5210     void focusInEvent(QFocusEvent *)
5211     {
5212         if (harakiri == 4) {
5213             dead = 1;
5214             delete this;
5215         }
5216     }
5217
5218     void focusOutEvent(QFocusEvent *)
5219     {
5220         if (harakiri == 5) {
5221             dead = 1;
5222             delete this;
5223         }
5224     }
5225
5226     void hoverEnterEvent(QGraphicsSceneHoverEvent *)
5227     {
5228         if (harakiri == 6) {
5229             dead = 1;
5230             delete this;
5231         }
5232     }
5233
5234     void hoverLeaveEvent(QGraphicsSceneHoverEvent *)
5235     {
5236         if (harakiri == 7) {
5237             dead = 1;
5238             delete this;
5239         }
5240     }
5241
5242     void hoverMoveEvent(QGraphicsSceneHoverEvent *)
5243     {
5244         if (harakiri == 8) {
5245             dead = 1;
5246             delete this;
5247         }
5248     }
5249
5250     void inputMethodEvent(QInputMethodEvent *event)
5251     {
5252         // ??
5253         QGraphicsRectItem::inputMethodEvent(event);
5254     }
5255
5256     QVariant inputMethodQuery(Qt::InputMethodQuery query) const
5257     {
5258         // ??
5259         return QGraphicsRectItem::inputMethodQuery(query);
5260     }
5261
5262     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
5263     {
5264         // deletion not supported
5265         return QGraphicsRectItem::itemChange(change, value);
5266     }
5267
5268     void keyPressEvent(QKeyEvent *)
5269     {
5270         if (harakiri == 9) {
5271             dead = 1;
5272             delete this;
5273         }
5274     }
5275
5276     void keyReleaseEvent(QKeyEvent *)
5277     {
5278         if (harakiri == 10) {
5279             dead = 1;
5280             delete this;
5281         }
5282     }
5283
5284     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *)
5285     {
5286         if (harakiri == 11) {
5287             dead = 1;
5288             delete this;
5289         }
5290     }
5291
5292     void mouseMoveEvent(QGraphicsSceneMouseEvent *)
5293     {
5294         if (harakiri == 12) {
5295             dead = 1;
5296             delete this;
5297         }
5298     }
5299
5300     void mousePressEvent(QGraphicsSceneMouseEvent *)
5301     {
5302         if (harakiri == 13) {
5303             dead = 1;
5304             delete this;
5305         }
5306     }
5307
5308     void mouseReleaseEvent(QGraphicsSceneMouseEvent *)
5309     {
5310         if (harakiri == 14) {
5311             dead = 1;
5312             delete this;
5313         }
5314     }
5315
5316     bool sceneEvent(QEvent *event)
5317     {
5318         // deletion not supported
5319         return QGraphicsRectItem::sceneEvent(event);
5320     }
5321
5322     bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
5323     {
5324         // deletion not supported
5325         return QGraphicsRectItem::sceneEventFilter(watched, event);
5326     }
5327
5328     void wheelEvent(QGraphicsSceneWheelEvent *)
5329     {
5330         if (harakiri == 16) {
5331             dead = 1;
5332             delete this;
5333         }
5334     }
5335
5336 private:
5337     int harakiri;
5338 };
5339
5340 int HarakiriItem::dead;
5341
5342 void tst_QGraphicsItem::deleteItemInEventHandlers()
5343 {
5344     for (int i = 0; i < 17; ++i) {
5345         QGraphicsScene scene;
5346         HarakiriItem *item = new HarakiriItem(i);
5347         item->setAcceptsHoverEvents(true);
5348         item->setFlag(QGraphicsItem::ItemIsFocusable);
5349
5350         scene.addItem(item);
5351
5352         item->installSceneEventFilter(item); // <- ehey!
5353
5354         QGraphicsView view(&scene);
5355         view.show();
5356
5357         qApp->processEvents();
5358         qApp->processEvents();
5359
5360         if (!item->dead)
5361             scene.advance();
5362
5363         if (!item->dead) {
5364             QContextMenuEvent event(QContextMenuEvent::Other,
5365                                     view.mapFromScene(item->scenePos()));
5366             QCoreApplication::sendEvent(view.viewport(), &event);
5367         }
5368         if (!item->dead)
5369             QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos()));
5370         if (!item->dead)
5371             QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
5372         if (!item->dead)
5373             QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos()));
5374         if (!item->dead)
5375             QTest::mouseClick(view.viewport(), Qt::RightButton, 0, view.mapFromScene(item->scenePos()));
5376         if (!item->dead)
5377             QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos() + QPointF(20, -20)));
5378         if (!item->dead)
5379             item->setFocus();
5380         if (!item->dead)
5381             item->clearFocus();
5382         if (!item->dead)
5383             item->setFocus();
5384         if (!item->dead)
5385             QTest::keyPress(view.viewport(), Qt::Key_A);
5386         if (!item->dead)
5387             QTest::keyRelease(view.viewport(), Qt::Key_A);
5388         if (!item->dead)
5389             QTest::keyPress(view.viewport(), Qt::Key_A);
5390         if (!item->dead)
5391             QTest::keyRelease(view.viewport(), Qt::Key_A);
5392     }
5393 }
5394
5395 class ItemPaintsOutsideShape : public QGraphicsItem
5396 {
5397 public:
5398     QRectF boundingRect() const
5399     {
5400         return QRectF(0, 0, 100, 100);
5401     }
5402
5403     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
5404     {
5405         painter->fillRect(-50, -50, 200, 200, Qt::red);
5406         painter->fillRect(0, 0, 100, 100, Qt::blue);
5407     }
5408 };
5409
5410 void tst_QGraphicsItem::itemClipsToShape()
5411 {
5412     QGraphicsItem *clippedItem = new ItemPaintsOutsideShape;
5413     clippedItem->setFlag(QGraphicsItem::ItemClipsToShape);
5414
5415     QGraphicsItem *unclippedItem = new ItemPaintsOutsideShape;
5416     unclippedItem->setPos(200, 0);
5417
5418     QGraphicsScene scene(-50, -50, 400, 200);
5419     scene.addItem(clippedItem);
5420     scene.addItem(unclippedItem);
5421
5422     QImage image(400, 200, QImage::Format_ARGB32_Premultiplied);
5423     image.fill(0);
5424     QPainter painter(&image);
5425     painter.setRenderHint(QPainter::Antialiasing);
5426     scene.render(&painter);
5427     painter.end();
5428
5429     QCOMPARE(image.pixel(45, 100), QRgb(0));
5430     QCOMPARE(image.pixel(100, 45), QRgb(0));
5431     QCOMPARE(image.pixel(155, 100), QRgb(0));
5432     QCOMPARE(image.pixel(45, 155), QRgb(0));
5433     QCOMPARE(image.pixel(55, 100), QColor(Qt::blue).rgba());
5434     QCOMPARE(image.pixel(100, 55), QColor(Qt::blue).rgba());
5435     QCOMPARE(image.pixel(145, 100), QColor(Qt::blue).rgba());
5436     QCOMPARE(image.pixel(55, 145), QColor(Qt::blue).rgba());
5437     QCOMPARE(image.pixel(245, 100), QColor(Qt::red).rgba());
5438     QCOMPARE(image.pixel(300, 45), QColor(Qt::red).rgba());
5439     QCOMPARE(image.pixel(355, 100), QColor(Qt::red).rgba());
5440     QCOMPARE(image.pixel(245, 155), QColor(Qt::red).rgba());
5441     QCOMPARE(image.pixel(255, 100), QColor(Qt::blue).rgba());
5442     QCOMPARE(image.pixel(300, 55), QColor(Qt::blue).rgba());
5443     QCOMPARE(image.pixel(345, 100), QColor(Qt::blue).rgba());
5444     QCOMPARE(image.pixel(255, 145), QColor(Qt::blue).rgba());
5445 }
5446
5447 void tst_QGraphicsItem::itemClipsChildrenToShape()
5448 {
5449     QGraphicsScene scene;
5450     QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::yellow));
5451
5452     QGraphicsItem *ellipse = scene.addEllipse(0, 0, 100, 100, QPen(Qt::NoPen), QBrush(Qt::green));
5453     ellipse->setParentItem(rect);
5454
5455     QGraphicsItem *clippedEllipse = scene.addEllipse(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::blue));
5456     clippedEllipse->setParentItem(ellipse);
5457
5458     QGraphicsItem *clippedEllipse2 = scene.addEllipse(0, 0, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
5459     clippedEllipse2->setParentItem(clippedEllipse);
5460
5461     QGraphicsItem *clippedEllipse3 = scene.addEllipse(50, 50, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
5462     clippedEllipse3->setParentItem(clippedEllipse);
5463
5464     QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
5465     ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5466     QVERIFY((ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
5467
5468     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
5469     image.fill(0);
5470     QPainter painter(&image);
5471     painter.setRenderHint(QPainter::Antialiasing);
5472     scene.render(&painter);
5473     painter.end();
5474
5475     QCOMPARE(image.pixel(16, 16), QColor(255, 0, 0).rgba());
5476     QCOMPARE(image.pixel(32, 32), QColor(0, 0, 255).rgba());
5477     QCOMPARE(image.pixel(50, 50), QColor(0, 255, 0).rgba());
5478     QCOMPARE(image.pixel(12, 12), QColor(255, 255, 0).rgba());
5479     QCOMPARE(image.pixel(60, 60), QColor(255, 0, 0).rgba());
5480 }
5481
5482 void tst_QGraphicsItem::itemClipsChildrenToShape2()
5483 {
5484     QGraphicsRectItem *parent = new QGraphicsRectItem(QRectF(0, 0, 10, 10));
5485     QGraphicsEllipseItem *child1 = new QGraphicsEllipseItem(QRectF(50, 50, 100, 100));
5486     QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(15, 15, 80, 80));
5487
5488     child1->setParentItem(parent);
5489     child1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5490     child2->setParentItem(child1);
5491
5492     parent->setBrush(Qt::blue);
5493     child1->setBrush(Qt::green);
5494     child2->setBrush(Qt::red);
5495
5496     QGraphicsScene scene;
5497     scene.addItem(parent);
5498
5499     QCOMPARE(scene.itemAt(5, 5), (QGraphicsItem *)parent);
5500     QCOMPARE(scene.itemAt(15, 5), (QGraphicsItem *)0);
5501     QCOMPARE(scene.itemAt(5, 15), (QGraphicsItem *)0);
5502     QCOMPARE(scene.itemAt(60, 60), (QGraphicsItem *)0);
5503     QCOMPARE(scene.itemAt(140, 60), (QGraphicsItem *)0);
5504     QCOMPARE(scene.itemAt(60, 140), (QGraphicsItem *)0);
5505     QCOMPARE(scene.itemAt(140, 140), (QGraphicsItem *)0);
5506     QCOMPARE(scene.itemAt(75, 75), (QGraphicsItem *)child2);
5507     QCOMPARE(scene.itemAt(75, 100), (QGraphicsItem *)child1);
5508     QCOMPARE(scene.itemAt(100, 75), (QGraphicsItem *)child1);
5509
5510     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
5511     image.fill(0);
5512     QPainter painter(&image);
5513     scene.render(&painter);
5514     painter.end();
5515
5516     QCOMPARE(image.pixel(5, 5), QColor(0, 0, 255).rgba());
5517     QCOMPARE(image.pixel(5, 10), QRgb(0));
5518     QCOMPARE(image.pixel(10, 5), QRgb(0));
5519     QCOMPARE(image.pixel(40, 40), QRgb(0));
5520     QCOMPARE(image.pixel(90, 40), QRgb(0));
5521     QCOMPARE(image.pixel(40, 90), QRgb(0));
5522     QCOMPARE(image.pixel(95, 95), QRgb(0));
5523     QCOMPARE(image.pixel(50, 70), QColor(0, 255, 0).rgba());
5524     QCOMPARE(image.pixel(70, 50), QColor(0, 255, 0).rgba());
5525     QCOMPARE(image.pixel(50, 60), QColor(255, 0, 0).rgba());
5526     QCOMPARE(image.pixel(60, 50), QColor(255, 0, 0).rgba());
5527 }
5528
5529 void tst_QGraphicsItem::itemClipsChildrenToShape3()
5530 {
5531     // Construct a scene with nested children, each 50 pixels offset from the elder.
5532     // Set a top-level clipping flag
5533     QGraphicsScene scene;
5534     QGraphicsRectItem *parent = scene.addRect( 0, 0, 150, 150 );
5535     QGraphicsRectItem *child = scene.addRect( 0, 0, 150, 150 );
5536     QGraphicsRectItem *grandchild = scene.addRect( 0, 0, 150, 150 );
5537     child->setParentItem(parent);
5538     grandchild->setParentItem(child);
5539     child->setPos( 50, 50 );
5540     grandchild->setPos( 50, 50 );
5541     parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5542
5543     QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)parent);
5544     QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)child);
5545     QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
5546     QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
5547
5548     // Move child to fully overlap the parent.  The grandchild should
5549     // now occupy two-thirds of the scene
5550     child->prepareGeometryChange();
5551     child->setPos( 0, 0 );
5552
5553     QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)child);
5554     QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)grandchild);
5555     QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild);
5556     QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0);
5557 }
5558
5559 class MyProxyWidget : public QGraphicsProxyWidget
5560 {
5561 public:
5562     MyProxyWidget(QGraphicsItem *parent) : QGraphicsProxyWidget(parent)
5563     {
5564         painted = false;
5565     }
5566
5567     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
5568     {
5569         QGraphicsProxyWidget::paint(painter, option, widget);
5570         painted = true;
5571     }
5572     bool painted;
5573 };
5574
5575 void tst_QGraphicsItem::itemClipsChildrenToShape4()
5576 {
5577     QGraphicsScene scene;
5578     QGraphicsView view(&scene);
5579
5580     QGraphicsWidget * outerWidget = new QGraphicsWidget();
5581     outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
5582     MyProxyWidget * innerWidget = new MyProxyWidget(outerWidget);
5583     QLabel * label = new QLabel();
5584     label->setText("Welcome back my friends to the show that never ends...");
5585     innerWidget->setWidget(label);
5586     view.resize(300, 300);
5587     scene.addItem(outerWidget);
5588     outerWidget->resize( 200, 100 );
5589     scene.addEllipse( 100, 100, 100, 50 );   // <-- this is important to trigger the right codepath*
5590     //now the label is shown
5591     outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false );
5592     QApplication::setActiveWindow(&view);
5593     view.show();
5594     QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view);
5595     QTRY_COMPARE(innerWidget->painted, true);
5596 }
5597
5598 //#define DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
5599 static inline void renderSceneToImage(QGraphicsScene *scene, QImage *image, const QString &filename)
5600 {
5601     image->fill(0);
5602     QPainter painter(image);
5603     scene->render(&painter);
5604     painter.end();
5605 #ifdef DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
5606     image->save(filename);
5607 #else
5608     Q_UNUSED(filename);
5609 #endif
5610 }
5611
5612 void tst_QGraphicsItem::itemClipsChildrenToShape5()
5613 {
5614     class ParentItem : public QGraphicsRectItem
5615     {
5616     public:
5617         ParentItem(qreal x, qreal y, qreal width, qreal height)
5618             : QGraphicsRectItem(x, y, width, height) {}
5619
5620         QPainterPath shape() const
5621         {
5622             QPainterPath path;
5623             path.addRect(50, 50, 200, 200);
5624             return path;
5625         }
5626     };
5627
5628     ParentItem *parent = new ParentItem(0, 0, 300, 300);
5629     parent->setBrush(Qt::blue);
5630     parent->setOpacity(0.5);
5631
5632     const QRegion parentRegion(0, 0, 300, 300);
5633     const QRegion clippedParentRegion = parentRegion & QRect(50, 50, 200, 200);
5634     QRegion childRegion;
5635     QRegion grandChildRegion;
5636
5637     QGraphicsRectItem *topLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
5638     topLeftChild->setBrush(Qt::red);
5639     topLeftChild->setParentItem(parent);
5640     childRegion += QRect(0, 0, 100, 100);
5641
5642     QGraphicsRectItem *topRightChild = new QGraphicsRectItem(0, 0, 100, 100);
5643     topRightChild->setBrush(Qt::red);
5644     topRightChild->setParentItem(parent);
5645     topRightChild->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5646     topRightChild->setPos(200, 0);
5647     childRegion += QRect(200, 0, 100, 100);
5648
5649     QGraphicsRectItem *topRightGrandChild = new QGraphicsRectItem(0, 0, 100, 100);
5650     topRightGrandChild->setBrush(Qt::green);
5651     topRightGrandChild->setParentItem(topRightChild);
5652     topRightGrandChild->setPos(-40, 40);
5653     grandChildRegion += QRect(200 - 40, 0 + 40, 100, 100) & QRect(200, 0, 100, 100);
5654
5655     QGraphicsRectItem *bottomLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
5656     bottomLeftChild->setBrush(Qt::red);
5657     bottomLeftChild->setParentItem(parent);
5658     bottomLeftChild->setFlag(QGraphicsItem::ItemClipsToShape);
5659     bottomLeftChild->setPos(0, 200);
5660     childRegion += QRect(0, 200, 100, 100);
5661
5662     QGraphicsRectItem *bottomLeftGrandChild = new QGraphicsRectItem(0, 0, 160, 160);
5663     bottomLeftGrandChild->setBrush(Qt::green);
5664     bottomLeftGrandChild->setParentItem(bottomLeftChild);
5665     bottomLeftGrandChild->setFlag(QGraphicsItem::ItemClipsToShape);
5666     bottomLeftGrandChild->setPos(0, -60);
5667     grandChildRegion += QRect(0, 200 - 60, 160, 160);
5668
5669     QGraphicsRectItem *bottomRightChild = new QGraphicsRectItem(0, 0, 100, 100);
5670     bottomRightChild->setBrush(Qt::red);
5671     bottomRightChild->setParentItem(parent);
5672     bottomRightChild->setPos(200, 200);
5673     childRegion += QRect(200, 200, 100, 100);
5674
5675     QPoint controlPoints[17] = {
5676         QPoint(5, 5)  , QPoint(95, 5)  , QPoint(205, 5)  , QPoint(295, 5)  ,
5677         QPoint(5, 95) , QPoint(95, 95) , QPoint(205, 95) , QPoint(295, 95) ,
5678                              QPoint(150, 150),
5679         QPoint(5, 205), QPoint(95, 205), QPoint(205, 205), QPoint(295, 205),
5680         QPoint(5, 295), QPoint(95, 295), QPoint(205, 295), QPoint(295, 295),
5681     };
5682
5683     const QRegion clippedChildRegion = childRegion & QRect(50, 50, 200, 200);
5684     const QRegion clippedGrandChildRegion = grandChildRegion & QRect(50, 50, 200, 200);
5685
5686     QGraphicsScene scene;
5687     scene.addItem(parent);
5688     QImage sceneImage(300, 300, QImage::Format_ARGB32);
5689
5690 #define VERIFY_CONTROL_POINTS(pRegion, cRegion, gRegion) \
5691     for (int i = 0; i < 17; ++i) { \
5692         QPoint controlPoint = controlPoints[i]; \
5693         QRgb pixel = sceneImage.pixel(controlPoint.x(), controlPoint.y()); \
5694         if (pRegion.contains(controlPoint)) \
5695             QVERIFY(qBlue(pixel) != 0); \
5696         else \
5697             QVERIFY(qBlue(pixel) == 0); \
5698         if (cRegion.contains(controlPoint)) \
5699             QVERIFY(qRed(pixel) != 0); \
5700         else \
5701             QVERIFY(qRed(pixel) == 0); \
5702         if (gRegion.contains(controlPoint)) \
5703             QVERIFY(qGreen(pixel) != 0); \
5704         else \
5705             QVERIFY(qGreen(pixel) == 0); \
5706     }
5707
5708     const QList<QGraphicsItem *> children = parent->childItems();
5709     const int childrenCount = children.count();
5710
5711     for (int i = 0; i < 5; ++i) {
5712         QString clipString;
5713         QString childString;
5714         switch (i) {
5715         case 0:
5716             // All children stacked in front.
5717             childString = QLatin1String("ChildrenInFront.png");
5718             foreach (QGraphicsItem *child, children)
5719                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
5720             break;
5721         case 1:
5722             // All children stacked behind.
5723             childString = QLatin1String("ChildrenBehind.png");
5724             foreach (QGraphicsItem *child, children)
5725                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
5726             break;
5727         case 2:
5728             // First half of the children behind, second half in front.
5729             childString = QLatin1String("FirstHalfBehind_SecondHalfInFront.png");
5730             for (int j = 0; j < childrenCount; ++j) {
5731                 QGraphicsItem *child = children.at(j);
5732                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j < childrenCount / 2));
5733             }
5734             break;
5735         case 3:
5736             // First half of the children in front, second half behind.
5737             childString = QLatin1String("FirstHalfInFront_SecondHalfBehind.png");
5738             for (int j = 0; j < childrenCount; ++j) {
5739                 QGraphicsItem *child = children.at(j);
5740                 child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j >= childrenCount / 2));
5741             }
5742             break;
5743         case 4:
5744             // Child2 and child4 behind, rest in front.
5745             childString = QLatin1String("Child2And4Behind_RestInFront.png");
5746             for (int j = 0; j < childrenCount; ++j) {
5747                 QGraphicsItem *child = children.at(j);
5748                 if (j == 1 || j == 3)
5749                     child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
5750                 else
5751                     child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
5752             }
5753             break;
5754         default:
5755             qFatal("internal error");
5756         }
5757
5758         // Nothing is clipped.
5759         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
5760         parent->setFlag(QGraphicsItem::ItemClipsToShape, false);
5761         clipString = QLatin1String("nothingClipped_");
5762         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5763         VERIFY_CONTROL_POINTS(parentRegion, childRegion, grandChildRegion);
5764
5765         // Parent clips children to shape.
5766         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5767         clipString = QLatin1String("parentClipsChildrenToShape_");
5768         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5769         VERIFY_CONTROL_POINTS(parentRegion, clippedChildRegion, clippedGrandChildRegion);
5770
5771         // Parent clips itself and children to shape.
5772         parent->setFlag(QGraphicsItem::ItemClipsToShape);
5773         clipString = QLatin1String("parentClipsItselfAndChildrenToShape_");
5774         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5775         VERIFY_CONTROL_POINTS(clippedParentRegion, clippedChildRegion, clippedGrandChildRegion);
5776
5777         // Parent clips itself to shape.
5778         parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
5779         clipString = QLatin1String("parentClipsItselfToShape_");
5780         renderSceneToImage(&scene, &sceneImage, clipString + childString);
5781         VERIFY_CONTROL_POINTS(clippedParentRegion, childRegion, grandChildRegion);
5782     }
5783 }
5784
5785 void tst_QGraphicsItem::itemClipsTextChildToShape()
5786 {
5787     // Construct a scene with a rect that clips its children, with one text
5788     // child that has text that exceeds the size of the rect.
5789     QGraphicsScene scene;
5790     QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::black), Qt::black);
5791     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5792     QGraphicsTextItem *text = new QGraphicsTextItem("This is a long sentence that's wider than 50 pixels.");
5793     text->setParentItem(rect);
5794
5795     // Render this scene to a transparent image.
5796     QRectF sr = scene.itemsBoundingRect();
5797     QImage image(sr.size().toSize(), QImage::Format_ARGB32_Premultiplied);
5798     image.fill(0);
5799     QPainter painter(&image);
5800     scene.render(&painter);
5801
5802     // Erase the area immediately underneath the rect.
5803     painter.setCompositionMode(QPainter::CompositionMode_Source);
5804     painter.fillRect(rect->sceneBoundingRect().translated(-sr.topLeft()).adjusted(-0.5, -0.5, 0.5, 0.5),
5805                      Qt::transparent);
5806     painter.end();
5807
5808     // Check that you get a truly transparent image back (i.e., the text was
5809     // clipped away, so there should be no trails left after erasing only the
5810     // rect's area).
5811     QImage emptyImage(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
5812     emptyImage.fill(0);
5813     QCOMPARE(image, emptyImage);
5814 }
5815
5816 void tst_QGraphicsItem::itemClippingDiscovery()
5817 {
5818     // A simple scene with an ellipse parent and two rect children, one a
5819     // child of the other.
5820     QGraphicsScene scene;
5821     QGraphicsEllipseItem *clipItem = scene.addEllipse(0, 0, 100, 100);
5822     QGraphicsRectItem *leftRectItem = scene.addRect(0, 0, 50, 100);
5823     QGraphicsRectItem *rightRectItem = scene.addRect(50, 0, 50, 100);
5824     leftRectItem->setParentItem(clipItem);
5825     rightRectItem->setParentItem(clipItem);
5826
5827     // The rects item are both visible at these points.
5828     QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)leftRectItem);
5829     QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)rightRectItem);
5830
5831     // The ellipse clips the rects now.
5832     clipItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
5833
5834     // The rect items are no longer visible at these points.
5835     QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0);
5836     if (sizeof(qreal) != sizeof(double))
5837         QSKIP("This fails due to internal rounding errors");
5838     QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)0);
5839 }
5840
5841 void tst_QGraphicsItem::ancestorFlags()
5842 {
5843     QGraphicsItem *level1 = new QGraphicsRectItem;
5844     QGraphicsItem *level21 = new QGraphicsRectItem;
5845     level21->setParentItem(level1);
5846     QGraphicsItem *level22 = new QGraphicsRectItem;
5847     level22->setParentItem(level1);
5848     QGraphicsItem *level31 = new QGraphicsRectItem;
5849     level31->setParentItem(level21);
5850     QGraphicsItem *level32 = new QGraphicsRectItem;
5851     level32->setParentItem(level21);
5852
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), 0);
5857     QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5858
5859     // HandlesChildEvents: 1) Root level 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: 2) Root level set it again
5868     level1->setHandlesChildEvents(true);
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: 3) Root level unsets a flag
5876     level1->setHandlesChildEvents(false);
5877     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5878     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5879     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5880     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5881     QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5882
5883     // HandlesChildEvents: 4) Child item sets a flag
5884     level21->setHandlesChildEvents(true);
5885     QCOMPARE(int(level1->d_ptr->ancestorFlags), 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     // HandlesChildEvents: 5) Parent item sets a flag
5892     level1->setHandlesChildEvents(true);
5893     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5894     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5895     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5896     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5897     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5898
5899     // HandlesChildEvents: 6) Child item unsets a flag
5900     level21->setHandlesChildEvents(false);
5901     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5902     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5903     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5904     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5905     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5906
5907     // HandlesChildEvents: 7) Parent item unsets a flag
5908     level21->setHandlesChildEvents(true);
5909     level1->setHandlesChildEvents(false);
5910     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5911     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5912     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5913     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5914     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5915
5916     // Reparent the child to root
5917     level21->setParentItem(0);
5918     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5919     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5920     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5921     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5922
5923     // Reparent the child to level1 again.
5924     level1->setHandlesChildEvents(true);
5925     level21->setParentItem(level1);
5926     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5927     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5928     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5929     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5930     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5931
5932     // Reparenting level31 back to level1.
5933     level31->setParentItem(level1);
5934     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5935     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5936     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5937     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5938     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5939
5940     // Reparenting level31 back to level21.
5941     level31->setParentItem(0);
5942     QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5943     level31->setParentItem(level21);
5944     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5945     QCOMPARE(int(level21->d_ptr->ancestorFlags), 1);
5946     QCOMPARE(int(level22->d_ptr->ancestorFlags), 1);
5947     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5948     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5949
5950     // Level1 doesn't handle child events
5951     level1->setHandlesChildEvents(false);
5952     QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5953     QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5954     QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5955     QCOMPARE(int(level31->d_ptr->ancestorFlags), 1);
5956     QCOMPARE(int(level32->d_ptr->ancestorFlags), 1);
5957
5958     // Nobody handles child events
5959     level21->setHandlesChildEvents(false);
5960
5961     for (int i = 0; i < 2; ++i) {
5962         QGraphicsItem::GraphicsItemFlag flag = !i ? QGraphicsItem::ItemClipsChildrenToShape
5963                                                : QGraphicsItem::ItemIgnoresTransformations;
5964         int ancestorFlag = !i ? QGraphicsItemPrivate::AncestorClipsChildren
5965                            : QGraphicsItemPrivate::AncestorIgnoresTransformations;
5966
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), 0);
5971         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5972
5973         // HandlesChildEvents: 1) Root level 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: 2) Root level set it again
5982         level1->setFlag(flag, true);
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: 3) Root level unsets a flag
5990         level1->setFlag(flag, false);
5991         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
5992         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
5993         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
5994         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
5995         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
5996
5997         // HandlesChildEvents: 4) Child item sets a flag
5998         level21->setFlag(flag, true);
5999         QCOMPARE(int(level1->d_ptr->ancestorFlags), 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         // HandlesChildEvents: 5) Parent item sets a flag
6006         level1->setFlag(flag, true);
6007         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6008         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6009         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6010         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6011         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6012
6013         // HandlesChildEvents: 6) Child item unsets a flag
6014         level21->setFlag(flag, false);
6015         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6016         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6017         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6018         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6019         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6020
6021         // HandlesChildEvents: 7) Parent item unsets a flag
6022         level21->setFlag(flag, true);
6023         level1->setFlag(flag, false);
6024         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6025         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6026         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6027         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6028         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6029
6030         // Reparent the child to root
6031         level21->setParentItem(0);
6032         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6033         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6034         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6035         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6036
6037         // Reparent the child to level1 again.
6038         level1->setFlag(flag, true);
6039         level21->setParentItem(level1);
6040         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6041         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6042         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6043         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6044         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6045
6046         // Reparenting level31 back to level1.
6047         level31->setParentItem(level1);
6048         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6049         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6050         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6051         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6052         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6053
6054         // Reparenting level31 back to level21.
6055         level31->setParentItem(0);
6056         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
6057         level31->setParentItem(level21);
6058         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6059         QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag);
6060         QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag);
6061         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6062         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6063
6064         // Level1 doesn't handle child events
6065         level1->setFlag(flag, false);
6066         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6067         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6068         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6069         QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag);
6070         QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag);
6071
6072         // Nobody handles child events
6073         level21->setFlag(flag, false);
6074         QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
6075         QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
6076         QCOMPARE(int(level22->d_ptr->ancestorFlags), 0);
6077         QCOMPARE(int(level31->d_ptr->ancestorFlags), 0);
6078         QCOMPARE(int(level32->d_ptr->ancestorFlags), 0);
6079     }
6080
6081     delete level1;
6082 }
6083
6084 void tst_QGraphicsItem::untransformable()
6085 {
6086     QGraphicsItem *item1 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6087     item1->setZValue(1);
6088     item1->setFlag(QGraphicsItem::ItemIgnoresTransformations);
6089     item1->rotate(45);
6090     ((QGraphicsEllipseItem *)item1)->setBrush(Qt::red);
6091
6092     QGraphicsItem *item2 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6093     item2->setParentItem(item1);
6094     item2->rotate(45);
6095     item2->setPos(100, 0);
6096     ((QGraphicsEllipseItem *)item2)->setBrush(Qt::green);
6097
6098     QGraphicsItem *item3 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100));
6099     item3->setParentItem(item2);
6100     item3->setPos(100, 0);
6101     ((QGraphicsEllipseItem *)item3)->setBrush(Qt::blue);
6102
6103     QGraphicsScene scene(-500, -500, 1000, 1000);
6104     scene.addItem(item1);
6105
6106     QWidget topLevel;
6107     QGraphicsView view(&scene,&topLevel);
6108     view.resize(300, 300);
6109     topLevel.show();
6110     view.scale(8, 8);
6111     view.centerOn(0, 0);
6112
6113 // Painting with the DiagCrossPattern is really slow on Mac
6114 // when zoomed out. (The test times out). Task to fix is 155567.
6115 #if !defined(Q_OS_MAC) || 1
6116     view.setBackgroundBrush(QBrush(Qt::black, Qt::DiagCrossPattern));
6117 #endif
6118
6119     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
6120
6121     for (int i = 0; i < 10; ++i) {
6122         QPoint center = view.viewport()->rect().center();
6123         QCOMPARE(view.itemAt(center), item1);
6124         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item1);
6125         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item1);
6126         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item1);
6127         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item1);
6128
6129         center += QPoint(70, 70);
6130         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item2);
6131         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item2);
6132         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item2);
6133         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item2);
6134
6135         center += QPoint(0, 100);
6136         QCOMPARE(view.itemAt(center - QPoint(40, 0)), item3);
6137         QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item3);
6138         QCOMPARE(view.itemAt(center - QPoint(0, 40)), item3);
6139         QCOMPARE(view.itemAt(center - QPoint(0, -40)), item3);
6140
6141         view.scale(0.5, 0.5);
6142         view.rotate(13);
6143         view.shear(qreal(0.01), qreal(0.01));
6144         view.translate(10, 10);
6145         QTest::qWait(25);
6146     }
6147 }
6148
6149 class ContextMenuItem : public QGraphicsRectItem
6150 {
6151 public:
6152     ContextMenuItem()
6153         : ignoreEvent(true), gotEvent(false), eventWasAccepted(false)
6154     { }
6155     bool ignoreEvent;
6156     bool gotEvent;
6157     bool eventWasAccepted;
6158 protected:
6159     void contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
6160     {
6161         gotEvent = true;
6162         eventWasAccepted = event->isAccepted();
6163         if (ignoreEvent)
6164             event->ignore();
6165     }
6166 };
6167
6168 void tst_QGraphicsItem::contextMenuEventPropagation()
6169 {
6170     ContextMenuItem *bottomItem = new ContextMenuItem;
6171     bottomItem->setRect(0, 0, 100, 100);
6172     ContextMenuItem *topItem = new ContextMenuItem;
6173     topItem->setParentItem(bottomItem);
6174     topItem->setRect(0, 0, 100, 100);
6175
6176     QGraphicsScene scene;
6177
6178     QGraphicsView view(&scene);
6179     view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
6180     view.show();
6181     view.resize(200, 200);
6182     QVERIFY(QTest::qWaitForWindowExposed(&view));
6183     QTest::qWait(20);
6184
6185     QContextMenuEvent event(QContextMenuEvent::Mouse, QPoint(10, 10),
6186                             view.viewport()->mapToGlobal(QPoint(10, 10)));
6187     event.ignore();
6188     QApplication::sendEvent(view.viewport(), &event);
6189     QVERIFY(!event.isAccepted());
6190
6191     scene.addItem(bottomItem);
6192     topItem->ignoreEvent = true;
6193     bottomItem->ignoreEvent = true;
6194
6195     QApplication::sendEvent(view.viewport(), &event);
6196     QVERIFY(!event.isAccepted());
6197     QCOMPARE(topItem->gotEvent, true);
6198     QCOMPARE(topItem->eventWasAccepted, true);
6199     QCOMPARE(bottomItem->gotEvent, true);
6200     QCOMPARE(bottomItem->eventWasAccepted, true);
6201
6202     topItem->ignoreEvent = false;
6203     topItem->gotEvent = false;
6204     bottomItem->gotEvent = false;
6205
6206     QApplication::sendEvent(view.viewport(), &event);
6207     QVERIFY(event.isAccepted());
6208     QCOMPARE(topItem->gotEvent, true);
6209     QCOMPARE(bottomItem->gotEvent, false);
6210     QCOMPARE(topItem->eventWasAccepted, true);
6211 }
6212
6213 void tst_QGraphicsItem::itemIsMovable()
6214 {
6215     QGraphicsRectItem *rect = new QGraphicsRectItem(-50, -50, 100, 100);
6216     rect->setFlag(QGraphicsItem::ItemIsMovable);
6217
6218     QGraphicsScene scene;
6219     scene.addItem(rect);
6220
6221     {
6222         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6223         event.setButton(Qt::LeftButton);
6224         event.setButtons(Qt::LeftButton);
6225         qApp->sendEvent(&scene, &event);
6226     }
6227     {
6228         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6229         event.setButton(Qt::LeftButton);
6230         event.setButtons(Qt::LeftButton);
6231         qApp->sendEvent(&scene, &event);
6232     }
6233     QCOMPARE(rect->pos(), QPointF(0, 0));
6234     {
6235         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6236         event.setButtons(Qt::LeftButton);
6237         event.setScenePos(QPointF(10, 10));
6238         qApp->sendEvent(&scene, &event);
6239     }
6240     QCOMPARE(rect->pos(), QPointF(10, 10));
6241     {
6242         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6243         event.setButtons(Qt::RightButton);
6244         event.setScenePos(QPointF(20, 20));
6245         qApp->sendEvent(&scene, &event);
6246     }
6247     QCOMPARE(rect->pos(), QPointF(10, 10));
6248     {
6249         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove);
6250         event.setButtons(Qt::LeftButton);
6251         event.setScenePos(QPointF(30, 30));
6252         qApp->sendEvent(&scene, &event);
6253     }
6254     QCOMPARE(rect->pos(), QPointF(30, 30));
6255 }
6256
6257 class ItemAddScene : public QGraphicsScene
6258 {
6259     Q_OBJECT
6260 public:
6261     ItemAddScene()
6262     {
6263         QTimer::singleShot(500, this, SLOT(newTextItem()));
6264     }
6265
6266 public slots:
6267     void newTextItem()
6268     {
6269         // Add a text item
6270         QGraphicsItem *item = new QGraphicsTextItem("This item will not ensure that it's visible", 0);
6271         item->setPos(.0, .0);
6272         item->show();
6273     }
6274 };
6275
6276 void tst_QGraphicsItem::task141694_textItemEnsureVisible()
6277 {
6278     ItemAddScene scene;
6279     scene.setSceneRect(-1000, -1000, 2000, 2000);
6280
6281     QGraphicsView view(&scene);
6282     view.setFixedSize(200, 200);
6283     view.show();
6284     QVERIFY(QTest::qWaitForWindowExposed(&view));
6285
6286     view.ensureVisible(-1000, -1000, 5, 5);
6287     int hscroll = view.horizontalScrollBar()->value();
6288     int vscroll = view.verticalScrollBar()->value();
6289
6290     QTest::qWait(10);
6291
6292     // This should not cause the view to scroll
6293     QTRY_COMPARE(view.horizontalScrollBar()->value(), hscroll);
6294     QCOMPARE(view.verticalScrollBar()->value(), vscroll);
6295 }
6296
6297 void tst_QGraphicsItem::task128696_textItemEnsureMovable()
6298 {
6299     QGraphicsTextItem *item = new QGraphicsTextItem;
6300     item->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
6301     item->setTextInteractionFlags(Qt::TextEditorInteraction);
6302     item->setPlainText("abc de\nf ghi\n   j k l");
6303
6304     QGraphicsScene scene;
6305     scene.setSceneRect(-100, -100, 200, 200);
6306     scene.addItem(item);
6307
6308     QGraphicsView view(&scene);
6309     view.setFixedSize(200, 200);
6310     view.show();
6311
6312     QGraphicsSceneMouseEvent event1(QEvent::GraphicsSceneMousePress);
6313     event1.setScenePos(QPointF(0, 0));
6314     event1.setButton(Qt::LeftButton);
6315     event1.setButtons(Qt::LeftButton);
6316     QApplication::sendEvent(&scene, &event1);
6317     QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6318
6319     QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove);
6320     event2.setScenePos(QPointF(10, 10));
6321     event2.setButton(Qt::LeftButton);
6322     event2.setButtons(Qt::LeftButton);
6323     QApplication::sendEvent(&scene, &event2);
6324     QCOMPARE(item->pos(), QPointF(10, 10));
6325 }
6326
6327 void tst_QGraphicsItem::task177918_lineItemUndetected()
6328 {
6329     QGraphicsScene scene;
6330     QGraphicsLineItem *line = scene.addLine(10, 10, 10, 10);
6331     QCOMPARE(line->boundingRect(), QRectF(10, 10, 0, 0));
6332
6333     QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemShape).isEmpty());
6334     QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemShape).isEmpty());
6335     QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemBoundingRect).isEmpty());
6336     QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemBoundingRect).isEmpty());
6337 }
6338
6339 void tst_QGraphicsItem::task240400_clickOnTextItem_data()
6340 {
6341     QTest::addColumn<int>("flags");
6342     QTest::addColumn<int>("textFlags");
6343     QTest::newRow("editor, noflags") << 0 << int(Qt::TextEditorInteraction);
6344     QTest::newRow("editor, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::TextEditorInteraction);
6345     QTest::newRow("editor, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::TextEditorInteraction);
6346     QTest::newRow("editor, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
6347                                                   << int(Qt::TextEditorInteraction);
6348     QTest::newRow("noninteractive, noflags") << 0 << int(Qt::NoTextInteraction);
6349     QTest::newRow("noninteractive, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::NoTextInteraction);
6350     QTest::newRow("noninteractive, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::NoTextInteraction);
6351     QTest::newRow("noninteractive, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable)
6352                                                           << int(Qt::NoTextInteraction);
6353 }
6354
6355 void tst_QGraphicsItem::task240400_clickOnTextItem()
6356 {
6357     QFETCH(int, flags);
6358     QFETCH(int, textFlags);
6359
6360     QGraphicsScene scene;
6361     QEvent activate(QEvent::WindowActivate);
6362     QApplication::sendEvent(&scene, &activate);
6363
6364     QGraphicsTextItem *item = scene.addText("Hello");
6365     item->setFlags(QGraphicsItem::GraphicsItemFlags(flags));
6366     item->setTextInteractionFlags(Qt::TextInteractionFlags(textFlags));
6367     bool focusable = (item->flags() & QGraphicsItem::ItemIsFocusable);
6368     QVERIFY(textFlags ? focusable : !focusable);
6369
6370     int column = item->textCursor().columnNumber();
6371     QCOMPARE(column, 0);
6372
6373     QVERIFY(!item->hasFocus());
6374
6375     // Click in the top-left corner of the item
6376     {
6377         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6378         event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
6379         event.setButton(Qt::LeftButton);
6380         event.setButtons(Qt::LeftButton);
6381         QApplication::sendEvent(&scene, &event);
6382     }
6383     if (flags || textFlags)
6384         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6385     else
6386         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
6387     {
6388         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
6389         event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1));
6390         event.setButton(Qt::LeftButton);
6391         event.setButtons(0);
6392         QApplication::sendEvent(&scene, &event);
6393     }
6394     if (textFlags)
6395         QVERIFY(item->hasFocus());
6396     else
6397         QVERIFY(!item->hasFocus());
6398     QVERIFY(!scene.mouseGrabberItem());
6399     bool selectable = (flags & QGraphicsItem::ItemIsSelectable);
6400     QVERIFY(selectable ? item->isSelected() : !item->isSelected());
6401
6402     // Now click in the middle and check that the cursor moved.
6403     {
6404         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress);
6405         event.setScenePos(item->sceneBoundingRect().center());
6406         event.setButton(Qt::LeftButton);
6407         event.setButtons(Qt::LeftButton);
6408         QApplication::sendEvent(&scene, &event);
6409     }
6410     if (flags || textFlags)
6411         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item);
6412     else
6413         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0);
6414     {
6415         QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease);
6416         event.setScenePos(item->sceneBoundingRect().center());
6417         event.setButton(Qt::LeftButton);
6418         event.setButtons(0);
6419         QApplication::sendEvent(&scene, &event);
6420     }
6421     if (textFlags)
6422         QVERIFY(item->hasFocus());
6423     else
6424         QVERIFY(!item->hasFocus());
6425     QVERIFY(!scene.mouseGrabberItem());
6426
6427     QVERIFY(selectable ? item->isSelected() : !item->isSelected());
6428
6429     //
6430     if (textFlags & Qt::TextEditorInteraction)
6431         QVERIFY(item->textCursor().columnNumber() > column);
6432     else
6433         QCOMPARE(item->textCursor().columnNumber(), 0);
6434 }
6435
6436 class TextItem : public QGraphicsSimpleTextItem
6437 {
6438 public:
6439     TextItem(const QString& text) : QGraphicsSimpleTextItem(text)
6440     {
6441         updates = 0;
6442     }
6443
6444     void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
6445     {
6446         updates++;
6447         QGraphicsSimpleTextItem::paint(painter, option, widget);
6448     }
6449
6450     int updates;
6451 };
6452
6453 void tst_QGraphicsItem::ensureUpdateOnTextItem()
6454 {
6455     QGraphicsScene scene;
6456     QGraphicsView view(&scene);
6457     view.show();
6458     QVERIFY(QTest::qWaitForWindowExposed(&view));
6459     QTest::qWait(25);
6460     TextItem *text1 = new TextItem(QLatin1String("123"));
6461     scene.addItem(text1);
6462     qApp->processEvents();
6463     QTRY_COMPARE(text1->updates,1);
6464
6465     //same bouding rect but we have to update
6466     text1->setText(QLatin1String("321"));
6467     qApp->processEvents();
6468     QTRY_COMPARE(text1->updates,2);
6469 }
6470
6471 void tst_QGraphicsItem::task243707_addChildBeforeParent()
6472 {
6473     // Task reports that adding the child before the parent leads to an
6474     // inconsistent internal state that can cause a crash.  This test shows
6475     // one such crash.
6476     QGraphicsScene scene;
6477     QGraphicsWidget *widget = new QGraphicsWidget;
6478     QGraphicsWidget *widget2 = new QGraphicsWidget(widget);
6479     scene.addItem(widget2);
6480     QVERIFY(!widget2->parentItem());
6481     scene.addItem(widget);
6482     QVERIFY(!widget->commonAncestorItem(widget2));
6483     QVERIFY(!widget2->commonAncestorItem(widget));
6484 }
6485
6486 void tst_QGraphicsItem::task197802_childrenVisibility()
6487 {
6488     QGraphicsScene scene;
6489     QGraphicsRectItem item(QRectF(0,0,20,20));
6490
6491     QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(0,0,10,10), &item);
6492     scene.addItem(&item);
6493
6494     //freshly created: both visible
6495     QVERIFY(item.isVisible());
6496     QVERIFY(item2->isVisible());
6497
6498     //hide child: parent visible, child not
6499     item2->hide();
6500     QVERIFY(item.isVisible());
6501     QVERIFY(!item2->isVisible());
6502
6503     //hide parent: parent and child invisible
6504     item.hide();
6505     QVERIFY(!item.isVisible());
6506     QVERIFY(!item2->isVisible());
6507
6508     //ask to show the child: parent and child invisible anyways
6509     item2->show();
6510     QVERIFY(!item.isVisible());
6511     QVERIFY(!item2->isVisible());
6512
6513     //show the parent: both parent and child visible
6514     item.show();
6515     QVERIFY(item.isVisible());
6516     QVERIFY(item2->isVisible());
6517
6518     delete item2;
6519 }
6520
6521 void tst_QGraphicsItem::boundingRegion_data()
6522 {
6523     QTest::addColumn<QLineF>("line");
6524     QTest::addColumn<qreal>("granularity");
6525     QTest::addColumn<QTransform>("transform");
6526     QTest::addColumn<QRegion>("expectedRegion");
6527
6528     QTest::newRow("(0, 0, 10, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.0) << QTransform()
6529                                                                         << QRegion(QRect(0, 0, 10, 10));
6530     QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform()
6531                                                                        << QRegion(QRect(0, 0, 10, 1));
6532     QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform()
6533                                                                       << QRegion(QRect(0, 0, 10, 1));
6534     QTest::newRow("(0, 0, 10, 0) | 1.0 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(1.0) << QTransform()
6535                                                                       << QRegion(QRect(0, 0, 10, 1));
6536     QTest::newRow("(0, 0, 0, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.0) << QTransform()
6537                                                                        << QRegion(QRect(0, 0, 1, 10));
6538     QTest::newRow("(0, 0, 0, 10) | 0.5 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.5) << QTransform()
6539                                                                       << QRegion(QRect(0, 0, 1, 10));
6540     QTest::newRow("(0, 0, 0, 10) | 1.0 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(1.0) << QTransform()
6541                                                                       << QRegion(QRect(0, 0, 1, 10));
6542 }
6543
6544 void tst_QGraphicsItem::boundingRegion()
6545 {
6546     QFETCH(QLineF, line);
6547     QFETCH(qreal, granularity);
6548     QFETCH(QTransform, transform);
6549     QFETCH(QRegion, expectedRegion);
6550
6551     QGraphicsLineItem item(line);
6552     item.setPen(QPen(Qt::black, 0));
6553     QCOMPARE(item.boundingRegionGranularity(), qreal(0.0));
6554     item.setBoundingRegionGranularity(granularity);
6555     QCOMPARE(item.boundingRegionGranularity(), granularity);
6556     QCOMPARE(item.boundingRegion(transform), expectedRegion);
6557 }
6558
6559 void tst_QGraphicsItem::itemTransform_parentChild()
6560 {
6561     QGraphicsScene scene;
6562     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6563     QGraphicsItem *child = scene.addRect(0, 0, 100, 100);
6564     child->setParentItem(parent);
6565     child->setPos(10, 10);
6566     child->scale(2, 2);
6567     child->rotate(90);
6568
6569     QCOMPARE(child->itemTransform(parent).map(QPointF(10, 10)), QPointF(-10, 30));
6570     QCOMPARE(parent->itemTransform(child).map(QPointF(-10, 30)), QPointF(10, 10));
6571 }
6572
6573 void tst_QGraphicsItem::itemTransform_siblings()
6574 {
6575     QGraphicsScene scene;
6576     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
6577     QGraphicsItem *brother = scene.addRect(0, 0, 100, 100);
6578     QGraphicsItem *sister = scene.addRect(0, 0, 100, 100);
6579     parent->scale(10, 5);
6580     parent->rotate(-180);
6581     parent->shear(2, 3);
6582
6583     brother->setParentItem(parent);
6584     sister->setParentItem(parent);
6585
6586     brother->setPos(10, 10);
6587     brother->scale(2, 2);
6588     brother->rotate(90);
6589     sister->setPos(10, 10);
6590     sister->scale(2, 2);
6591     sister->rotate(90);
6592
6593     QCOMPARE(brother->itemTransform(sister).map(QPointF(10, 10)), QPointF(10, 10));
6594     QCOMPARE(sister->itemTransform(brother).map(QPointF(10, 10)), QPointF(10, 10));
6595 }
6596
6597 void tst_QGraphicsItem::itemTransform_unrelated()
6598 {
6599     QGraphicsScene scene;
6600     QGraphicsItem *stranger1 = scene.addRect(0, 0, 100, 100);
6601     QGraphicsItem *stranger2 = scene.addRect(0, 0, 100, 100);
6602     stranger1->setPos(10, 10);
6603     stranger1->scale(2, 2);
6604     stranger1->rotate(90);
6605     stranger2->setPos(10, 10);
6606     stranger2->scale(2, 2);
6607     stranger2->rotate(90);
6608
6609     QCOMPARE(stranger1->itemTransform(stranger2).map(QPointF(10, 10)), QPointF(10, 10));
6610     QCOMPARE(stranger2->itemTransform(stranger1).map(QPointF(10, 10)), QPointF(10, 10));
6611 }
6612
6613 void tst_QGraphicsItem::opacity_data()
6614 {
6615     QTest::addColumn<qreal>("p_opacity");
6616     QTest::addColumn<int>("p_opacityFlags");
6617     QTest::addColumn<qreal>("c1_opacity");
6618     QTest::addColumn<int>("c1_opacityFlags");
6619     QTest::addColumn<qreal>("c2_opacity");
6620     QTest::addColumn<int>("c2_opacityFlags");
6621     QTest::addColumn<qreal>("p_effectiveOpacity");
6622     QTest::addColumn<qreal>("c1_effectiveOpacity");
6623     QTest::addColumn<qreal>("c2_effectiveOpacity");
6624     QTest::addColumn<qreal>("c3_effectiveOpacity");
6625
6626     // Modify the opacity and see how it propagates
6627     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
6628                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6629     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
6630                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6631     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
6632                                                         << qreal(0.5) << qreal(0.05) << qreal(0.05) << qreal(0.05);
6633     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
6634                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6635
6636     // Parent doesn't propagate to children - now modify the opacity and see how it propagates
6637     int flags = QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6638     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
6639                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6640     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
6641                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6642     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
6643                                                         << qreal(0.5) << qreal(0.1) << qreal(0.1) << qreal(0.1);
6644     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
6645                                                         << qreal(0.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6646
6647     // Child ignores parent - now modify the opacity and see how it propagates
6648     flags = QGraphicsItem::ItemIgnoresParentOpacity;
6649     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
6650                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6651     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
6652                                                         << qreal(0.5) << qreal(0.5) << qreal(0.25) << qreal(0.25);
6653     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
6654                                                         << qreal(0.2) << qreal(0.2) << qreal(0.04) << qreal(0.04);
6655     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
6656                                                         << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
6657
6658     // Child ignores parent and doesn't propagate - now modify the opacity and see how it propagates
6659     flags = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6660     QTest::newRow("M: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6661                                                         << qreal(1.0) << flags // c1 (no prop)
6662                                                         << qreal(1.0) << 0 // c2
6663                                                         << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6664     QTest::newRow("M: 0.5 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6665                                                         << qreal(1.0) << flags // c1 (no prop)
6666                                                         << qreal(1.0) << 0 // c2
6667                                                         << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0);
6668     QTest::newRow("M: 0.5 0 0.5 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6669                                                         << qreal(0.5) << flags // c1 (no prop)
6670                                                         << qreal(1.0) << 0 // c2
6671                                                         << qreal(0.5) << qreal(0.5) << qreal(1.0) << qreal(1.0);
6672     QTest::newRow("M: 0.5 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p
6673                                                         << qreal(0.5) << flags // c1 (no prop)
6674                                                         << qreal(0.5) << 0 // c2
6675                                                         << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6676     QTest::newRow("M: 1.0 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p
6677                                                         << qreal(0.5) << flags // c1 (no prop)
6678                                                         << qreal(0.5) << 0 // c2
6679                                                         << qreal(1.0) << qreal(0.5) << qreal(0.5) << qreal(0.5);
6680 }
6681
6682 void tst_QGraphicsItem::opacity()
6683 {
6684     QFETCH(qreal, p_opacity);
6685     QFETCH(int, p_opacityFlags);
6686     QFETCH(qreal, p_effectiveOpacity);
6687     QFETCH(qreal, c1_opacity);
6688     QFETCH(int, c1_opacityFlags);
6689     QFETCH(qreal, c1_effectiveOpacity);
6690     QFETCH(qreal, c2_opacity);
6691     QFETCH(int, c2_opacityFlags);
6692     QFETCH(qreal, c2_effectiveOpacity);
6693     QFETCH(qreal, c3_effectiveOpacity);
6694
6695     QGraphicsRectItem *p = new QGraphicsRectItem;
6696     QGraphicsRectItem *c1 = new QGraphicsRectItem(p);
6697     QGraphicsRectItem *c2 = new QGraphicsRectItem(c1);
6698     QGraphicsRectItem *c3 = new QGraphicsRectItem(c2);
6699
6700     QCOMPARE(p->opacity(), qreal(1.0));
6701     QCOMPARE(p->effectiveOpacity(), qreal(1.0));
6702     int opacityMask = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren;
6703     QVERIFY(!(p->flags() & opacityMask));
6704
6705     p->setOpacity(p_opacity);
6706     c1->setOpacity(c1_opacity);
6707     c2->setOpacity(c2_opacity);
6708     p->setFlags(QGraphicsItem::GraphicsItemFlags(p->flags() | p_opacityFlags));
6709     c1->setFlags(QGraphicsItem::GraphicsItemFlags(c1->flags() | c1_opacityFlags));
6710     c2->setFlags(QGraphicsItem::GraphicsItemFlags(c2->flags() | c2_opacityFlags));
6711
6712     QCOMPARE(int(p->flags() & opacityMask), p_opacityFlags);
6713     QCOMPARE(int(c1->flags() & opacityMask), c1_opacityFlags);
6714     QCOMPARE(int(c2->flags() & opacityMask), c2_opacityFlags);
6715     QCOMPARE(p->opacity(), p_opacity);
6716     QCOMPARE(p->effectiveOpacity(), p_effectiveOpacity);
6717     QCOMPARE(c1->effectiveOpacity(), c1_effectiveOpacity);
6718     QCOMPARE(c2->effectiveOpacity(), c2_effectiveOpacity);
6719     QCOMPARE(c3->effectiveOpacity(), c3_effectiveOpacity);
6720 }
6721
6722 void tst_QGraphicsItem::opacity2()
6723 {
6724     EventTester *parent = new EventTester;
6725     EventTester *child = new EventTester(parent);
6726     EventTester *grandChild = new EventTester(child);
6727
6728     QGraphicsScene scene;
6729     scene.addItem(parent);
6730
6731     MyGraphicsView view(&scene);
6732     view.show();
6733     QVERIFY(QTest::qWaitForWindowActive(&view));
6734     QTRY_VERIFY(view.repaints >= 1);
6735
6736 #define RESET_REPAINT_COUNTERS \
6737     parent->repaints = 0; \
6738     child->repaints = 0; \
6739     grandChild->repaints = 0; \
6740     view.repaints = 0;
6741
6742     RESET_REPAINT_COUNTERS
6743
6744     child->setOpacity(0.0);
6745     QTest::qWait(10);
6746     QTRY_COMPARE(view.repaints, 1);
6747     QCOMPARE(parent->repaints, 1);
6748     QCOMPARE(child->repaints, 0);
6749     QCOMPARE(grandChild->repaints, 0);
6750
6751     RESET_REPAINT_COUNTERS
6752
6753     child->setOpacity(1.0);
6754     QTest::qWait(10);
6755     QTRY_COMPARE(view.repaints, 1);
6756     QCOMPARE(parent->repaints, 1);
6757     QCOMPARE(child->repaints, 1);
6758     QCOMPARE(grandChild->repaints, 1);
6759
6760     RESET_REPAINT_COUNTERS
6761
6762     parent->setOpacity(0.0);
6763     QTest::qWait(10);
6764     QTRY_COMPARE(view.repaints, 1);
6765     QCOMPARE(parent->repaints, 0);
6766     QCOMPARE(child->repaints, 0);
6767     QCOMPARE(grandChild->repaints, 0);
6768
6769     RESET_REPAINT_COUNTERS
6770
6771     parent->setOpacity(1.0);
6772     QTest::qWait(10);
6773     QTRY_COMPARE(view.repaints, 1);
6774     QCOMPARE(parent->repaints, 1);
6775     QCOMPARE(child->repaints, 1);
6776     QCOMPARE(grandChild->repaints, 1);
6777
6778     grandChild->setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
6779     RESET_REPAINT_COUNTERS
6780
6781     child->setOpacity(0.0);
6782     QTest::qWait(10);
6783     QTRY_COMPARE(view.repaints, 1);
6784     QCOMPARE(parent->repaints, 1);
6785     QCOMPARE(child->repaints, 0);
6786     QCOMPARE(grandChild->repaints, 1);
6787
6788     RESET_REPAINT_COUNTERS
6789
6790     child->setOpacity(0.0); // Already 0.0; no change.
6791     QTest::qWait(10);
6792     QTRY_COMPARE(view.repaints, 0);
6793     QCOMPARE(parent->repaints, 0);
6794     QCOMPARE(child->repaints, 0);
6795     QCOMPARE(grandChild->repaints, 0);
6796 }
6797
6798 void tst_QGraphicsItem::opacityZeroUpdates()
6799 {
6800     EventTester *parent = new EventTester;
6801     EventTester *child = new EventTester(parent);
6802
6803     child->setPos(10, 10);
6804
6805     QGraphicsScene scene;
6806     scene.addItem(parent);
6807
6808     MyGraphicsView view(&scene);
6809     view.show();
6810     QVERIFY(QTest::qWaitForWindowActive(&view));
6811     QTRY_VERIFY(view.repaints > 0);
6812
6813     view.reset();
6814     parent->setOpacity(0.0);
6815
6816     QTest::qWait(20);
6817
6818     // transforming items bounding rect to view coordinates
6819     const QRect childDeviceBoundingRect = child->deviceTransform(view.viewportTransform())
6820                                            .mapRect(child->boundingRect()).toRect();
6821     const QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
6822                                            .mapRect(parent->boundingRect()).toRect();
6823
6824     QRegion expectedRegion = parentDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6825     expectedRegion += childDeviceBoundingRect.adjusted(-2, -2, 2, 2);
6826
6827     COMPARE_REGIONS(view.paintedRegion, expectedRegion);
6828 }
6829
6830 class StacksBehindParentHelper : public QGraphicsRectItem
6831 {
6832 public:
6833     StacksBehindParentHelper(QList<QGraphicsItem *> *paintedItems, const QRectF &rect, QGraphicsItem *parent = 0)
6834         : QGraphicsRectItem(rect, parent), paintedItems(paintedItems)
6835     { }
6836
6837     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
6838     {
6839         QGraphicsRectItem::paint(painter, option, widget);
6840         paintedItems->append(this);
6841     }
6842
6843 private:
6844     QList<QGraphicsItem *> *paintedItems;
6845 };
6846
6847 void tst_QGraphicsItem::itemStacksBehindParent()
6848 {
6849     StacksBehindParentHelper *parent1 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6850     StacksBehindParentHelper *child11 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent1);
6851     StacksBehindParentHelper *grandChild111 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child11);
6852     StacksBehindParentHelper *child12 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent1);
6853     StacksBehindParentHelper *grandChild121 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child12);
6854
6855     StacksBehindParentHelper *parent2 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50));
6856     StacksBehindParentHelper *child21 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent2);
6857     StacksBehindParentHelper *grandChild211 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child21);
6858     StacksBehindParentHelper *child22 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent2);
6859     StacksBehindParentHelper *grandChild221 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child22);
6860
6861     parent1->setData(0, "parent1");
6862     child11->setData(0, "child11");
6863     grandChild111->setData(0, "grandChild111");
6864     child12->setData(0, "child12");
6865     grandChild121->setData(0, "grandChild121");
6866     parent2->setData(0, "parent2");
6867     child21->setData(0, "child21");
6868     grandChild211->setData(0, "grandChild211");
6869     child22->setData(0, "child22");
6870     grandChild221->setData(0, "grandChild221");
6871
6872     // Disambiguate siblings
6873     parent1->setZValue(1);
6874     child11->setZValue(1);
6875     child21->setZValue(1);
6876
6877     QGraphicsScene scene;
6878     scene.addItem(parent1);
6879     scene.addItem(parent2);
6880
6881     QGraphicsView view(&scene);
6882     view.show();
6883     QVERIFY(QTest::qWaitForWindowExposed(&view));
6884     QTRY_VERIFY(!paintedItems.isEmpty());
6885     QTest::qWait(100);
6886     paintedItems.clear();
6887     view.viewport()->update();
6888     QApplication::processEvents();
6889     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6890                                            << grandChild111 << child11
6891                                            << grandChild121 << child12 << parent1
6892                                            << grandChild211 << child21
6893                                            << grandChild221 << child22 << parent2));
6894     QTRY_COMPARE(paintedItems, QList<QGraphicsItem *>()
6895              << parent2 << child22 << grandChild221
6896              << child21 << grandChild211
6897              << parent1 << child12 << grandChild121
6898              << child11 << grandChild111);
6899
6900     child11->setFlag(QGraphicsItem::ItemStacksBehindParent);
6901     scene.update();
6902     paintedItems.clear();
6903     QApplication::processEvents();
6904
6905     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6906                                            << grandChild121 << child12 << parent1
6907                                            << grandChild111 << child11
6908                                            << grandChild211 << child21
6909                                            << grandChild221 << child22 << parent2));
6910     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6911              << parent2 << child22 << grandChild221
6912              << child21 << grandChild211
6913              << child11 << grandChild111
6914              << parent1 << child12 << grandChild121);
6915
6916     child12->setFlag(QGraphicsItem::ItemStacksBehindParent);
6917     paintedItems.clear();
6918     scene.update();
6919     QApplication::processEvents();
6920
6921     QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList<QGraphicsItem *>()
6922                                            << parent1 << grandChild111 << child11
6923                                            << grandChild121 << child12
6924                                            << grandChild211 << child21
6925                                            << grandChild221 << child22 << parent2));
6926     QCOMPARE(paintedItems, QList<QGraphicsItem *>()
6927              << parent2 << child22 << grandChild221
6928              << child21 << grandChild211
6929              << child12 << grandChild121
6930              << child11 << grandChild111 << parent1);
6931 }
6932
6933 class ClippingAndTransformsScene : public QGraphicsScene
6934 {
6935 public:
6936     QList<QGraphicsItem *> drawnItems;
6937 protected:
6938     void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[],
6939                    const QStyleOptionGraphicsItem options[], QWidget *widget = 0)
6940     {
6941         drawnItems.clear();
6942         for (int i = 0; i < numItems; ++i)
6943             drawnItems << items[i];
6944         QGraphicsScene::drawItems(painter, numItems, items, options, widget);
6945     }
6946 };
6947
6948 void tst_QGraphicsItem::nestedClipping()
6949 {
6950     ClippingAndTransformsScene scene;
6951     scene.setSceneRect(-50, -50, 200, 200);
6952
6953     QGraphicsRectItem *root = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6954     root->setBrush(QColor(0, 0, 255));
6955     root->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6956     QGraphicsRectItem *l1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
6957     l1->setParentItem(root);
6958     l1->setPos(-50, 0);
6959     l1->setBrush(QColor(255, 0, 0));
6960     l1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6961     QGraphicsEllipseItem *l2 = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100));
6962     l2->setParentItem(l1);
6963     l2->setPos(50, 50);
6964     l2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
6965     l2->setBrush(QColor(255, 255, 0));
6966     QGraphicsRectItem *l3 = new QGraphicsRectItem(QRectF(0, 0, 25, 25));
6967     l3->setParentItem(l2);
6968     l3->setBrush(QColor(0, 255, 0));
6969     l3->setPos(50 - 12, -12);
6970
6971     scene.addItem(root);
6972
6973     root->setData(0, "root");
6974     l1->setData(0, "l1");
6975     l2->setData(0, "l2");
6976     l3->setData(0, "l3");
6977
6978     QGraphicsView view(&scene);
6979     view.setOptimizationFlag(QGraphicsView::IndirectPainting);
6980     view.show();
6981     QVERIFY(QTest::qWaitForWindowExposed(&view));
6982     QTest::qWait(25);
6983
6984     QList<QGraphicsItem *> expected;
6985     expected << root << l1 << l2 << l3;
6986     QTRY_COMPARE(scene.drawnItems, expected);
6987
6988     QImage image(200, 200, QImage::Format_ARGB32_Premultiplied);
6989     image.fill(0);
6990
6991     QPainter painter(&image);
6992     scene.render(&painter);
6993     painter.end();
6994
6995     // Check transparent areas
6996     QCOMPARE(image.pixel(100, 25), qRgba(0, 0, 0, 0));
6997     QCOMPARE(image.pixel(100, 175), qRgba(0, 0, 0, 0));
6998     QCOMPARE(image.pixel(25, 100), qRgba(0, 0, 0, 0));
6999     QCOMPARE(image.pixel(175, 100), qRgba(0, 0, 0, 0));
7000     QCOMPARE(image.pixel(70, 80), qRgba(255, 0, 0, 255));
7001     QCOMPARE(image.pixel(80, 130), qRgba(255, 255, 0, 255));
7002     QCOMPARE(image.pixel(92, 105), qRgba(0, 255, 0, 255));
7003     QCOMPARE(image.pixel(105, 105), qRgba(0, 0, 255, 255));
7004 #if 0
7005     // Enable this to compare if the test starts failing.
7006     image.save("nestedClipping_reference.png");
7007 #endif
7008 }
7009
7010 class TransformDebugItem : public QGraphicsRectItem
7011 {
7012 public:
7013     TransformDebugItem()
7014         : QGraphicsRectItem(QRectF(-10, -10, 20, 20))
7015     {
7016         setPen(QPen(Qt::black, 0));
7017         setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
7018     }
7019
7020     QTransform x;
7021
7022     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
7023                QWidget *widget = 0)
7024     {
7025         x = painter->worldTransform();
7026         QGraphicsRectItem::paint(painter, option, widget);
7027     }
7028 };
7029
7030 void tst_QGraphicsItem::nestedClippingTransforms()
7031 {
7032     TransformDebugItem *rootClipper = new TransformDebugItem;
7033     rootClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7034     TransformDebugItem *child = new TransformDebugItem;
7035     child->setParentItem(rootClipper);
7036     child->setPos(2, 2);
7037     TransformDebugItem *grandChildClipper = new TransformDebugItem;
7038     grandChildClipper->setParentItem(child);
7039     grandChildClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7040     grandChildClipper->setPos(4, 4);
7041     TransformDebugItem *greatGrandChild = new TransformDebugItem;
7042     greatGrandChild->setPos(2, 2);
7043     greatGrandChild->setParentItem(grandChildClipper);
7044     TransformDebugItem *grandChildClipper2 = new TransformDebugItem;
7045     grandChildClipper2->setParentItem(child);
7046     grandChildClipper2->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7047     grandChildClipper2->setPos(8, 8);
7048     TransformDebugItem *greatGrandChild2 = new TransformDebugItem;
7049     greatGrandChild2->setPos(2, 2);
7050     greatGrandChild2->setParentItem(grandChildClipper2);
7051     TransformDebugItem *grandChildClipper3 = new TransformDebugItem;
7052     grandChildClipper3->setParentItem(child);
7053     grandChildClipper3->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
7054     grandChildClipper3->setPos(12, 12);
7055     TransformDebugItem *greatGrandChild3 = new TransformDebugItem;
7056     greatGrandChild3->setPos(2, 2);
7057     greatGrandChild3->setParentItem(grandChildClipper3);
7058
7059     QGraphicsScene scene;
7060     scene.addItem(rootClipper);
7061
7062     QImage image(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
7063     image.fill(0);
7064     QPainter p(&image);
7065     scene.render(&p);
7066     p.end();
7067
7068     QCOMPARE(rootClipper->x, QTransform(1, 0, 0, 0, 1, 0, 10, 10, 1));
7069     QCOMPARE(child->x, QTransform(1, 0, 0, 0, 1, 0, 12, 12, 1));
7070     QCOMPARE(grandChildClipper->x, QTransform(1, 0, 0, 0, 1, 0, 16, 16, 1));
7071     QCOMPARE(greatGrandChild->x, QTransform(1, 0, 0, 0, 1, 0, 18, 18, 1));
7072     QCOMPARE(grandChildClipper2->x, QTransform(1, 0, 0, 0, 1, 0, 20, 20, 1));
7073     QCOMPARE(greatGrandChild2->x, QTransform(1, 0, 0, 0, 1, 0, 22, 22, 1));
7074     QCOMPARE(grandChildClipper3->x, QTransform(1, 0, 0, 0, 1, 0, 24, 24, 1));
7075     QCOMPARE(greatGrandChild3->x, QTransform(1, 0, 0, 0, 1, 0, 26, 26, 1));
7076 }
7077
7078 void tst_QGraphicsItem::sceneTransformCache()
7079 {
7080     // Test that an item's scene transform is updated correctly when the
7081     // parent is transformed.
7082     QGraphicsScene scene;
7083     QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100);
7084     rect->setPen(QPen(Qt::black, 0));
7085     QGraphicsRectItem *rect2 = scene.addRect(0, 0, 100, 100);
7086     rect2->setPen(QPen(Qt::black, 0));
7087     rect2->setParentItem(rect);
7088     rect2->rotate(90);
7089     rect->translate(0, 50);
7090     QGraphicsView view(&scene);
7091     view.show();
7092     QVERIFY(QTest::qWaitForWindowExposed(&view));
7093     rect->translate(0, 100);
7094     QTransform x;
7095     x.translate(0, 150);
7096     x.rotate(90);
7097     QCOMPARE(rect2->sceneTransform(), x);
7098
7099     scene.removeItem(rect);
7100
7101     //Crazy use case : rect4 child of rect3 so the transformation of rect4 will be cached.Good!
7102     //We remove rect4 from the scene, then the validTransform bit flag is set to 0 and the index of the cache
7103     //add to the freeTransformSlots. The problem was that sceneTransformIndex was not set to -1 so if a new item arrive
7104     //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
7105     //added back to the scene then it will set the transform to his old sceneTransformIndex value that will erase the new
7106     //value of rect6 so rect6 transform will be wrong.
7107     QGraphicsRectItem *rect3 = scene.addRect(0, 0, 100, 100);
7108     QGraphicsRectItem *rect4 = scene.addRect(0, 0, 100, 100);
7109     rect3->setPos(QPointF(10,10));
7110     rect3->setPen(QPen(Qt::black, 0));
7111
7112     rect4->setParentItem(rect3);
7113     rect4->setPos(QPointF(10,10));
7114     rect4->setPen(QPen(Qt::black, 0));
7115
7116     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(20,20));
7117
7118     scene.removeItem(rect4);
7119     //rect4 transform is local only
7120     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7121
7122     QGraphicsRectItem *rect5 = scene.addRect(0, 0, 100, 100);
7123     QGraphicsRectItem *rect6 = scene.addRect(0, 0, 100, 100);
7124     rect5->setPos(QPointF(20,20));
7125     rect5->setPen(QPen(Qt::black, 0));
7126
7127     rect6->setParentItem(rect5);
7128     rect6->setPos(QPointF(10,10));
7129     rect6->setPen(QPen(Qt::black, 0));
7130     //test if rect6 transform is ok
7131     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7132
7133     scene.addItem(rect4);
7134
7135     QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10));
7136     //test if rect6 transform is still correct
7137     QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30));
7138 }
7139
7140 void tst_QGraphicsItem::tabChangesFocus_data()
7141 {
7142     QTest::addColumn<bool>("tabChangesFocus");
7143     QTest::newRow("tab changes focus") << true;
7144     QTest::newRow("tab doesn't change focus") << false;
7145 }
7146
7147 void tst_QGraphicsItem::tabChangesFocus()
7148 {
7149     QFETCH(bool, tabChangesFocus);
7150
7151     QGraphicsScene scene;
7152     QGraphicsTextItem *item = scene.addText("Hello");
7153     item->setTabChangesFocus(tabChangesFocus);
7154     item->setTextInteractionFlags(Qt::TextEditorInteraction);
7155     item->setFocus();
7156
7157     QDial *dial1 = new QDial;
7158     QGraphicsView *view = new QGraphicsView(&scene);
7159
7160     QDial *dial2 = new QDial;
7161     QVBoxLayout *layout = new QVBoxLayout;
7162     layout->addWidget(dial1);
7163     layout->addWidget(view);
7164     layout->addWidget(dial2);
7165
7166     QWidget widget;
7167     widget.setLayout(layout);
7168     widget.show();
7169     QVERIFY(QTest::qWaitForWindowActive(&widget));
7170
7171     QTRY_VERIFY(scene.isActive());
7172
7173     dial1->setFocus();
7174     QTest::qWait(15);
7175     QTRY_VERIFY(dial1->hasFocus());
7176
7177     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7178     QTest::qWait(15);
7179     QTRY_VERIFY(view->hasFocus());
7180     QTRY_VERIFY(item->hasFocus());
7181
7182     QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab);
7183     QTest::qWait(15);
7184
7185     if (tabChangesFocus) {
7186         QTRY_VERIFY(!view->hasFocus());
7187         QTRY_VERIFY(!item->hasFocus());
7188         QTRY_VERIFY(dial2->hasFocus());
7189     } else {
7190         QTRY_VERIFY(view->hasFocus());
7191         QTRY_VERIFY(item->hasFocus());
7192         QCOMPARE(item->toPlainText(), QString("\tHello"));
7193     }
7194 }
7195
7196 void tst_QGraphicsItem::cacheMode()
7197 {
7198     QGraphicsScene scene(0, 0, 100, 100);
7199     QGraphicsView view(&scene);
7200     view.resize(150, 150);
7201     view.show();
7202     QApplication::setActiveWindow(&view);
7203     QVERIFY(QTest::qWaitForWindowActive(&view));
7204
7205     // Increase the probability of window activation
7206     // not causing another repaint of test items.
7207     QTest::qWait(50);
7208
7209     EventTester *tester = new EventTester;
7210     EventTester *testerChild = new EventTester;
7211     testerChild->setParentItem(tester);
7212     EventTester *testerChild2 = new EventTester;
7213     testerChild2->setParentItem(testerChild);
7214     testerChild2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
7215
7216     scene.addItem(tester);
7217     QTest::qWait(10);
7218
7219     for (int i = 0; i < 2; ++i) {
7220         // No visual change.
7221         QTRY_COMPARE(tester->repaints, 1);
7222         QCOMPARE(testerChild->repaints, 1);
7223         QCOMPARE(testerChild2->repaints, 1);
7224         tester->setCacheMode(QGraphicsItem::NoCache);
7225         testerChild->setCacheMode(QGraphicsItem::NoCache);
7226         testerChild2->setCacheMode(QGraphicsItem::NoCache);
7227         QTest::qWait(25);
7228         QTRY_COMPARE(tester->repaints, 1);
7229         QCOMPARE(testerChild->repaints, 1);
7230         QCOMPARE(testerChild2->repaints, 1);
7231         tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7232         testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7233         testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7234         QTest::qWait(25);
7235     }
7236
7237     // The first move causes a repaint as the item is painted into its pixmap.
7238     // (Only occurs if the item has previously been painted without cache).
7239     tester->setPos(10, 10);
7240     testerChild->setPos(10, 10);
7241     testerChild2->setPos(10, 10);
7242     QTest::qWait(25);
7243     QTRY_COMPARE(tester->repaints, 2);
7244     QCOMPARE(testerChild->repaints, 2);
7245     QCOMPARE(testerChild2->repaints, 2);
7246
7247     // Consecutive moves should not repaint.
7248     tester->setPos(20, 20);
7249     testerChild->setPos(20, 20);
7250     testerChild2->setPos(20, 20);
7251     QTest::qWait(250);
7252     QCOMPARE(tester->repaints, 2);
7253     QCOMPARE(testerChild->repaints, 2);
7254     QCOMPARE(testerChild2->repaints, 2);
7255
7256     // Translating does not result in a repaint.
7257     tester->translate(10, 10);
7258     QTest::qWait(25);
7259     QTRY_COMPARE(tester->repaints, 2);
7260     QCOMPARE(testerChild->repaints, 2);
7261     QCOMPARE(testerChild2->repaints, 2);
7262
7263     // Rotating results in a repaint.
7264     tester->rotate(45);
7265     QTest::qWait(25);
7266     QTRY_COMPARE(tester->repaints, 3);
7267     QCOMPARE(testerChild->repaints, 3);
7268     QCOMPARE(testerChild2->repaints, 2);
7269
7270     // Change to ItemCoordinateCache (triggers repaint).
7271     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7272     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7273     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize
7274     QTest::qWait(25);
7275     QTRY_COMPARE(tester->repaints, 4);
7276     QCOMPARE(testerChild->repaints, 4);
7277     QCOMPARE(testerChild2->repaints, 3);
7278
7279     // Rotating items with ItemCoordinateCache doesn't cause a repaint.
7280     tester->rotate(22);
7281     testerChild->rotate(22);
7282     testerChild2->rotate(22);
7283     QTest::qWait(25);
7284     QTRY_COMPARE(tester->repaints, 4);
7285     QTRY_COMPARE(testerChild->repaints, 4);
7286     QTRY_COMPARE(testerChild2->repaints, 3);
7287     tester->resetTransform();
7288     testerChild->resetTransform();
7289     testerChild2->resetTransform();
7290
7291     // Explicit update causes a repaint.
7292     tester->update(0, 0, 5, 5);
7293     QTest::qWait(25);
7294     QTRY_COMPARE(tester->repaints, 5);
7295     QCOMPARE(testerChild->repaints, 4);
7296     QCOMPARE(testerChild2->repaints, 3);
7297
7298     // Updating outside the item's bounds does not cause a repaint.
7299     tester->update(10, 10, 5, 5);
7300     QTest::qWait(25);
7301     QTRY_COMPARE(tester->repaints, 5);
7302     QCOMPARE(testerChild->repaints, 4);
7303     QCOMPARE(testerChild2->repaints, 3);
7304
7305     // Resizing an item should cause a repaint of that item. (because of
7306     // autosize).
7307     tester->setGeometry(QRectF(-15, -15, 30, 30));
7308     QTest::qWait(25);
7309     QTRY_COMPARE(tester->repaints, 6);
7310     QCOMPARE(testerChild->repaints, 4);
7311     QCOMPARE(testerChild2->repaints, 3);
7312
7313     // Set fixed size.
7314     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7315     testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7316     testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30));
7317     QTest::qWait(20);
7318     QTRY_COMPARE(tester->repaints, 7);
7319     QCOMPARE(testerChild->repaints, 5);
7320     QCOMPARE(testerChild2->repaints, 4);
7321
7322     // Resizing the item should cause a repaint.
7323     testerChild->setGeometry(QRectF(-15, -15, 30, 30));
7324     QTest::qWait(25);
7325     QTRY_COMPARE(tester->repaints, 7);
7326     QCOMPARE(testerChild->repaints, 6);
7327     QCOMPARE(testerChild2->repaints, 4);
7328
7329     // Scaling the view does not cause a repaint.
7330     view.scale(0.7, 0.7);
7331     QTest::qWait(25);
7332     QTRY_COMPARE(tester->repaints, 7);
7333     QCOMPARE(testerChild->repaints, 6);
7334     QCOMPARE(testerChild2->repaints, 4);
7335
7336     // Switch to device coordinate cache.
7337     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7338     testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7339     testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7340     QTest::qWait(25);
7341     QTRY_COMPARE(tester->repaints, 8);
7342     QCOMPARE(testerChild->repaints, 7);
7343     QCOMPARE(testerChild2->repaints, 5);
7344
7345     // Scaling the view back should cause repaints for two of the items.
7346     view.setTransform(QTransform());
7347     QTest::qWait(25);
7348     QTRY_COMPARE(tester->repaints, 9);
7349     QCOMPARE(testerChild->repaints, 8);
7350     QCOMPARE(testerChild2->repaints, 5);
7351
7352     // Rotating the base item (perspective) should repaint two items.
7353     tester->setTransform(QTransform().rotate(10, Qt::XAxis));
7354     QTest::qWait(25);
7355     QTRY_COMPARE(tester->repaints, 10);
7356     QCOMPARE(testerChild->repaints, 9);
7357     QCOMPARE(testerChild2->repaints, 5);
7358
7359     // Moving the middle item should case a repaint even if it's a move,
7360     // because the parent is rotated with a perspective.
7361     testerChild->setPos(1, 1);
7362     QTest::qWait(25);
7363     QTRY_COMPARE(tester->repaints, 11);
7364     QTRY_COMPARE(testerChild->repaints, 10);
7365     QTRY_COMPARE(testerChild2->repaints, 5);
7366     tester->resetTransform();
7367
7368     // Make a huge item
7369     tester->setGeometry(QRectF(-4000, -4000, 8000, 8000));
7370     QTRY_COMPARE(tester->repaints, 12);
7371     QTRY_COMPARE(testerChild->repaints, 11);
7372     QTRY_COMPARE(testerChild2->repaints, 5);
7373
7374     // Move the large item - will cause a repaint as the
7375     // cache is clipped.
7376     tester->setPos(5, 0);
7377     QTRY_COMPARE(tester->repaints, 13);
7378     QTRY_COMPARE(testerChild->repaints, 11);
7379     QTRY_COMPARE(testerChild2->repaints, 5);
7380
7381     // Hiding and showing should invalidate the cache
7382     tester->hide();
7383     QTest::qWait(25);
7384     tester->show();
7385     QTRY_COMPARE(tester->repaints, 14);
7386     QTRY_COMPARE(testerChild->repaints, 12);
7387     QTRY_COMPARE(testerChild2->repaints, 6);
7388 }
7389
7390 void tst_QGraphicsItem::cacheMode2()
7391 {
7392     QGraphicsScene scene(0, 0, 100, 100);
7393     QGraphicsView view(&scene);
7394     view.resize(150, 150);
7395     view.show();
7396     QApplication::setActiveWindow(&view);
7397     QVERIFY(QTest::qWaitForWindowActive(&view));
7398
7399     // Increase the probability of window activation
7400     // not causing another repaint of test items.
7401     QTest::qWait(50);
7402
7403     EventTester *tester = new EventTester;
7404     scene.addItem(tester);
7405     QTest::qWait(10);
7406     QTRY_COMPARE(tester->repaints, 1);
7407
7408     // Switching from NoCache to NoCache (no repaint)
7409     tester->setCacheMode(QGraphicsItem::NoCache);
7410     QTest::qWait(50);
7411     QTRY_COMPARE(tester->repaints, 1);
7412
7413     // Switching from NoCache to DeviceCoordinateCache (no repaint)
7414     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7415     QTest::qWait(50);
7416     QTRY_COMPARE(tester->repaints, 1);
7417
7418     // Switching from DeviceCoordinateCache to DeviceCoordinateCache (no repaint)
7419     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7420     QTest::qWait(50);
7421     QTRY_COMPARE(tester->repaints, 1);
7422
7423     // Switching from DeviceCoordinateCache to NoCache (no repaint)
7424     tester->setCacheMode(QGraphicsItem::NoCache);
7425     QTest::qWait(50);
7426     QTRY_COMPARE(tester->repaints, 1);
7427
7428     // Switching from NoCache to ItemCoordinateCache (repaint)
7429     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7430     QTest::qWait(50);
7431     QTRY_COMPARE(tester->repaints, 2);
7432
7433     // Switching from ItemCoordinateCache to ItemCoordinateCache (no repaint)
7434     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7435     QTest::qWait(50);
7436     QTRY_COMPARE(tester->repaints, 2);
7437
7438     // Switching from ItemCoordinateCache to ItemCoordinateCache with different size (repaint)
7439     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(100, 100));
7440     QTest::qWait(50);
7441     QTRY_COMPARE(tester->repaints, 3);
7442
7443     // Switching from ItemCoordinateCache to NoCache (repaint)
7444     tester->setCacheMode(QGraphicsItem::NoCache);
7445     QTest::qWait(50);
7446     QTRY_COMPARE(tester->repaints, 4);
7447
7448     // Switching from DeviceCoordinateCache to ItemCoordinateCache (repaint)
7449     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7450     QTest::qWait(50);
7451     QTRY_COMPARE(tester->repaints, 4);
7452     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7453     QTest::qWait(50);
7454     QTRY_COMPARE(tester->repaints, 5);
7455
7456     // Switching from ItemCoordinateCache to DeviceCoordinateCache (repaint)
7457     tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
7458     QTest::qWait(50);
7459     QTRY_COMPARE(tester->repaints, 6);
7460 }
7461
7462 void tst_QGraphicsItem::updateCachedItemAfterMove()
7463 {
7464     // A simple item that uses ItemCoordinateCache
7465     EventTester *tester = new EventTester;
7466     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
7467
7468     // Add to a scene, show in a view, ensure it's painted and reset its
7469     // repaint counter.
7470     QGraphicsScene scene;
7471     scene.addItem(tester);
7472     QGraphicsView view(&scene);
7473     view.show();
7474     QVERIFY(QTest::qWaitForWindowExposed(&view));
7475
7476     QTest::qWait(12);
7477     QTRY_VERIFY(tester->repaints > 0);
7478     tester->repaints = 0;
7479
7480     // Move the item, should not cause repaints
7481     tester->setPos(10, 0);
7482     QTest::qWait(12);
7483     QCOMPARE(tester->repaints, 0);
7484
7485     // Move then update, should cause one repaint
7486     tester->setPos(20, 0);
7487     tester->update();
7488     QTest::qWait(12);
7489     QCOMPARE(tester->repaints, 1);
7490
7491     // Hiding the item doesn't cause a repaint
7492     tester->hide();
7493     QTest::qWait(12);
7494     QCOMPARE(tester->repaints, 1);
7495
7496     // Moving a hidden item doesn't cause a repaint
7497     tester->setPos(30, 0);
7498     tester->update();
7499     QTest::qWait(12);
7500     QCOMPARE(tester->repaints, 1);
7501 }
7502
7503 class Track : public QGraphicsRectItem
7504 {
7505 public:
7506     Track(const QRectF &rect)
7507         : QGraphicsRectItem(rect)
7508     {
7509         setAcceptHoverEvents(true);
7510     }
7511
7512     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7513     {
7514         QGraphicsRectItem::paint(painter, option, widget);
7515         painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1x%2\n%3x%4").arg(p.x()).arg(p.y()).arg(sp.x()).arg(sp.y()));
7516     }
7517
7518 protected:
7519     void hoverMoveEvent(QGraphicsSceneHoverEvent *event)
7520     {
7521         p = event->pos();
7522         sp = event->widget()->mapFromGlobal(event->screenPos());
7523         update();
7524     }
7525 private:
7526     QPointF p;
7527     QPoint sp;
7528 };
7529
7530 void tst_QGraphicsItem::deviceTransform_data()
7531 {
7532     QTest::addColumn<bool>("untransformable1");
7533     QTest::addColumn<bool>("untransformable2");
7534     QTest::addColumn<bool>("untransformable3");
7535     QTest::addColumn<qreal>("rotation1");
7536     QTest::addColumn<qreal>("rotation2");
7537     QTest::addColumn<qreal>("rotation3");
7538     QTest::addColumn<QTransform>("deviceX");
7539     QTest::addColumn<QPointF>("mapResult1");
7540     QTest::addColumn<QPointF>("mapResult2");
7541     QTest::addColumn<QPointF>("mapResult3");
7542
7543     QTest::newRow("nil") << false << false << false
7544                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7545                          << QTransform()
7546                          << QPointF(150, 150) << QPointF(250, 250) << QPointF(350, 350);
7547     QTest::newRow("deviceX rot 90") << false << false << false
7548                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7549                          << QTransform().rotate(90)
7550                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-350, 350);
7551     QTest::newRow("deviceX rot 90 100") << true << false << false
7552                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7553                          << QTransform().rotate(90)
7554                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7555     QTest::newRow("deviceX rot 90 010") << false << true << false
7556                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7557                          << QTransform().rotate(90)
7558                          << QPointF(-150, 150) << QPointF(-150, 250) << QPointF(-50, 350);
7559     QTest::newRow("deviceX rot 90 001") << false << false << true
7560                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7561                          << QTransform().rotate(90)
7562                          << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-250, 350);
7563     QTest::newRow("deviceX rot 90 111") << true << true << true
7564                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7565                          << QTransform().rotate(90)
7566                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7567     QTest::newRow("deviceX rot 90 101") << true << false << true
7568                          << qreal(0.0) << qreal(0.0) << qreal(0.0)
7569                          << QTransform().rotate(90)
7570                          << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350);
7571 }
7572
7573 void tst_QGraphicsItem::deviceTransform()
7574 {
7575     QFETCH(bool, untransformable1);
7576     QFETCH(bool, untransformable2);
7577     QFETCH(bool, untransformable3);
7578     QFETCH(qreal, rotation1);
7579     QFETCH(qreal, rotation2);
7580     QFETCH(qreal, rotation3);
7581     QFETCH(QTransform, deviceX);
7582     QFETCH(QPointF, mapResult1);
7583     QFETCH(QPointF, mapResult2);
7584     QFETCH(QPointF, mapResult3);
7585
7586     QGraphicsScene scene;
7587     Track *rect1 = new Track(QRectF(0, 0, 100, 100));
7588     Track *rect2 = new Track(QRectF(0, 0, 100, 100));
7589     Track *rect3 = new Track(QRectF(0, 0, 100, 100));
7590     rect2->setParentItem(rect1);
7591     rect3->setParentItem(rect2);
7592     rect1->setPos(100, 100);
7593     rect2->setPos(100, 100);
7594     rect3->setPos(100, 100);
7595     rect1->rotate(rotation1);
7596     rect2->rotate(rotation2);
7597     rect3->rotate(rotation3);
7598     rect1->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable1);
7599     rect2->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable2);
7600     rect3->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable3);
7601     rect1->setBrush(Qt::red);
7602     rect2->setBrush(Qt::green);
7603     rect3->setBrush(Qt::blue);
7604     scene.addItem(rect1);
7605
7606     QCOMPARE(rect1->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult1);
7607     QCOMPARE(rect2->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult2);
7608     QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3);
7609 }
7610
7611 void tst_QGraphicsItem::update()
7612 {
7613     QGraphicsScene scene;
7614     scene.setSceneRect(-100, -100, 200, 200);
7615     QWidget topLevel;
7616     MyGraphicsView view(&scene,&topLevel);
7617
7618     topLevel.resize(300, 300);
7619     topLevel.show();
7620     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
7621
7622     EventTester *item = new EventTester;
7623     scene.addItem(item);
7624     QTest::qWait(100); // Make sure all pending updates are processed.
7625     item->repaints = 0;
7626
7627     item->update(); // Item marked as dirty
7628     scene.update(); // Entire scene marked as dirty
7629     qApp->processEvents();
7630     QCOMPARE(item->repaints, 1);
7631
7632     // Make sure the dirty state from the previous update is reset so that
7633     // the item don't think it is already dirty and discards this update.
7634     item->update();
7635     qApp->processEvents();
7636     QCOMPARE(item->repaints, 2);
7637
7638     // Make sure a partial update doesn't cause a full update to be discarded.
7639     view.reset();
7640     item->repaints = 0;
7641     item->update(QRectF(0, 0, 5, 5));
7642     item->update();
7643     qApp->processEvents();
7644     QCOMPARE(item->repaints, 1);
7645     QCOMPARE(view.repaints, 1);
7646     QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7647                                                          .mapRect(item->boundingRect()).toAlignedRect();
7648     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7649     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7650     QCOMPARE(view.paintedRegion, expectedRegion);
7651
7652     // Make sure update requests outside the bounding rect are discarded.
7653     view.reset();
7654     item->repaints = 0;
7655     item->update(-15, -15, 5, 5); // Item's brect: (-10, -10, 20, 20)
7656     qApp->processEvents();
7657     QCOMPARE(item->repaints, 0);
7658     QCOMPARE(view.repaints, 0);
7659
7660     // Make sure the area occupied by an item is repainted when hiding it.
7661     view.reset();
7662     item->repaints = 0;
7663     item->update(); // Full update; all sub-sequent update requests are discarded.
7664     item->hide(); // visible set to 0. ignoreVisible must be set to 1; the item won't be processed otherwise.
7665     qApp->processEvents();
7666     QCOMPARE(item->repaints, 0);
7667     QCOMPARE(view.repaints, 1);
7668     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7669     QCOMPARE(view.paintedRegion, expectedRegion);
7670
7671     // Make sure item is repainted when shown (after being hidden).
7672     view.reset();
7673     item->repaints = 0;
7674     item->show();
7675     qApp->processEvents();
7676     QCOMPARE(item->repaints, 1);
7677     QCOMPARE(view.repaints, 1);
7678     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7679     QCOMPARE(view.paintedRegion, expectedRegion);
7680
7681     item->repaints = 0;
7682     item->hide();
7683     qApp->processEvents();
7684     view.reset();
7685     const QPointF originalPos = item->pos();
7686     item->setPos(5000, 5000);
7687     qApp->processEvents();
7688     QCOMPARE(item->repaints, 0);
7689     QCOMPARE(view.repaints, 0);
7690     qApp->processEvents();
7691
7692     item->setPos(originalPos);
7693     qApp->processEvents();
7694     QCOMPARE(item->repaints, 0);
7695     QCOMPARE(view.repaints, 0);
7696     item->show();
7697     qApp->processEvents();
7698     QCOMPARE(item->repaints, 1);
7699     QCOMPARE(view.repaints, 1);
7700     // The entire item's bounding rect (adjusted for antialiasing) should have been painted.
7701     QCOMPARE(view.paintedRegion, expectedRegion);
7702
7703     QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
7704     item->setPos(originalPos + QPoint(50, 50));
7705     viewPrivate->updateAll();
7706     QVERIFY(viewPrivate->fullUpdatePending);
7707     QTest::qWait(50);
7708     item->repaints = 0;
7709     view.reset();
7710     item->setPos(originalPos);
7711     QTest::qWait(50);
7712     qApp->processEvents();
7713     QCOMPARE(item->repaints, 1);
7714     QCOMPARE(view.repaints, 1);
7715     COMPARE_REGIONS(view.paintedRegion, expectedRegion + expectedRegion.translated(50, 50));
7716
7717     // Make sure moving a parent item triggers an update on the children
7718     // (even though the parent itself is outside the viewport).
7719     QGraphicsRectItem *parent = new QGraphicsRectItem(0, 0, 10, 10);
7720     parent->setPos(-400, 0);
7721     item->setParentItem(parent);
7722     item->setPos(400, 0);
7723     scene.addItem(parent);
7724     QTest::qWait(50);
7725     itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
7726                                                    .mapRect(item->boundingRect()).toAlignedRect();
7727     expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
7728     view.reset();
7729     item->repaints = 0;
7730     parent->translate(-400, 0);
7731     qApp->processEvents();
7732     QCOMPARE(item->repaints, 0);
7733     QCOMPARE(view.repaints, 1);
7734     QCOMPARE(view.paintedRegion, expectedRegion);
7735     view.reset();
7736     item->repaints = 0;
7737     parent->translate(400, 0);
7738     qApp->processEvents();
7739     QCOMPARE(item->repaints, 1);
7740     QCOMPARE(view.repaints, 1);
7741     QCOMPARE(view.paintedRegion, expectedRegion);
7742     QCOMPARE(view.paintedRegion, expectedRegion);
7743 }
7744
7745 void tst_QGraphicsItem::setTransformProperties_data()
7746 {
7747     QTest::addColumn<QPointF>("origin");
7748     QTest::addColumn<qreal>("rotation");
7749     QTest::addColumn<qreal>("scale");
7750
7751     QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(1.0);
7752
7753     QTest::newRow("rotation") << QPointF() << qreal(42.2) << qreal(1.0);
7754
7755     QTest::newRow("rotation dicentred") << QPointF(qreal(22.3), qreal(-56.2))
7756                                 << qreal(-2578.2)
7757                                 << qreal(1.0);
7758
7759     QTest::newRow("Scale")    << QPointF() << qreal(0.0)
7760                                           << qreal(6);
7761
7762     QTest::newRow("Everything dicentred")  << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196);
7763 }
7764
7765 /**
7766  * the normal QCOMPARE doesn't work because it doesn't use qFuzzyCompare
7767  */
7768 #define QCOMPARE_TRANSFORM(X1, X2)   QVERIFY(((X1)*(X2).inverted()).isIdentity())
7769
7770 void tst_QGraphicsItem::setTransformProperties()
7771 {
7772     QFETCH(QPointF,origin);
7773     QFETCH(qreal,rotation);
7774     QFETCH(qreal,scale);
7775
7776     QTransform result;
7777     result.translate(origin.x(), origin.y());
7778     result.rotate(rotation, Qt::ZAxis);
7779     result.scale(scale, scale);
7780     result.translate(-origin.x(), -origin.y());
7781
7782     QGraphicsScene scene;
7783     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
7784     scene.addItem(item);
7785
7786     item->setRotation(rotation);
7787     item->setScale(scale);
7788     item->setTransformOriginPoint(origin);
7789
7790     QCOMPARE(item->rotation(), rotation);
7791     QCOMPARE(item->scale(), scale);
7792     QCOMPARE(item->transformOriginPoint(), origin);
7793
7794     QCOMPARE(QTransform(), item->transform());
7795     QCOMPARE(result, item->sceneTransform());
7796
7797     //-----------------------------------------------------------------
7798     //Change the rotation Z
7799     item->setRotation(45);
7800     QTransform result2;
7801     result2.translate(origin.x(), origin.y());
7802     result2.rotate(45);
7803     result2.scale(scale, scale);
7804     result2.translate(-origin.x(), -origin.y());
7805
7806     QCOMPARE(item->rotation(), 45.);
7807     QCOMPARE(item->scale(), scale);
7808     QCOMPARE(item->transformOriginPoint(), origin);
7809
7810     QCOMPARE(QTransform(), item->transform());
7811     QCOMPARE(result2, item->sceneTransform());
7812
7813     //-----------------------------------------------------------------
7814     // calling setTransform() and setPos should change the sceneTransform
7815     item->setTransform(result);
7816     item->setPos(100, -150.5);
7817
7818     QCOMPARE(item->rotation(), 45.);
7819     QCOMPARE(item->scale(), scale);
7820     QCOMPARE(item->transformOriginPoint(), origin);
7821     QCOMPARE(result, item->transform());
7822
7823     QTransform result3(result);
7824
7825     result3.translate(origin.x(), origin.y());
7826     result3.rotate(45);
7827     result3.scale(scale, scale);
7828     result3.translate(-origin.x(), -origin.y());
7829
7830     result3 *= QTransform::fromTranslate(100, -150.5); //the pos;
7831
7832     QCOMPARE(result3, item->sceneTransform());
7833
7834     //-----------------------------------------------------
7835     // setting the propertiees should be the same as setting a transform
7836     {//with center origin on the matrix
7837         QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7838         scene.addItem(item1);
7839         QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119));
7840         scene.addItem(item2);
7841
7842         item1->setPos(12.3, -5);
7843         item2->setPos(12.3, -5);
7844         item1->setRotation(rotation);
7845         item1->setScale(scale);
7846         item1->setTransformOriginPoint(origin);
7847
7848         item2->setTransform(result);
7849
7850         QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform());
7851
7852         QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform());
7853         QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform());
7854     }
7855 }
7856
7857 class MyStyleOptionTester : public QGraphicsRectItem
7858 {
7859 public:
7860     MyStyleOptionTester(const QRectF &rect)
7861         : QGraphicsRectItem(rect), startTrack(false)
7862     {}
7863
7864     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
7865     {
7866         if (startTrack) {
7867             //Doesn't use the extended style option so the exposed rect is the boundingRect
7868             if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) {
7869                 QCOMPARE(option->exposedRect, boundingRect());
7870                 QCOMPARE(option->matrix, QMatrix());
7871             } else {
7872                 QVERIFY(option->exposedRect != QRect());
7873                 QVERIFY(option->exposedRect != boundingRect());
7874                 QCOMPARE(option->matrix, sceneTransform().toAffine());
7875             }
7876         }
7877         QGraphicsRectItem::paint(painter, option, widget);
7878     }
7879     bool startTrack;
7880 };
7881
7882 void tst_QGraphicsItem::itemUsesExtendedStyleOption()
7883 {
7884     QGraphicsScene scene(0, 0, 300, 300);
7885     QGraphicsPixmapItem item;
7886     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7887     QCOMPARE(item.flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption));
7888     item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
7889     QCOMPARE(item.flags(), 0);
7890
7891     //We now test the content of the style option
7892     MyStyleOptionTester *rect = new MyStyleOptionTester(QRect(0, 0, 100, 100));
7893     scene.addItem(rect);
7894     rect->setPos(200, 200);
7895     QWidget topLevel;
7896     QGraphicsView view(&scene, &topLevel);
7897     topLevel.setWindowFlags(Qt::X11BypassWindowManagerHint);
7898     rect->startTrack = false;
7899     topLevel.show();
7900     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
7901     QTest::qWait(60);
7902     rect->startTrack = true;
7903     rect->update(10, 10, 10, 10);
7904     QTest::qWait(60);
7905     rect->startTrack = false;
7906     rect->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
7907     QVERIFY((rect->flags() & QGraphicsItem::ItemUsesExtendedStyleOption));
7908     QTest::qWait(60);
7909     rect->startTrack = true;
7910     rect->update(10, 10, 10, 10);
7911     QTest::qWait(60);
7912 }
7913
7914 void tst_QGraphicsItem::itemSendsGeometryChanges()
7915 {
7916     ItemChangeTester item;
7917     item.setFlags(0);
7918     item.clear();
7919
7920     QTransform x = QTransform().rotate(45);
7921     QPointF pos(10, 10);
7922     qreal o(0.5);
7923     qreal r(10.0);
7924     qreal s(1.5);
7925     QPointF origin(1.0, 1.0);
7926     item.setTransform(x);
7927     item.setPos(pos);
7928     item.setRotation(r);
7929     item.setScale(s);
7930     item.setTransformOriginPoint(origin);
7931     QCOMPARE(item.transform(), x);
7932     QCOMPARE(item.pos(), pos);
7933     QCOMPARE(item.rotation(), r);
7934     QCOMPARE(item.scale(), s);
7935     QCOMPARE(item.transformOriginPoint(), origin);
7936     QCOMPARE(item.changes.size(), 0);
7937
7938     item.setOpacity(o);
7939     QCOMPARE(item.changes.size(), 2); // opacity
7940
7941     item.setFlag(QGraphicsItem::ItemSendsGeometryChanges);
7942     QCOMPARE(item.changes.size(), 4); // flags
7943     item.setTransform(QTransform());
7944     item.setPos(QPointF());
7945     QCOMPARE(item.changes.size(), 8); // transform + pos
7946     QCOMPARE(item.transform(), QTransform());
7947     QCOMPARE(item.pos(), QPointF());
7948     QCOMPARE(item.opacity(), o);
7949     item.setRotation(0.0);
7950     item.setScale(1.0);
7951     item.setTransformOriginPoint(0.0, 0.0);
7952     QCOMPARE(item.changes.size(), 14); // rotation + scale + origin
7953     QCOMPARE(item.rotation(), qreal(0.0));
7954     QCOMPARE(item.scale(), qreal(1.0));
7955     QCOMPARE(item.transformOriginPoint(), QPointF(0.0, 0.0));
7956
7957     QCOMPARE(item.changes, QList<QGraphicsItem::GraphicsItemChange>()
7958              << QGraphicsItem::ItemOpacityChange
7959              << QGraphicsItem::ItemOpacityHasChanged
7960              << QGraphicsItem::ItemFlagsChange
7961              << QGraphicsItem::ItemFlagsHaveChanged
7962              << QGraphicsItem::ItemTransformChange
7963              << QGraphicsItem::ItemTransformHasChanged
7964              << QGraphicsItem::ItemPositionChange
7965              << QGraphicsItem::ItemPositionHasChanged
7966              << QGraphicsItem::ItemRotationChange
7967              << QGraphicsItem::ItemRotationHasChanged
7968              << QGraphicsItem::ItemScaleChange
7969              << QGraphicsItem::ItemScaleHasChanged
7970              << QGraphicsItem::ItemTransformOriginPointChange
7971              << QGraphicsItem::ItemTransformOriginPointHasChanged);
7972 }
7973
7974 // Make sure we update moved items correctly.
7975 void tst_QGraphicsItem::moveItem()
7976 {
7977     QGraphicsScene scene;
7978     scene.setSceneRect(-50, -50, 200, 200);
7979
7980     MyGraphicsView view(&scene);
7981     view.show();
7982     QVERIFY(QTest::qWaitForWindowExposed(&view));
7983
7984     EventTester *parent = new EventTester;
7985     EventTester *child = new EventTester(parent);
7986     EventTester *grandChild = new EventTester(child);
7987
7988 #define RESET_COUNTERS \
7989     parent->repaints = 0; \
7990     child->repaints = 0; \
7991     grandChild->repaints = 0; \
7992     view.reset();
7993
7994     scene.addItem(parent);
7995     QTest::qWait(100);
7996
7997     RESET_COUNTERS
7998
7999     // Item's boundingRect:  (-10, -10, 20, 20).
8000     QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
8001                                      .mapRect(parent->boundingRect()).toAlignedRect()
8002                                      .adjusted(-2, -2, 2, 2); // Adjusted for antialiasing.
8003
8004     parent->setPos(20, 20);
8005     qApp->processEvents();
8006     QCOMPARE(parent->repaints, 1);
8007     QCOMPARE(view.repaints, 1);
8008     QRegion expectedParentRegion = parentDeviceBoundingRect; // old position
8009     parentDeviceBoundingRect.translate(20, 20);
8010     expectedParentRegion += parentDeviceBoundingRect; // new position
8011     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
8012
8013     RESET_COUNTERS
8014
8015     child->setPos(20, 20);
8016     qApp->processEvents();
8017     QCOMPARE(parent->repaints, 1);
8018     QCOMPARE(child->repaints, 1);
8019     QCOMPARE(view.repaints, 1);
8020     const QRegion expectedChildRegion = expectedParentRegion.translated(20, 20);
8021     COMPARE_REGIONS(view.paintedRegion, expectedChildRegion);
8022
8023     RESET_COUNTERS
8024
8025     grandChild->setPos(20, 20);
8026     qApp->processEvents();
8027     QCOMPARE(parent->repaints, 1);
8028     QCOMPARE(child->repaints, 1);
8029     QCOMPARE(grandChild->repaints, 1);
8030     QCOMPARE(view.repaints, 1);
8031     const QRegion expectedGrandChildRegion = expectedParentRegion.translated(40, 40);
8032     COMPARE_REGIONS(view.paintedRegion, expectedGrandChildRegion);
8033
8034     RESET_COUNTERS
8035
8036     parent->translate(20, 20);
8037     qApp->processEvents();
8038     QCOMPARE(parent->repaints, 1);
8039     QCOMPARE(child->repaints, 1);
8040     QCOMPARE(grandChild->repaints, 1);
8041     QCOMPARE(view.repaints, 1);
8042     expectedParentRegion.translate(20, 20);
8043     expectedParentRegion += expectedChildRegion.translated(20, 20);
8044     expectedParentRegion += expectedGrandChildRegion.translated(20, 20);
8045     COMPARE_REGIONS(view.paintedRegion, expectedParentRegion);
8046 }
8047
8048 void tst_QGraphicsItem::moveLineItem()
8049 {
8050     QGraphicsScene scene;
8051     scene.setSceneRect(0, 0, 200, 200);
8052     QGraphicsLineItem *item = new QGraphicsLineItem(0, 0, 100, 0);
8053     item->setPos(50, 50);
8054     scene.addItem(item);
8055
8056     MyGraphicsView view(&scene);
8057     view.show();
8058     QVERIFY(QTest::qWaitForWindowActive(&view));
8059     view.reset();
8060
8061     QRectF brect = item->boundingRect();
8062     // Do same adjustments as in qgraphicsscene.cpp
8063     if (!brect.width())
8064         brect.adjust(qreal(-0.00001), 0, qreal(0.00001), 0);
8065     if (!brect.height())
8066         brect.adjust(0, qreal(-0.00001), 0, qreal(0.00001));
8067     const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
8068                                          .mapRect(brect).toAlignedRect();
8069     QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // antialiasing
8070
8071     // Make sure the calculated region is correct.
8072     item->update();
8073     QTest::qWait(10);
8074     QTRY_COMPARE(view.paintedRegion, expectedRegion);
8075     view.reset();
8076
8077     // Old position: (50, 50)
8078     item->setPos(50, 100);
8079     expectedRegion += expectedRegion.translated(0, 50);
8080     QTest::qWait(10);
8081     QCOMPARE(view.paintedRegion, expectedRegion);
8082 }
8083
8084 void tst_QGraphicsItem::sorting_data()
8085 {
8086     QTest::addColumn<int>("index");
8087
8088     QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex);
8089     QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex);
8090 }
8091
8092 void tst_QGraphicsItem::sorting()
8093 {
8094     if (qGuiApp->styleHints()->showIsFullScreen())
8095         QSKIP("Skipped because Platform is auto maximizing");
8096
8097     _paintedItems.clear();
8098
8099     QGraphicsScene scene;
8100     QGraphicsItem *grid[100][100];
8101     for (int x = 0; x < 100; ++x) {
8102         for (int y = 0; y < 100; ++y) {
8103             PainterItem *item = new PainterItem;
8104             item->setPos(x * 25, y * 25);
8105             item->setData(0, QString("%1x%2").arg(x).arg(y));
8106             grid[x][y] = item;
8107             scene.addItem(item);
8108         }
8109     }
8110
8111     PainterItem *item1 = new PainterItem;
8112     PainterItem *item2 = new PainterItem;
8113     item1->setData(0, "item1");
8114     item2->setData(0, "item2");
8115     scene.addItem(item1);
8116     scene.addItem(item2);
8117
8118     QGraphicsView view(&scene);
8119     // Use Qt::Tool as fully decorated windows have a minimum width of 160 on Windows.
8120     view.setWindowFlags(view.windowFlags() | Qt::Tool);
8121     view.setResizeAnchor(QGraphicsView::NoAnchor);
8122     view.setTransformationAnchor(QGraphicsView::NoAnchor);
8123     view.resize(120, 100);
8124     view.setFrameStyle(0);
8125     view.show();
8126     qApp->setActiveWindow(&view);
8127     QVERIFY(QTest::qWaitForWindowActive(&view));
8128     QTest::qWait(100);
8129
8130     _paintedItems.clear();
8131
8132     view.viewport()->repaint();
8133 #if defined(Q_OS_MAC)
8134     // There's no difference between repaint and update on the Mac,
8135     // so we have to process events here to make sure we get the event.
8136     QTest::qWait(100);
8137 #endif
8138
8139     QCOMPARE(_paintedItems, QList<QGraphicsItem *>()
8140                  << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3]
8141                  << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3]
8142                  << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3]
8143                  << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3]
8144                  << grid[4][0] << grid[4][1] << grid[4][2] << grid[4][3]
8145                  << item1 << item2);
8146 }
8147
8148 void tst_QGraphicsItem::itemHasNoContents()
8149 {
8150     PainterItem *item1 = new PainterItem;
8151     PainterItem *item2 = new PainterItem;
8152     item2->setParentItem(item1);
8153     item2->setPos(50, 50);
8154     item1->setFlag(QGraphicsItem::ItemHasNoContents);
8155     item1->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
8156
8157     QGraphicsScene scene;
8158     scene.addItem(item1);
8159
8160     QGraphicsView view(&scene);
8161     view.show();
8162     qApp->setActiveWindow(&view);
8163     QVERIFY(QTest::qWaitForWindowActive(&view));
8164     QTRY_VERIFY(!_paintedItems.isEmpty());
8165
8166     _paintedItems.clear();
8167
8168     view.viewport()->repaint();
8169 #ifdef Q_OS_MAC
8170     // There's no difference between update() and repaint() on the Mac,
8171     // so we have to process events here to make sure we get the event.
8172     QTest::qWait(10);
8173 #endif
8174
8175     QTRY_COMPARE(_paintedItems, QList<QGraphicsItem *>() << item2);
8176 }
8177
8178 void tst_QGraphicsItem::hitTestUntransformableItem()
8179 {
8180     QGraphicsScene scene;
8181     scene.setSceneRect(-100, -100, 200, 200);
8182
8183     QGraphicsView view(&scene);
8184     view.show();
8185     QVERIFY(QTest::qWaitForWindowExposed(&view));
8186
8187     // Confuse the BSP with dummy items.
8188     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8189     dummy->setPos(-100, -100);
8190     scene.addItem(dummy);
8191     for (int i = 0; i < 100; ++i) {
8192         QGraphicsItem *parent = dummy;
8193         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8194         dummy->setPos(-100 + i, -100 + i);
8195         dummy->setParentItem(parent);
8196     }
8197
8198     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
8199     item1->setPos(-200, -200);
8200
8201     QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 20, 20);
8202     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8203     item2->setParentItem(item1);
8204     item2->setPos(200, 200);
8205
8206     QGraphicsRectItem *item3 = new QGraphicsRectItem(0, 0, 20, 20);
8207     item3->setParentItem(item2);
8208     item3->setPos(80, 80);
8209
8210     scene.addItem(item1);
8211     QTest::qWait(100);
8212
8213     QList<QGraphicsItem *> items = scene.items(QPointF(80, 80));
8214     QCOMPARE(items.size(), 1);
8215     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8216
8217     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8218     QTest::qWait(100);
8219
8220     items = scene.items(QPointF(80, 80));
8221     QCOMPARE(items.size(), 1);
8222     QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3));
8223 }
8224
8225 void tst_QGraphicsItem::hitTestGraphicsEffectItem()
8226 {
8227     QGraphicsScene scene;
8228     scene.setSceneRect(-100, -100, 200, 200);
8229
8230     QWidget toplevel;
8231
8232     QGraphicsView view(&scene, &toplevel);
8233     toplevel.resize(300, 300);
8234     toplevel.show();
8235     QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
8236
8237     // Confuse the BSP with dummy items.
8238     QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20);
8239     dummy->setPos(-100, -100);
8240     scene.addItem(dummy);
8241     for (int i = 0; i < 100; ++i) {
8242         QGraphicsItem *parent = dummy;
8243         dummy = new QGraphicsRectItem(0, 0, 20, 20);
8244         dummy->setPos(-100 + i, -100 + i);
8245         dummy->setParentItem(parent);
8246     }
8247
8248     const QRectF itemBoundingRect(0, 0, 20, 20);
8249     EventTester *item1 = new EventTester;
8250     item1->br = itemBoundingRect;
8251     item1->setPos(-200, -200);
8252     item1->brush = Qt::red;
8253
8254     EventTester *item2 = new EventTester;
8255     item2->br = itemBoundingRect;
8256     item2->setFlag(QGraphicsItem::ItemIgnoresTransformations);
8257     item2->setParentItem(item1);
8258     item2->setPos(200, 200);
8259     item2->brush = Qt::green;
8260
8261     EventTester *item3 = new EventTester;
8262     item3->br = itemBoundingRect;
8263     item3->setParentItem(item2);
8264     item3->setPos(80, 80);
8265     item3->brush = Qt::blue;
8266
8267     scene.addItem(item1);
8268     QTest::qWait(100);
8269
8270     item1->repaints = 0;
8271     item2->repaints = 0;
8272     item3->repaints = 0;
8273
8274     // Apply shadow effect to the entire sub-tree.
8275     QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
8276     shadow->setOffset(-20, -20);
8277     item1->setGraphicsEffect(shadow);
8278     QTest::qWait(50);
8279
8280     // Make sure all visible items are repainted.
8281     QCOMPARE(item1->repaints, 1);
8282     QCOMPARE(item2->repaints, 1);
8283     QCOMPARE(item3->repaints, 1);
8284
8285     // Make sure an item doesn't respond to a click on its shadow.
8286     QList<QGraphicsItem *> items = scene.items(QPointF(75, 75));
8287     QVERIFY(items.isEmpty());
8288     items = scene.items(QPointF(80, 80));
8289     QCOMPARE(items.size(), 1);
8290     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8291
8292     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
8293     QTest::qWait(100);
8294
8295     items = scene.items(QPointF(75, 75));
8296     QVERIFY(items.isEmpty());
8297     items = scene.items(QPointF(80, 80));
8298     QCOMPARE(items.size(), 1);
8299     QCOMPARE(items.at(0), static_cast<QGraphicsItem *>(item3));
8300 }
8301
8302 void tst_QGraphicsItem::focusProxy()
8303 {
8304     QGraphicsScene scene;
8305     QEvent activate(QEvent::WindowActivate);
8306     QApplication::sendEvent(&scene, &activate);
8307
8308     QGraphicsItem *item = scene.addRect(0, 0, 10, 10);
8309     item->setFlag(QGraphicsItem::ItemIsFocusable);
8310     QVERIFY(!item->focusProxy());
8311
8312     QGraphicsItem *item2 = scene.addRect(0, 0, 10, 10);
8313     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8314     item->setFocusProxy(item2);
8315     QCOMPARE(item->focusProxy(), item2);
8316
8317     item->setFocus();
8318     QVERIFY(item->hasFocus());
8319     QVERIFY(item2->hasFocus());
8320
8321     // Try to make a focus chain loop
8322     QString err;
8323     QTextStream stream(&err);
8324     stream << "QGraphicsItem::setFocusProxy: "
8325            << (void*)item << " is already in the focus proxy chain" << flush;
8326     QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
8327     item2->setFocusProxy(item); // fails
8328     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8329     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8330
8331     // Try to assign self as focus proxy
8332     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
8333     item->setFocusProxy(item); // fails
8334     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8335     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8336
8337     // Reset the focus proxy
8338     item->setFocusProxy(0);
8339     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8340     QVERIFY(!item->hasFocus());
8341     QVERIFY(item2->hasFocus());
8342
8343     // Test deletion
8344     item->setFocusProxy(item2);
8345     QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2);
8346     delete item2;
8347     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8348
8349     // Test event delivery
8350     item2 = scene.addRect(0, 0, 10, 10);
8351     item2->setFlag(QGraphicsItem::ItemIsFocusable);
8352     item->setFocusProxy(item2);
8353     item->clearFocus();
8354
8355     EventSpy focusInSpy(&scene, item, QEvent::FocusIn);
8356     EventSpy focusOutSpy(&scene, item, QEvent::FocusOut);
8357     EventSpy focusInSpy2(&scene, item2, QEvent::FocusIn);
8358     EventSpy focusOutSpy2(&scene, item2, QEvent::FocusOut);
8359     QCOMPARE(focusInSpy.count(), 0);
8360     QCOMPARE(focusOutSpy.count(), 0);
8361     QCOMPARE(focusInSpy2.count(), 0);
8362     QCOMPARE(focusOutSpy2.count(), 0);
8363
8364     item->setFocus();
8365     QCOMPARE(focusInSpy.count(), 0);
8366     QCOMPARE(focusInSpy2.count(), 1);
8367     item->clearFocus();
8368     QCOMPARE(focusOutSpy.count(), 0);
8369     QCOMPARE(focusOutSpy2.count(), 1);
8370
8371     // Test two items proxying one item.
8372     QGraphicsItem *item3 = scene.addRect(0, 0, 10, 10);
8373     item3->setFlag(QGraphicsItem::ItemIsFocusable);
8374     item3->setFocusProxy(item2); // item and item3 use item2 as proxy
8375
8376     QCOMPARE(item->focusProxy(), item2);
8377     QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0);
8378     QCOMPARE(item3->focusProxy(), item2);
8379     delete item2;
8380     QCOMPARE(item->focusProxy(), (QGraphicsItem *)0);
8381     QCOMPARE(item3->focusProxy(), (QGraphicsItem *)0);
8382 }
8383
8384 void tst_QGraphicsItem::subFocus()
8385 {
8386     // Construct a text item that's not part of a scene (yet)
8387     // and has no parent. Setting focus on it will not make
8388     // the item gain input focus; that requires a scene. But
8389     // it does set subfocus, indicating that the item wishes
8390     // to gain focus later.
8391     QGraphicsTextItem *text = new QGraphicsTextItem("Hello");
8392     text->setTextInteractionFlags(Qt::TextEditorInteraction);
8393     QVERIFY(!text->hasFocus());
8394     text->setFocus();
8395     QVERIFY(!text->hasFocus());
8396     QCOMPARE(text->focusItem(), (QGraphicsItem *)text);
8397
8398     // Add a sibling.
8399     QGraphicsTextItem *text2 = new QGraphicsTextItem("Hi");
8400     text2->setTextInteractionFlags(Qt::TextEditorInteraction);
8401     text2->setPos(30, 30);
8402
8403     // Add both items to a scene and check that it's text that
8404     // got input focus.
8405     QGraphicsScene scene;
8406     QEvent activate(QEvent::WindowActivate);
8407     QApplication::sendEvent(&scene, &activate);
8408
8409     scene.addItem(text);
8410     scene.addItem(text2);
8411     QVERIFY(text->hasFocus());
8412
8413     text->setData(0, "text");
8414     text2->setData(0, "text2");
8415
8416     // Remove text2 and set subfocus on it. Then readd. Reparent it onto the
8417     // other item and see that it gains input focus.
8418     scene.removeItem(text2);
8419     text2->setFocus();
8420     scene.addItem(text2);
8421     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8422     text2->setParentItem(text);
8423     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8424     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8425     QVERIFY(!text->hasFocus());
8426     QVERIFY(text2->hasFocus());
8427
8428     // Remove both items from the scene, restore subfocus and
8429     // readd them. Now the subfocus should kick in and give
8430     // text2 focus.
8431     scene.removeItem(text);
8432     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8433     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8434     text2->setFocus();
8435     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8436     QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2);
8437     scene.addItem(text);
8438
8439     // Hiding and showing text should pass focus to text2.
8440     QCOMPARE(text->focusItem(), (QGraphicsItem *)text2);
8441     QVERIFY(text2->hasFocus());
8442
8443     // Subfocus should repropagate to root when reparenting.
8444     QGraphicsRectItem *rect = new QGraphicsRectItem;
8445     QGraphicsRectItem *rect2 = new QGraphicsRectItem(rect);
8446     QGraphicsRectItem *rect3 = new QGraphicsRectItem(rect2);
8447     rect3->setFlag(QGraphicsItem::ItemIsFocusable);
8448
8449     text->setData(0, "text");
8450     text2->setData(0, "text2");
8451     rect->setData(0, "rect");
8452     rect2->setData(0, "rect2");
8453     rect3->setData(0, "rect3");
8454
8455     rect3->setFocus();
8456     QVERIFY(!rect3->hasFocus());
8457     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8458     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8459     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8460     rect->setParentItem(text2);
8461     QCOMPARE(text->focusItem(), (QGraphicsItem *)rect3);
8462     QCOMPARE(text2->focusItem(), (QGraphicsItem *)rect3);
8463     QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3);
8464     QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3);
8465     QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3);
8466     QVERIFY(!rect->hasFocus());
8467     QVERIFY(!rect2->hasFocus());
8468     QVERIFY(rect3->hasFocus());
8469
8470     delete rect2;
8471     QCOMPARE(text->focusItem(), (QGraphicsItem *)0);
8472     QCOMPARE(text2->focusItem(), (QGraphicsItem *)0);
8473     QCOMPARE(rect->focusItem(), (QGraphicsItem *)0);
8474 }
8475
8476 void tst_QGraphicsItem::focusProxyDeletion()
8477 {
8478     QGraphicsRectItem *rect = new QGraphicsRectItem;
8479     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8480     rect->setFocusProxy(rect2);
8481     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8482
8483     delete rect2;
8484     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8485
8486     rect2 = new QGraphicsRectItem;
8487     rect->setFocusProxy(rect2);
8488     delete rect; // don't crash
8489
8490     rect = new QGraphicsRectItem;
8491     rect->setFocusProxy(rect2);
8492     QGraphicsScene *scene = new QGraphicsScene;
8493     scene->addItem(rect);
8494     scene->addItem(rect2);
8495     delete rect2;
8496     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8497
8498     rect2 = new QGraphicsRectItem;
8499     QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
8500     rect->setFocusProxy(rect2);
8501     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0);
8502     scene->addItem(rect2);
8503     rect->setFocusProxy(rect2);
8504     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8505     delete rect; // don't crash
8506
8507     rect = new QGraphicsRectItem;
8508     rect2 = new QGraphicsRectItem;
8509     rect->setFocusProxy(rect2);
8510     QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2);
8511     scene->addItem(rect);
8512     scene->addItem(rect2);
8513     rect->setFocusProxy(rect2);
8514     delete scene; // don't crash
8515 }
8516
8517 void tst_QGraphicsItem::negativeZStacksBehindParent()
8518 {
8519     QGraphicsRectItem rect;
8520     QCOMPARE(rect.zValue(), qreal(0.0));
8521     QVERIFY(!(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent));
8522     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8523     rect.setZValue(-1);
8524     QCOMPARE(rect.zValue(), qreal(-1.0));
8525     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8526     rect.setZValue(0);
8527     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
8528     QVERIFY(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent);
8529     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8530     rect.setZValue(-1);
8531     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8532     rect.setZValue(0);
8533     QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent));
8534     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8535     rect.setZValue(-1);
8536     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, true);
8537     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8538     rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false);
8539     QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent);
8540 }
8541
8542 void tst_QGraphicsItem::setGraphicsEffect()
8543 {
8544     // Check that we don't have any effect by default.
8545     QGraphicsItem *item = new QGraphicsRectItem(0, 0, 10, 10);
8546     QVERIFY(!item->graphicsEffect());
8547
8548     // SetGet check.
8549     QPointer<QGraphicsEffect> blurEffect = new QGraphicsBlurEffect;
8550     item->setGraphicsEffect(blurEffect);
8551     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(blurEffect));
8552
8553     // Ensure the existing effect is deleted when setting a new one.
8554     QPointer<QGraphicsEffect> shadowEffect = new QGraphicsDropShadowEffect;
8555     item->setGraphicsEffect(shadowEffect);
8556     QVERIFY(!blurEffect);
8557     QCOMPARE(item->graphicsEffect(), static_cast<QGraphicsEffect *>(shadowEffect));
8558     blurEffect = new QGraphicsBlurEffect;
8559
8560     // Ensure the effect is uninstalled when setting it on a new target.
8561     QGraphicsItem *anotherItem = new QGraphicsRectItem(0, 0, 10, 10);
8562     anotherItem->setGraphicsEffect(blurEffect);
8563     item->setGraphicsEffect(blurEffect);
8564     QVERIFY(!anotherItem->graphicsEffect());
8565     QVERIFY(!shadowEffect);
8566
8567     // Ensure the existing effect is deleted when deleting the item.
8568     delete item;
8569     QVERIFY(!blurEffect);
8570     delete anotherItem;
8571
8572     // Ensure the effect is uninstalled when deleting it
8573     item = new QGraphicsRectItem(0, 0, 10, 10);
8574     blurEffect = new QGraphicsBlurEffect;
8575     item->setGraphicsEffect(blurEffect);
8576     delete blurEffect;
8577     QVERIFY(!item->graphicsEffect());
8578
8579     // Ensure the existing effect is uninstalled and deleted when setting a null effect
8580     blurEffect = new QGraphicsBlurEffect;
8581     item->setGraphicsEffect(blurEffect);
8582     item->setGraphicsEffect(0);
8583     QVERIFY(!item->graphicsEffect());
8584     QVERIFY(!blurEffect);
8585
8586     delete item;
8587 }
8588
8589 void tst_QGraphicsItem::panel()
8590 {
8591     QGraphicsScene scene;
8592
8593     QGraphicsRectItem *panel1 = new QGraphicsRectItem;
8594     QGraphicsRectItem *panel2 = new QGraphicsRectItem;
8595     QGraphicsRectItem *panel3 = new QGraphicsRectItem;
8596     QGraphicsRectItem *panel4 = new QGraphicsRectItem;
8597     QGraphicsRectItem *notPanel1 = new QGraphicsRectItem;
8598     QGraphicsRectItem *notPanel2 = new QGraphicsRectItem;
8599     panel1->setFlag(QGraphicsItem::ItemIsPanel);
8600     panel2->setFlag(QGraphicsItem::ItemIsPanel);
8601     panel3->setFlag(QGraphicsItem::ItemIsPanel);
8602     panel4->setFlag(QGraphicsItem::ItemIsPanel);
8603     scene.addItem(panel1);
8604     scene.addItem(panel2);
8605     scene.addItem(panel3);
8606     scene.addItem(panel4);
8607     scene.addItem(notPanel1);
8608     scene.addItem(notPanel2);
8609
8610     EventSpy spy_activate_panel1(&scene, panel1, QEvent::WindowActivate);
8611     EventSpy spy_deactivate_panel1(&scene, panel1, QEvent::WindowDeactivate);
8612     EventSpy spy_activate_panel2(&scene, panel2, QEvent::WindowActivate);
8613     EventSpy spy_deactivate_panel2(&scene, panel2, QEvent::WindowDeactivate);
8614     EventSpy spy_activate_panel3(&scene, panel3, QEvent::WindowActivate);
8615     EventSpy spy_deactivate_panel3(&scene, panel3, QEvent::WindowDeactivate);
8616     EventSpy spy_activate_panel4(&scene, panel4, QEvent::WindowActivate);
8617     EventSpy spy_deactivate_panel4(&scene, panel4, QEvent::WindowDeactivate);
8618     EventSpy spy_activate_notPanel1(&scene, notPanel1, QEvent::WindowActivate);
8619     EventSpy spy_deactivate_notPanel1(&scene, notPanel1, QEvent::WindowDeactivate);
8620     EventSpy spy_activate_notPanel2(&scene, notPanel1, QEvent::WindowActivate);
8621     EventSpy spy_deactivate_notPanel2(&scene, notPanel1, QEvent::WindowDeactivate);
8622
8623     QCOMPARE(spy_activate_panel1.count(), 0);
8624     QCOMPARE(spy_deactivate_panel1.count(), 0);
8625     QCOMPARE(spy_activate_panel2.count(), 0);
8626     QCOMPARE(spy_deactivate_panel2.count(), 0);
8627     QCOMPARE(spy_activate_panel3.count(), 0);
8628     QCOMPARE(spy_deactivate_panel3.count(), 0);
8629     QCOMPARE(spy_activate_panel4.count(), 0);
8630     QCOMPARE(spy_deactivate_panel4.count(), 0);
8631     QCOMPARE(spy_activate_notPanel1.count(), 0);
8632     QCOMPARE(spy_deactivate_notPanel1.count(), 0);
8633     QCOMPARE(spy_activate_notPanel2.count(), 0);
8634     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8635
8636     QVERIFY(!scene.activePanel());
8637     QVERIFY(!scene.isActive());
8638
8639     QEvent activate(QEvent::WindowActivate);
8640     QEvent deactivate(QEvent::WindowDeactivate);
8641
8642     QApplication::sendEvent(&scene, &activate);
8643
8644     // No previous activation, so the scene is active.
8645     QVERIFY(scene.isActive());
8646     QCOMPARE(scene.activePanel(), (QGraphicsItem *)panel1);
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_deactivate_notPanel1.count(), 0);
8654     QCOMPARE(spy_deactivate_notPanel2.count(), 0);
8655     QCOMPARE(spy_activate_panel1.count(), 1);
8656     QCOMPARE(spy_activate_panel2.count(), 0);
8657     QCOMPARE(spy_activate_panel3.count(), 0);
8658     QCOMPARE(spy_activate_panel4.count(), 0);
8659
8660     // Switch back to scene.
8661     scene.setActivePanel(0);
8662     QVERIFY(!scene.activePanel());
8663     QVERIFY(!panel1->isActive());
8664     QVERIFY(!panel2->isActive());
8665     QVERIFY(!panel3->isActive());
8666     QVERIFY(!panel4->isActive());
8667     QVERIFY(notPanel1->isActive());
8668     QVERIFY(notPanel2->isActive());
8669     QCOMPARE(spy_activate_notPanel1.count(), 1);
8670     QCOMPARE(spy_activate_notPanel2.count(), 1);
8671
8672     // Deactivate the scene
8673     QApplication::sendEvent(&scene, &deactivate);
8674     QVERIFY(!scene.activePanel());
8675     QVERIFY(!panel1->isActive());
8676     QVERIFY(!panel2->isActive());
8677     QVERIFY(!panel3->isActive());
8678     QVERIFY(!panel4->isActive());
8679     QVERIFY(!notPanel1->isActive());
8680     QVERIFY(!notPanel2->isActive());
8681     QCOMPARE(spy_deactivate_notPanel1.count(), 1);
8682     QCOMPARE(spy_deactivate_notPanel2.count(), 1);
8683
8684     // Reactivate the scene
8685     QApplication::sendEvent(&scene, &activate);
8686     QVERIFY(!scene.activePanel());
8687     QVERIFY(!panel1->isActive());
8688     QVERIFY(!panel2->isActive());
8689     QVERIFY(!panel3->isActive());
8690     QVERIFY(!panel4->isActive());
8691     QVERIFY(notPanel1->isActive());
8692     QVERIFY(notPanel2->isActive());
8693     QCOMPARE(spy_activate_notPanel1.count(), 2);
8694     QCOMPARE(spy_activate_notPanel2.count(), 2);
8695
8696     // Switch to panel1
8697     scene.setActivePanel(panel1);
8698     QVERIFY(panel1->isActive());
8699     QCOMPARE(spy_deactivate_notPanel1.count(), 2);
8700     QCOMPARE(spy_deactivate_notPanel2.count(), 2);
8701     QCOMPARE(spy_activate_panel1.count(), 2);
8702
8703     // Deactivate the scene
8704     QApplication::sendEvent(&scene, &deactivate);
8705     QVERIFY(!panel1->isActive());
8706     QCOMPARE(spy_deactivate_panel1.count(), 2);
8707
8708     // Reactivate the scene
8709     QApplication::sendEvent(&scene, &activate);
8710     QVERIFY(panel1->isActive());
8711     QCOMPARE(spy_activate_panel1.count(), 3);
8712
8713     // Deactivate the scene
8714     QApplication::sendEvent(&scene, &deactivate);
8715     QVERIFY(!panel1->isActive());
8716     QVERIFY(!scene.activePanel());
8717     scene.setActivePanel(0);
8718
8719     // Reactivate the scene
8720     QApplication::sendEvent(&scene, &activate);
8721     QVERIFY(!panel1->isActive());
8722 }
8723
8724 void tst_QGraphicsItem::panelWithFocusItem()
8725 {
8726     QGraphicsScene scene;
8727     QEvent activate(QEvent::WindowActivate);
8728     QApplication::sendEvent(&scene, &activate);
8729
8730     QGraphicsRectItem *parentPanel = new QGraphicsRectItem;
8731     QGraphicsRectItem *parentPanelFocusItem = new QGraphicsRectItem(parentPanel);
8732     parentPanel->setFlag(QGraphicsItem::ItemIsPanel);
8733     parentPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8734     parentPanelFocusItem->setFocus();
8735     scene.addItem(parentPanel);
8736
8737     QVERIFY(parentPanel->isActive());
8738     QVERIFY(parentPanelFocusItem->hasFocus());
8739     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8740     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8741
8742     QGraphicsRectItem *childPanel = new QGraphicsRectItem;
8743     QGraphicsRectItem *childPanelFocusItem = new QGraphicsRectItem(childPanel);
8744     childPanel->setFlag(QGraphicsItem::ItemIsPanel);
8745     childPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable);
8746     childPanelFocusItem->setFocus();
8747
8748     QVERIFY(!childPanelFocusItem->hasFocus());
8749     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8750     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8751
8752     childPanel->setParentItem(parentPanel);
8753
8754     QVERIFY(!parentPanel->isActive());
8755     QVERIFY(!parentPanelFocusItem->hasFocus());
8756     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8757     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8758
8759     QVERIFY(childPanel->isActive());
8760     QVERIFY(childPanelFocusItem->hasFocus());
8761     QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8762     QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem);
8763
8764     childPanel->hide();
8765
8766     QVERIFY(parentPanel->isActive());
8767     QVERIFY(parentPanelFocusItem->hasFocus());
8768     QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8769     QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem);
8770 }
8771
8772 void tst_QGraphicsItem::addPanelToActiveScene()
8773 {
8774     QGraphicsScene scene;
8775     QVERIFY(!scene.isActive());
8776
8777     QGraphicsRectItem *rect = new QGraphicsRectItem;
8778     scene.addItem(rect);
8779     QVERIFY(!rect->isActive());
8780     scene.removeItem(rect);
8781
8782     QEvent activate(QEvent::WindowActivate);
8783     QEvent deactivate(QEvent::WindowDeactivate);
8784
8785     QApplication::sendEvent(&scene, &activate);
8786     QVERIFY(scene.isActive());
8787     scene.addItem(rect);
8788     QVERIFY(rect->isActive());
8789     scene.removeItem(rect);
8790
8791     rect->setFlag(QGraphicsItem::ItemIsPanel);
8792     scene.addItem(rect);
8793     QVERIFY(rect->isActive());
8794     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8795
8796     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8797     scene.addItem(rect2);
8798     QVERIFY(rect->isActive());
8799     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
8800 }
8801
8802 void tst_QGraphicsItem::activate()
8803 {
8804     QGraphicsScene scene;
8805     QGraphicsRectItem *rect = scene.addRect(-10, -10, 20, 20);
8806     QVERIFY(!rect->isActive());
8807
8808     QEvent activate(QEvent::WindowActivate);
8809     QEvent deactivate(QEvent::WindowDeactivate);
8810
8811     QApplication::sendEvent(&scene, &activate);
8812
8813     // Non-panel item (active when scene is active).
8814     QVERIFY(rect->isActive());
8815
8816     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
8817     rect2->setFlag(QGraphicsItem::ItemIsPanel);
8818     QGraphicsRectItem *rect3 = new QGraphicsRectItem;
8819     rect3->setFlag(QGraphicsItem::ItemIsPanel);
8820
8821     // Test normal activation.
8822     QVERIFY(!rect2->isActive());
8823     scene.addItem(rect2);
8824     QVERIFY(rect2->isActive()); // first panel item is activated
8825     scene.addItem(rect3);
8826     QVERIFY(!rect3->isActive()); // second panel item is _not_ activated
8827     rect3->setActive(true);
8828     QVERIFY(rect3->isActive());
8829     scene.removeItem(rect3);
8830     QVERIFY(!rect3->isActive()); // no panel is active anymore
8831     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8832     scene.addItem(rect3);
8833     QVERIFY(rect3->isActive()); // second panel item is activated
8834
8835     // Test pending activation.
8836     scene.removeItem(rect3);
8837     rect2->setActive(true);
8838     QVERIFY(rect2->isActive()); // first panel item is activated
8839     rect3->setActive(true);
8840     QVERIFY(!rect3->isActive()); // not active (yet)
8841     scene.addItem(rect3);
8842     QVERIFY(rect3->isActive()); // now becomes active
8843
8844     // Test pending deactivation.
8845     scene.removeItem(rect3);
8846     rect3->setActive(false);
8847     scene.addItem(rect3);
8848     QVERIFY(!rect3->isActive()); // doesn't become active
8849
8850     // Child of panel activation.
8851     rect3->setActive(true);
8852     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
8853     rect4->setFlag(QGraphicsItem::ItemIsPanel);
8854     QGraphicsRectItem *rect5 = new QGraphicsRectItem(rect4);
8855     QGraphicsRectItem *rect6 = new QGraphicsRectItem(rect5);
8856     scene.addItem(rect4);
8857     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect3);
8858     scene.removeItem(rect4);
8859     rect6->setActive(true);
8860     scene.addItem(rect4);
8861     QVERIFY(rect4->isActive());
8862     QVERIFY(rect5->isActive());
8863     QVERIFY(rect6->isActive());
8864     QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect4);
8865     scene.removeItem(rect4); // no active panel
8866     rect6->setActive(false);
8867     scene.addItem(rect4);
8868     QVERIFY(!rect4->isActive());
8869     QVERIFY(!rect5->isActive());
8870     QVERIFY(!rect6->isActive());
8871     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8872
8873     // Controlling auto-activation when the scene changes activation.
8874     rect4->setActive(true);
8875     QApplication::sendEvent(&scene, &deactivate);
8876     QVERIFY(!scene.isActive());
8877     QVERIFY(!rect4->isActive());
8878     rect4->setActive(false);
8879     QApplication::sendEvent(&scene, &activate);
8880     QVERIFY(scene.isActive());
8881     QVERIFY(!scene.activePanel());
8882     QVERIFY(!rect4->isActive());
8883 }
8884
8885 void tst_QGraphicsItem::setActivePanelOnInactiveScene()
8886 {
8887     QGraphicsScene scene;
8888     QGraphicsRectItem *item = scene.addRect(QRectF());
8889     QGraphicsRectItem *panel = scene.addRect(QRectF());
8890     panel->setFlag(QGraphicsItem::ItemIsPanel);
8891
8892     EventSpy itemActivateSpy(&scene, item, QEvent::WindowActivate);
8893     EventSpy itemDeactivateSpy(&scene, item, QEvent::WindowDeactivate);
8894     EventSpy panelActivateSpy(&scene, panel, QEvent::WindowActivate);
8895     EventSpy panelDeactivateSpy(&scene, panel, QEvent::WindowDeactivate);
8896     EventSpy sceneActivationChangeSpy(&scene, QEvent::ActivationChange);
8897
8898     scene.setActivePanel(panel);
8899     QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
8900     QCOMPARE(itemActivateSpy.count(), 0);
8901     QCOMPARE(itemDeactivateSpy.count(), 0);
8902     QCOMPARE(panelActivateSpy.count(), 0);
8903     QCOMPARE(panelDeactivateSpy.count(), 0);
8904     QCOMPARE(sceneActivationChangeSpy.count(), 0);
8905 }
8906
8907 void tst_QGraphicsItem::activationOnShowHide()
8908 {
8909     QGraphicsScene scene;
8910     QEvent activate(QEvent::WindowActivate);
8911     QApplication::sendEvent(&scene, &activate);
8912
8913     QGraphicsRectItem *rootPanel = scene.addRect(QRectF());
8914     rootPanel->setFlag(QGraphicsItem::ItemIsPanel);
8915     rootPanel->setActive(true);
8916
8917     QGraphicsRectItem *subPanel = new QGraphicsRectItem;
8918     subPanel->setFlag(QGraphicsItem::ItemIsPanel);
8919
8920     // Reparenting onto an active panel auto-activates the child panel.
8921     subPanel->setParentItem(rootPanel);
8922     QVERIFY(subPanel->isActive());
8923     QVERIFY(!rootPanel->isActive());
8924
8925     // Hiding an active child panel will reactivate the parent panel.
8926     subPanel->hide();
8927     QVERIFY(rootPanel->isActive());
8928
8929     // Showing a child panel will auto-activate it.
8930     subPanel->show();
8931     QVERIFY(subPanel->isActive());
8932     QVERIFY(!rootPanel->isActive());
8933
8934     // Adding an unrelated panel doesn't affect activation.
8935     QGraphicsRectItem *otherPanel = new QGraphicsRectItem;
8936     otherPanel->setFlag(QGraphicsItem::ItemIsPanel);
8937     scene.addItem(otherPanel);
8938     QVERIFY(subPanel->isActive());
8939
8940     // Showing an unrelated panel doesn't affect activation.
8941     otherPanel->hide();
8942     otherPanel->show();
8943     QVERIFY(subPanel->isActive());
8944
8945     // Add a non-panel item.
8946     QGraphicsRectItem *otherItem = new QGraphicsRectItem;
8947     scene.addItem(otherItem);
8948     otherItem->setActive(true);
8949     QVERIFY(otherItem->isActive());
8950
8951     // Reparent a panel onto an active non-panel item.
8952     subPanel->setParentItem(otherItem);
8953     QVERIFY(subPanel->isActive());
8954
8955     // Showing a child panel of a non-panel item will activate it.
8956     subPanel->hide();
8957     QVERIFY(!subPanel->isActive());
8958     QVERIFY(otherItem->isActive());
8959     subPanel->show();
8960     QVERIFY(subPanel->isActive());
8961
8962     // Hiding a toplevel active panel will pass activation back
8963     // to the non-panel items.
8964     rootPanel->setActive(true);
8965     rootPanel->hide();
8966     QVERIFY(!rootPanel->isActive());
8967     QVERIFY(otherItem->isActive());
8968 }
8969
8970 class MoveWhileDying : public QGraphicsRectItem
8971 {
8972 public:
8973     MoveWhileDying(QGraphicsItem *parent = 0)
8974         : QGraphicsRectItem(parent)
8975     { }
8976     ~MoveWhileDying()
8977     {
8978         foreach (QGraphicsItem *c, childItems()) {
8979             foreach (QGraphicsItem *cc, c->childItems()) {
8980                 cc->moveBy(10, 10);
8981             }
8982             c->moveBy(10, 10);
8983         }
8984         if (QGraphicsItem *p = parentItem()) { p->moveBy(10, 10); }
8985     }
8986 };
8987
8988 void tst_QGraphicsItem::moveWhileDeleting()
8989 {
8990     QGraphicsScene scene;
8991     QGraphicsRectItem *rect = new QGraphicsRectItem;
8992     MoveWhileDying *silly = new MoveWhileDying(rect);
8993     QGraphicsRectItem *child = new QGraphicsRectItem(silly);
8994     scene.addItem(rect);
8995     delete rect; // don't crash!
8996
8997     rect = new QGraphicsRectItem;
8998     silly = new MoveWhileDying(rect);
8999     child = new QGraphicsRectItem(silly);
9000
9001     QGraphicsView view(&scene);
9002     view.show();
9003     QVERIFY(QTest::qWaitForWindowExposed(&view));
9004
9005     delete rect;
9006
9007     rect = new QGraphicsRectItem;
9008     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
9009     silly = new MoveWhileDying(rect);
9010     child = new QGraphicsRectItem(silly);
9011
9012     QTest::qWait(125);
9013
9014     delete rect;
9015
9016     rect = new MoveWhileDying;
9017     rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
9018     child = new QGraphicsRectItem(rect);
9019     silly = new MoveWhileDying(child);
9020
9021     QTest::qWait(125);
9022
9023     delete rect;
9024 }
9025
9026 class MyRectItem : public QGraphicsWidget
9027 {
9028     Q_OBJECT
9029 public:
9030     MyRectItem(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
9031     {
9032
9033     }
9034
9035     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
9036     {
9037         painter->setBrush(brush);
9038         painter->drawRect(boundingRect());
9039     }
9040     void move()
9041     {
9042         setPos(-100,-100);
9043         topLevel->collidingItems(Qt::IntersectsItemBoundingRect);
9044     }
9045 public:
9046     QGraphicsItem *topLevel;
9047     QBrush brush;
9048 };
9049
9050
9051 void tst_QGraphicsItem::ensureDirtySceneTransform()
9052 {
9053     QGraphicsScene scene;
9054
9055     MyRectItem *topLevel = new MyRectItem;
9056     topLevel->setGeometry(0, 0, 100, 100);
9057     topLevel->setPos(-50, -50);
9058     topLevel->brush = QBrush(QColor(Qt::black));
9059     scene.addItem(topLevel);
9060
9061     MyRectItem *parent = new MyRectItem;
9062     parent->topLevel = topLevel;
9063     parent->setGeometry(0, 0, 100, 100);
9064     parent->setPos(0, 0);
9065     parent->brush = QBrush(QColor(Qt::magenta));
9066     parent->setObjectName("parent");
9067     scene.addItem(parent);
9068
9069     MyRectItem *child = new MyRectItem(parent);
9070     child->setGeometry(0, 0, 80, 80);
9071     child->setPos(10, 10);
9072     child->setObjectName("child");
9073     child->brush = QBrush(QColor(Qt::blue));
9074
9075     MyRectItem *child2 = new MyRectItem(parent);
9076     child2->setGeometry(0, 0, 80, 80);
9077     child2->setPos(15, 15);
9078     child2->setObjectName("child2");
9079     child2->brush = QBrush(QColor(Qt::green));
9080
9081     MyRectItem *child3 = new MyRectItem(parent);
9082     child3->setGeometry(0, 0, 80, 80);
9083     child3->setPos(20, 20);
9084     child3->setObjectName("child3");
9085     child3->brush = QBrush(QColor(Qt::gray));
9086
9087     QGraphicsView view(&scene);
9088     view.show();
9089     QApplication::setActiveWindow(&view);
9090     QVERIFY(QTest::qWaitForWindowActive(&view));
9091     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
9092
9093     //We move the parent
9094     parent->move();
9095     QApplication::processEvents();
9096
9097     //We check if all items moved
9098     QCOMPARE(child->pos(), QPointF(10, 10));
9099     QCOMPARE(child2->pos(), QPointF(15, 15));
9100     QCOMPARE(child3->pos(), QPointF(20, 20));
9101
9102     QCOMPARE(child->sceneBoundingRect(), QRectF(-90, -90, 80, 80));
9103     QCOMPARE(child2->sceneBoundingRect(), QRectF(-85, -85, 80, 80));
9104     QCOMPARE(child3->sceneBoundingRect(), QRectF(-80, -80, 80, 80));
9105
9106     QCOMPARE(child->sceneTransform(), QTransform::fromTranslate(-90, -90));
9107     QCOMPARE(child2->sceneTransform(), QTransform::fromTranslate(-85, -85));
9108     QCOMPARE(child3->sceneTransform(), QTransform::fromTranslate(-80, -80));
9109 }
9110
9111 void tst_QGraphicsItem::focusScope()
9112 {
9113     // ItemIsFocusScope is an internal feature (for now).
9114     QGraphicsScene scene;
9115
9116     QGraphicsRectItem *scope3 = new QGraphicsRectItem;
9117     scope3->setData(0, "scope3");
9118     scope3->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9119     scope3->setFocus();
9120     QVERIFY(!scope3->focusScopeItem());
9121     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9122
9123     QGraphicsRectItem *scope2 = new QGraphicsRectItem;
9124     scope2->setData(0, "scope2");
9125     scope2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9126     scope2->setFocus();
9127     QVERIFY(!scope2->focusScopeItem());
9128     scope3->setParentItem(scope2);
9129     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9130     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9131
9132     QGraphicsRectItem *scope1 = new QGraphicsRectItem;
9133     scope1->setData(0, "scope1");
9134     scope1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9135     scope1->setFocus();
9136     QVERIFY(!scope1->focusScopeItem());
9137     scope2->setParentItem(scope1);
9138
9139     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9140     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9141     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9142     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9143     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9144     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9145
9146     scene.addItem(scope1);
9147
9148     QEvent windowActivate(QEvent::WindowActivate);
9149     qApp->sendEvent(&scene, &windowActivate);
9150     scene.setFocus();
9151
9152     QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3);
9153     QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3);
9154     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3);
9155     QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2);
9156     QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3);
9157     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9158
9159     QVERIFY(scope3->hasFocus());
9160
9161     scope3->hide();
9162     QVERIFY(scope2->hasFocus());
9163     scope2->hide();
9164     QVERIFY(scope1->hasFocus());
9165     scope2->show();
9166     QVERIFY(scope2->hasFocus());
9167     scope3->show();
9168     QVERIFY(scope3->hasFocus());
9169     scope1->hide();
9170     QVERIFY(!scope3->hasFocus());
9171     scope1->show();
9172     QVERIFY(scope3->hasFocus());
9173     scope3->clearFocus();
9174     QVERIFY(scope2->hasFocus());
9175     scope2->clearFocus();
9176     QVERIFY(scope1->hasFocus());
9177     scope2->hide();
9178     scope2->show();
9179     QVERIFY(!scope2->hasFocus());
9180     QVERIFY(scope1->hasFocus());
9181     scope2->setFocus();
9182     QVERIFY(scope2->hasFocus());
9183     scope3->setFocus();
9184     QVERIFY(scope3->hasFocus());
9185
9186     QGraphicsRectItem *rect4 = new QGraphicsRectItem;
9187     rect4->setData(0, "rect4");
9188     rect4->setParentItem(scope3);
9189
9190     QGraphicsRectItem *rect5 = new QGraphicsRectItem;
9191     rect5->setData(0, "rect5");
9192     rect5->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9193     rect5->setFocus();
9194     rect5->setParentItem(rect4);
9195     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)rect5);
9196     QVERIFY(rect5->hasFocus());
9197
9198     rect4->setParentItem(0);
9199     QVERIFY(rect5->hasFocus());
9200     QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0);
9201     QCOMPARE(scope3->focusItem(), (QGraphicsItem *)0);
9202     QVERIFY(!scope3->hasFocus());
9203
9204     QGraphicsRectItem *rectA = new QGraphicsRectItem;
9205     QGraphicsRectItem *scopeA = new QGraphicsRectItem(rectA);
9206     scopeA->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9207     scopeA->setFocus();
9208     QGraphicsRectItem *scopeB = new QGraphicsRectItem(scopeA);
9209     scopeB->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9210     scopeB->setFocus();
9211
9212     scene.addItem(rectA);
9213     QVERIFY(rect5->hasFocus());
9214     QVERIFY(!scopeB->hasFocus());
9215
9216     scopeA->setFocus();
9217     QVERIFY(scopeB->hasFocus());
9218     QCOMPARE(scopeB->focusItem(), (QGraphicsItem *)scopeB);
9219 }
9220
9221 void tst_QGraphicsItem::focusScope2()
9222 {
9223     QGraphicsRectItem *child1 = new QGraphicsRectItem;
9224     child1->setFlags(QGraphicsItem::ItemIsFocusable);
9225     child1->setFocus();
9226     QCOMPARE(child1->focusItem(), (QGraphicsItem *)child1);
9227
9228     QGraphicsRectItem *child2 = new QGraphicsRectItem;
9229     child2->setFlags(QGraphicsItem::ItemIsFocusable);
9230
9231     QGraphicsRectItem *rootFocusScope = new QGraphicsRectItem;
9232     rootFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9233     rootFocusScope->setFocus();
9234     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)rootFocusScope);
9235
9236     child1->setParentItem(rootFocusScope);
9237     child2->setParentItem(rootFocusScope);
9238
9239     QCOMPARE(rootFocusScope->focusScopeItem(), (QGraphicsItem *)child1);
9240     QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)child1);
9241
9242     QGraphicsRectItem *siblingChild1 = new QGraphicsRectItem;
9243     siblingChild1->setFlags(QGraphicsItem::ItemIsFocusable);
9244     siblingChild1->setFocus();
9245
9246     QGraphicsRectItem *siblingChild2 = new QGraphicsRectItem;
9247     siblingChild2->setFlags(QGraphicsItem::ItemIsFocusable);
9248
9249     QGraphicsRectItem *siblingFocusScope = new QGraphicsRectItem;
9250     siblingFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
9251
9252     siblingChild1->setParentItem(siblingFocusScope);
9253     siblingChild2->setParentItem(siblingFocusScope);
9254
9255     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild1);
9256     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9257
9258     QGraphicsItem *root = new QGraphicsRectItem;
9259     rootFocusScope->setParentItem(root);
9260     siblingFocusScope->setParentItem(root);
9261
9262     QCOMPARE(root->focusItem(), (QGraphicsItem *)child1);
9263
9264     QGraphicsScene scene;
9265     scene.addItem(root);
9266
9267     QEvent activate(QEvent::WindowActivate);
9268     qApp->sendEvent(&scene, &activate);
9269     scene.setFocus();
9270
9271     QCOMPARE(scene.focusItem(), (QGraphicsItem *)child1);
9272
9273     // You cannot set focus on a descendant of a focus scope directly;
9274     // this will only change the scope's focus scope item pointer. If
9275     // you want to give true input focus, you must set it directly on
9276     // the scope itself
9277     siblingChild2->setFocus();
9278     QVERIFY(!siblingChild2->hasFocus());
9279     QVERIFY(!siblingChild2->focusItem());
9280     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9281     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0);
9282
9283     // Set focus on the scope; focus is forwarded to the focus scope item.
9284     siblingFocusScope->setFocus();
9285     QVERIFY(siblingChild2->hasFocus());
9286     QVERIFY(siblingChild2->focusItem());
9287     QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2);
9288     QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)siblingChild2);
9289 }
9290
9291 void tst_QGraphicsItem::stackBefore()
9292 {
9293     QGraphicsRectItem parent;
9294     QGraphicsRectItem *child1 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9295     QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9296     QGraphicsRectItem *child3 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9297     QGraphicsRectItem *child4 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent);
9298     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9299     child1->setData(0, "child1");
9300     child2->setData(0, "child2");
9301     child3->setData(0, "child3");
9302     child4->setData(0, "child4");
9303
9304     // Remove and append
9305     child2->setParentItem(0);
9306     child2->setParentItem(&parent);
9307     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9308
9309     // Move child2 before child1
9310     child2->stackBefore(child1); // 2134
9311     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9312     child2->stackBefore(child2); // 2134
9313     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9314     child1->setZValue(1); // 2341
9315     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9316     child1->stackBefore(child2); // 2341
9317     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9318     child1->setZValue(0); // 1234
9319     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9320     child4->stackBefore(child1); // 4123
9321     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9322     child4->setZValue(1); // 1234 (4123)
9323     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9324     child3->stackBefore(child1); // 3124 (4312)
9325     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9326     child4->setZValue(0); // 4312
9327     QCOMPARE(parent.childItems(), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9328
9329     // Make them all toplevels
9330     child1->setParentItem(0);
9331     child2->setParentItem(0);
9332     child3->setParentItem(0);
9333     child4->setParentItem(0);
9334
9335     QGraphicsScene scene;
9336     scene.addItem(child1);
9337     scene.addItem(child2);
9338     scene.addItem(child3);
9339     scene.addItem(child4);
9340     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder),
9341              (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9342
9343     // Remove and append
9344     scene.removeItem(child2);
9345     scene.addItem(child2);
9346     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child3 << child4 << child2));
9347
9348     // Move child2 before child1
9349     child2->stackBefore(child1); // 2134
9350     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9351     child2->stackBefore(child2); // 2134
9352     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child1 << child3 << child4));
9353     child1->setZValue(1); // 2341
9354     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9355     child1->stackBefore(child2); // 2341
9356     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child2 << child3 << child4 << child1));
9357     child1->setZValue(0); // 1234
9358     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9359     child4->stackBefore(child1); // 4123
9360     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child1 << child2 << child3));
9361     child4->setZValue(1); // 1234 (4123)
9362     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child1 << child2 << child3 << child4));
9363     child3->stackBefore(child1); // 3124 (4312)
9364     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child3 << child1 << child2 << child4));
9365     child4->setZValue(0); // 4312
9366     QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList<QGraphicsItem *>() << child4 << child3 << child1 << child2));
9367 }
9368
9369 void tst_QGraphicsItem::QTBUG_4233_updateCachedWithSceneRect()
9370 {
9371     EventTester *tester = new EventTester;
9372     tester->setCacheMode(QGraphicsItem::ItemCoordinateCache);
9373
9374     QGraphicsScene scene;
9375     scene.addItem(tester);
9376     scene.setSceneRect(-100, -100, 200, 200); // contains the tester item
9377
9378     QGraphicsView view(&scene);
9379     view.show();
9380     QApplication::setActiveWindow(&view);
9381     QVERIFY(QTest::qWaitForWindowActive(&view));
9382     QCOMPARE(QApplication::activeWindow(), (QWidget *)&view);
9383
9384     QTRY_COMPARE(tester->repaints, 1);
9385
9386     scene.update(); // triggers "updateAll" optimization
9387     qApp->processEvents();
9388     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9389
9390     QCOMPARE(tester->repaints, 1);
9391
9392     scene.update(); // triggers "updateAll" optimization
9393     tester->update();
9394     qApp->processEvents();
9395     qApp->processEvents(); // in 4.6 only one processEvents is necessary
9396
9397     QCOMPARE(tester->repaints, 2);
9398 }
9399
9400 void tst_QGraphicsItem::sceneModality()
9401 {
9402     // 1) Test mouse events (delivery/propagation/redirection)
9403     // 2) Test hover events (incl. leave on block, enter on unblock)
9404     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9405     // 4) Test clickfocus
9406     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9407     // 6) ### modality for non-panels is unsupported for now
9408     QGraphicsScene scene;
9409
9410     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9411     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9412     bottomItem->setBrush(Qt::yellow);
9413
9414     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9415     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9416     leftParent->setBrush(Qt::blue);
9417
9418     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9419     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9420     leftChild->setBrush(Qt::green);
9421     leftChild->setParentItem(leftParent);
9422
9423     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9424     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9425     rightParent->setBrush(Qt::red);
9426     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9427     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9428     rightChild->setBrush(Qt::gray);
9429     rightChild->setParentItem(rightParent);
9430
9431     leftParent->setPos(-75, 0);
9432     rightParent->setPos(75, 0);
9433
9434     bottomItem->setData(0, "bottomItem");
9435     leftParent->setData(0, "leftParent");
9436     leftChild->setData(0, "leftChild");
9437     rightParent->setData(0, "rightParent");
9438     rightChild->setData(0, "rightChild");
9439
9440     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9441
9442     EventSpy2 leftParentSpy(&scene, leftParent);
9443     EventSpy2 leftChildSpy(&scene, leftChild);
9444     EventSpy2 rightParentSpy(&scene, rightParent);
9445     EventSpy2 rightChildSpy(&scene, rightChild);
9446     EventSpy2 bottomItemSpy(&scene, bottomItem);
9447
9448     // Scene modality, also test multiple scene modal items
9449     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9450     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9451     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9452     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9453     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9454     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // not a panel
9455
9456     // Click inside left child
9457     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9458     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9459     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9460     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9461     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9462     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9463     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9464
9465     // Click on left parent, event goes to modal child
9466     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9467     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9468     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9469     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9470     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9471     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9472     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9473
9474     // Click on all other items and outside the items
9475     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9476     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9477     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9478     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9479     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9480     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9481     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9482     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9483     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9484     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9485     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9486     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9487     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9488
9489     leftChildSpy.counts.clear();
9490     rightChildSpy.counts.clear();
9491     leftParentSpy.counts.clear();
9492     rightParentSpy.counts.clear();
9493     bottomItemSpy.counts.clear();
9494
9495     leftChild->setPanelModality(QGraphicsItem::NonModal);
9496     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9497     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9498     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9499     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 1);
9500     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9501
9502     // Left parent enters scene modality.
9503     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9504     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9505     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9506     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9507     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9508     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9509
9510     // Click inside left child.
9511     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9512     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9513     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9514     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // panel stops propagation
9515     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9516     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9517     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9518
9519    // Click on left parent.
9520     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9521     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9522     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9523     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9524     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9525     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9526     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9527
9528     // Click on all other items and outside the items
9529     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9530     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9531     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9532     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9533     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9534     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9535     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9536     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9537     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9538     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9539     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9540     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9541     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0);
9542
9543     leftChildSpy.counts.clear();
9544     rightChildSpy.counts.clear();
9545     leftParentSpy.counts.clear();
9546     rightParentSpy.counts.clear();
9547     bottomItemSpy.counts.clear();
9548
9549     // Now both left parent and child are scene modal. Left parent is blocked.
9550     leftChild->setPanelModality(QGraphicsItem::SceneModal);
9551     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9552     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9553     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9554     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9555     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9556
9557     // Click inside left child
9558     sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton);
9559     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1);
9560     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9561     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9562     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9563     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9564     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9565
9566     // Click on left parent, event goes to modal child
9567     sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9568     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2);
9569     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9570     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9571     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9572     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9573     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9574
9575     // Click on all other items and outside the items
9576     sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton);
9577     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3);
9578     sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton);
9579     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4);
9580     sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton);
9581     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5);
9582     sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton);
9583     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6);
9584     QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab
9585     QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9586     QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9587     QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9588     QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked
9589
9590     leftChildSpy.counts.clear();
9591     rightChildSpy.counts.clear();
9592     leftParentSpy.counts.clear();
9593     rightParentSpy.counts.clear();
9594     bottomItemSpy.counts.clear();
9595
9596     // Right child enters scene modality, only left child is blocked.
9597     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9598     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9599     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9600     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9601     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9602     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9603 }
9604
9605 void tst_QGraphicsItem::panelModality()
9606 {
9607     // 1) Test mouse events (delivery/propagation/redirection)
9608     // 2) Test hover events (incl. leave on block, enter on unblock)
9609     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9610     // 4) Test clickfocus
9611     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9612     // 6) ### modality for non-panels is unsupported for now
9613     QGraphicsScene scene;
9614
9615     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9616     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9617     bottomItem->setBrush(Qt::yellow);
9618
9619     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9620     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9621     leftParent->setBrush(Qt::blue);
9622
9623     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9624     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9625     leftChild->setBrush(Qt::green);
9626     leftChild->setParentItem(leftParent);
9627
9628     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9629     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9630     rightParent->setBrush(Qt::red);
9631     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9632     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9633     rightChild->setBrush(Qt::gray);
9634     rightChild->setParentItem(rightParent);
9635
9636     leftParent->setPos(-75, 0);
9637     rightParent->setPos(75, 0);
9638
9639     bottomItem->setData(0, "bottomItem");
9640     leftParent->setData(0, "leftParent");
9641     leftChild->setData(0, "leftChild");
9642     rightParent->setData(0, "rightParent");
9643     rightChild->setData(0, "rightChild");
9644
9645     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9646
9647     EventSpy2 leftParentSpy(&scene, leftParent);
9648     EventSpy2 leftChildSpy(&scene, leftChild);
9649     EventSpy2 rightParentSpy(&scene, rightParent);
9650     EventSpy2 rightChildSpy(&scene, rightChild);
9651     EventSpy2 bottomItemSpy(&scene, bottomItem);
9652
9653     // Left Child enters panel modality, only left parent is blocked.
9654     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9655     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9656     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9657     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9658     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9659     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9660
9661     leftChild->setPanelModality(QGraphicsItem::NonModal);
9662     leftChildSpy.counts.clear();
9663     rightChildSpy.counts.clear();
9664     leftParentSpy.counts.clear();
9665     rightParentSpy.counts.clear();
9666     bottomItemSpy.counts.clear();
9667
9668     // Left parent enter panel modality, nothing is blocked.
9669     leftParent->setPanelModality(QGraphicsItem::PanelModal);
9670     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9671     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9672     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9673     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9674     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9675
9676     // Left child enters panel modality, left parent is blocked again.
9677     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9678     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9679     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9680     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9681     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9682     QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0);
9683
9684     leftChildSpy.counts.clear();
9685     rightChildSpy.counts.clear();
9686     leftParentSpy.counts.clear();
9687     rightParentSpy.counts.clear();
9688     bottomItemSpy.counts.clear();
9689
9690     leftChild->setPanelModality(QGraphicsItem::NonModal);
9691     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9692     leftParent->setPanelModality(QGraphicsItem::NonModal);
9693     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9694     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9695     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1);
9696     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9697     QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0);
9698
9699     leftChildSpy.counts.clear();
9700     rightChildSpy.counts.clear();
9701     leftParentSpy.counts.clear();
9702     rightParentSpy.counts.clear();
9703     bottomItemSpy.counts.clear();
9704
9705     // Left and right child enter panel modality, both parents are blocked.
9706     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9707     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0);
9708     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9709     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9710     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9711     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9712 }
9713
9714 void tst_QGraphicsItem::mixedModality()
9715 {
9716     // 1) Test mouse events (delivery/propagation/redirection)
9717     // 2) Test hover events (incl. leave on block, enter on unblock)
9718     // 3) Test cursor stuff (incl. unset on block, set on unblock)
9719     // 4) Test clickfocus
9720     // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock)
9721     // 6) ### modality for non-panels is unsupported for now
9722     QGraphicsScene scene;
9723
9724     QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200);
9725     bottomItem->setFlag(QGraphicsItem::ItemIsFocusable);
9726     bottomItem->setBrush(Qt::yellow);
9727
9728     QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100);
9729     leftParent->setFlag(QGraphicsItem::ItemIsPanel);
9730     leftParent->setBrush(Qt::blue);
9731
9732     QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50);
9733     leftChild->setFlag(QGraphicsItem::ItemIsPanel);
9734     leftChild->setBrush(Qt::green);
9735     leftChild->setParentItem(leftParent);
9736
9737     QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100);
9738     rightParent->setFlag(QGraphicsItem::ItemIsPanel);
9739     rightParent->setBrush(Qt::red);
9740     QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50);
9741     rightChild->setFlag(QGraphicsItem::ItemIsPanel);
9742     rightChild->setBrush(Qt::gray);
9743     rightChild->setParentItem(rightParent);
9744
9745     leftParent->setPos(-75, 0);
9746     rightParent->setPos(75, 0);
9747
9748     bottomItem->setData(0, "bottomItem");
9749     leftParent->setData(0, "leftParent");
9750     leftChild->setData(0, "leftChild");
9751     rightParent->setData(0, "rightParent");
9752     rightChild->setData(0, "rightChild");
9753
9754     scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50));
9755
9756     EventSpy2 leftParentSpy(&scene, leftParent);
9757     EventSpy2 leftChildSpy(&scene, leftChild);
9758     EventSpy2 rightParentSpy(&scene, rightParent);
9759     EventSpy2 rightChildSpy(&scene, rightChild);
9760     EventSpy2 bottomItemSpy(&scene, bottomItem);
9761
9762     // Left Child enters panel modality, only left parent is blocked.
9763     leftChild->setPanelModality(QGraphicsItem::PanelModal);
9764     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9765     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0);
9766     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9767     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0);
9768
9769     // Left parent enters scene modality, which blocks everything except the child.
9770     leftParent->setPanelModality(QGraphicsItem::SceneModal);
9771     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9772     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9773     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9774     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9775     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9776     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9777     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9778     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9779
9780     // Right child enters panel modality (changes nothing).
9781     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9782     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9783     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9784     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9785     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0);
9786     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9787     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9788     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9789     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9790
9791     // Left parent leaves modality. Right child is unblocked.
9792     leftParent->setPanelModality(QGraphicsItem::NonModal);
9793     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0);
9794     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9795     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9796     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9797     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9798     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9799     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9800     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9801
9802     // Right child "upgrades" its modality to scene modal. Left child is blocked.
9803     // Right parent is unaffected.
9804     rightChild->setPanelModality(QGraphicsItem::SceneModal);
9805     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9806     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0);
9807     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9808     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9809     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9810     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9811     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9812     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9813
9814     // "downgrade" right child back to panel modal, left child is unblocked
9815     rightChild->setPanelModality(QGraphicsItem::PanelModal);
9816     QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1);
9817     QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 1);
9818     QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1);
9819     QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1);
9820     QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1);
9821     QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0);
9822     QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1);
9823     QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0);
9824 }
9825
9826 void tst_QGraphicsItem::modality_hover()
9827 {
9828     QGraphicsScene scene;
9829     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9830     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9831     rect1->setAcceptHoverEvents(true);
9832     rect1->setData(0, "rect1");
9833
9834     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9835     rect2->setParentItem(rect1);
9836     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9837     rect2->setAcceptHoverEvents(true);
9838     rect2->setPos(50, 50);
9839     rect2->setPanelModality(QGraphicsItem::SceneModal);
9840     rect2->setData(0, "rect2");
9841
9842     EventSpy2 rect1Spy(&scene, rect1);
9843     EventSpy2 rect2Spy(&scene, rect2);
9844
9845     sendMouseMove(&scene, QPointF(-25, -25));
9846
9847     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9848     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9849     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9850
9851     sendMouseMove(&scene, QPointF(75, 75));
9852
9853     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9854     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9855     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9856     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9857     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9858     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9859
9860     sendMouseMove(&scene, QPointF(-25, -25));
9861
9862     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9863     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0);
9864     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0);
9865     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0);
9866
9867     rect2->setPanelModality(QGraphicsItem::NonModal);
9868
9869     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9870     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9871
9872     sendMouseMove(&scene, QPointF(75, 75));
9873
9874     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9875     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9876
9877     rect2->setPanelModality(QGraphicsItem::SceneModal);
9878
9879     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9880     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9881     // changing modality causes a spurious GraphicsSceneHoveMove, even though the mouse didn't
9882     // actually move
9883     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9884
9885     sendMouseMove(&scene, QPointF(-25, -25));
9886
9887     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9888     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9889     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9890     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9891
9892     rect2->setPanelModality(QGraphicsItem::PanelModal);
9893
9894     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1);
9895     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1);
9896     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1);
9897     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9898     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9899     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9900
9901     rect2->setPanelModality(QGraphicsItem::NonModal);
9902
9903     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9904     QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 2);
9905     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2);
9906     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3);
9907     QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2);
9908 }
9909
9910 void tst_QGraphicsItem::modality_mouseGrabber()
9911 {
9912     QGraphicsScene scene;
9913     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
9914     rect1->setFlag(QGraphicsItem::ItemIsPanel);
9915     rect1->setFlag(QGraphicsItem::ItemIsMovable);
9916     rect1->setData(0, "rect1");
9917
9918     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
9919     rect2->setParentItem(rect1);
9920     rect2->setFlag(QGraphicsItem::ItemIsPanel);
9921     rect2->setFlag(QGraphicsItem::ItemIsMovable);
9922     rect2->setPos(50, 50);
9923     rect2->setData(0, "rect2");
9924
9925     EventSpy2 rect1Spy(&scene, rect1);
9926     EventSpy2 rect2Spy(&scene, rect2);
9927
9928     {
9929         // pressing mouse on rect1 starts implicit grab
9930         sendMousePress(&scene, QPoint(-25, -25));
9931         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9932         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9933         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
9934         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9935         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9936         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9937
9938         // grab lost when rect1 is modally shadowed
9939         rect2->setPanelModality(QGraphicsItem::SceneModal);
9940         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9941         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9942         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9943         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9944         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9945
9946         // releasing goes nowhere
9947         sendMouseRelease(&scene, QPoint(-25, -25));
9948         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9949         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9950         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9951         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
9952         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9953         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
9954         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9955
9956         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
9957         sendMouseClick(&scene, QPoint(-25, -25));
9958         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
9959         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9960         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9961         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9962         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9963         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
9964         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
9965         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9966
9967         rect2->setPanelModality(QGraphicsItem::NonModal);
9968
9969         // pressing mouse on rect1 starts implicit grab
9970         sendMousePress(&scene, QPoint(-25, -25));
9971         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9972         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
9973         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
9974         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9975         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9976         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
9977
9978         // grab lost to rect2 when rect1 is modally shadowed
9979         rect2->setPanelModality(QGraphicsItem::SceneModal);
9980         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9981         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9982         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9983         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9984         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9985
9986         // rect1 does *not* re-grab when rect2 is no longer modal
9987         rect2->setPanelModality(QGraphicsItem::NonModal);
9988         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9989         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9990         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
9991         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
9992         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
9993
9994         // release goes nowhere
9995         sendMouseRelease(&scene, QPoint(-25, -25));
9996         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
9997         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
9998         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
9999         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10000         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10001         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10002     }
10003     {
10004         // repeat the test using PanelModal
10005         rect2->setPanelModality(QGraphicsItem::NonModal);
10006         rect1Spy.counts.clear();
10007         rect2Spy.counts.clear();
10008
10009         // pressing mouse on rect1 starts implicit grab
10010         sendMousePress(&scene, QPoint(-25, -25));
10011         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10012         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10013         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10014         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10015         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10016         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10017
10018         // grab lost when rect1 is modally shadowed
10019         rect2->setPanelModality(QGraphicsItem::PanelModal);
10020         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10021         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10022         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10023         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10024         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10025
10026         // releasing goes nowhere
10027         sendMouseRelease(&scene, QPoint(-25, -25));
10028         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10029         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10030         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10031         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10032         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10033         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10034         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10035
10036         // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal)
10037         sendMouseClick(&scene, QPoint(-25, -25));
10038         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1);
10039         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10040         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10041         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10042         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10043         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10044         QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10045         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10046
10047         rect2->setPanelModality(QGraphicsItem::NonModal);
10048
10049         // pressing mouse on rect1 starts implicit grab
10050         sendMousePress(&scene, QPoint(-25, -25));
10051         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10052         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2);
10053         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1);
10054         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10055         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10056         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1);
10057
10058         // grab lost to rect2 when rect1 is modally shadowed
10059         rect2->setPanelModality(QGraphicsItem::PanelModal);
10060         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10061         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10062         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10063         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10064         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10065
10066         // rect1 does *not* re-grab when rect2 is no longer modal
10067         rect2->setPanelModality(QGraphicsItem::NonModal);
10068         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10069         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10070         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10071         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10072         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10073
10074         // release goes nowhere
10075         sendMouseRelease(&scene, QPoint(-25, -25));
10076         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2);
10077         QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0);
10078         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2);
10079         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1);
10080         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1);
10081         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10082     }
10083
10084     {
10085         // repeat the PanelModal tests, but this time the mouse events will be on a non-modal item,
10086         // meaning normal grabbing should work
10087         rect2->setPanelModality(QGraphicsItem::NonModal);
10088         rect1Spy.counts.clear();
10089         rect2Spy.counts.clear();
10090
10091         QGraphicsRectItem *rect3 = scene.addRect(-50, -50, 100, 100);
10092         rect3->setFlag(QGraphicsItem::ItemIsPanel);
10093         rect3->setFlag(QGraphicsItem::ItemIsMovable);
10094         rect3->setPos(150, 50);
10095         rect3->setData(0, "rect3");
10096
10097         EventSpy2 rect3Spy(&scene, rect3);
10098
10099         // pressing mouse on rect3 starts implicit grab
10100         sendMousePress(&scene, QPoint(150, 50));
10101         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10102         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10103         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10104         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10105         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10106         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMousePress], 1);
10107         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10108         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10109
10110         // grab is *not* lost when rect1 is modally shadowed by rect2
10111         rect2->setPanelModality(QGraphicsItem::PanelModal);
10112         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10113         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10114         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10115         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10116         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10117         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0);
10118         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10119
10120         // releasing goes to rect3
10121         sendMouseRelease(&scene, QPoint(150, 50));
10122         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10123         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10124         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10125         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10126         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1);
10127         QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMouseRelease], 1);
10128         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10129         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10130
10131         rect2->setPanelModality(QGraphicsItem::NonModal);
10132
10133         // pressing mouse on rect3 starts implicit grab
10134         sendMousePress(&scene, QPoint(150, 50));
10135         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10136         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10137         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10138         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10139         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10140         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10141         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10142
10143         // grab is not lost
10144         rect2->setPanelModality(QGraphicsItem::PanelModal);
10145         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10146         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10147         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10148         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10149         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10150         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10151         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10152
10153         // grab stays on rect3
10154         rect2->setPanelModality(QGraphicsItem::NonModal);
10155         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10156         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10157         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10158         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10159         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10160         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1);
10161         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3);
10162
10163         // release goes to rect3
10164         sendMouseRelease(&scene, QPoint(150, 50));
10165         QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0);
10166         QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0);
10167         QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0);
10168         QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0);
10169         QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2);
10170         QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 2);
10171         QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0);
10172     }
10173 }
10174
10175 void tst_QGraphicsItem::modality_clickFocus()
10176 {
10177     QGraphicsScene scene;
10178     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10179     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10180     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10181     rect1->setData(0, "rect1");
10182
10183     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10184     rect2->setParentItem(rect1);
10185     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10186     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10187     rect2->setPos(50, 50);
10188     rect2->setData(0, "rect2");
10189
10190     QEvent windowActivateEvent(QEvent::WindowActivate);
10191     QApplication::sendEvent(&scene, &windowActivateEvent);
10192
10193     EventSpy2 rect1Spy(&scene, rect1);
10194     EventSpy2 rect2Spy(&scene, rect2);
10195
10196     // activate rect1, it should not get focus
10197     rect1->setActive(true);
10198     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10199
10200     // focus stays unset when rect2 becomes modal
10201     rect2->setPanelModality(QGraphicsItem::SceneModal);
10202     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10203     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10204     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10205     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10206     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10207
10208     // clicking on rect1 should not set it's focus item
10209     sendMouseClick(&scene, QPointF(-25, -25));
10210     QCOMPARE(rect1->focusItem(), (QGraphicsItem *) 0);
10211     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10212     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10213     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0);
10214     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10215
10216     // clicking on rect2 gives it focus
10217     rect2->setActive(true);
10218     sendMouseClick(&scene, QPointF(75, 75));
10219     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect2);
10220     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10221     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10222     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10223     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0);
10224
10225     // clicking on rect1 does *not* give it focus
10226     rect1->setActive(true);
10227     sendMouseClick(&scene, QPointF(-25, -25));
10228     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10229     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10230     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10231     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10232     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10233
10234     // focus doesn't change when leaving modality either
10235     rect2->setPanelModality(QGraphicsItem::NonModal);
10236     QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0);
10237     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0);
10238     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10239     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10240     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10241
10242     // click on rect1, it should get focus now
10243     sendMouseClick(&scene, QPointF(-25, -25));
10244     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1);
10245     QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 1);
10246     QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0);
10247     QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1);
10248     QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1);
10249 }
10250
10251 void tst_QGraphicsItem::modality_keyEvents()
10252 {
10253     QGraphicsScene scene;
10254     QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100);
10255     rect1->setFlag(QGraphicsItem::ItemIsPanel);
10256     rect1->setFlag(QGraphicsItem::ItemIsFocusable);
10257     rect1->setData(0, "rect1");
10258
10259     QGraphicsRectItem *rect1child = scene.addRect(-10, -10, 20, 20);
10260     rect1child->setParentItem(rect1);
10261     rect1child->setFlag(QGraphicsItem::ItemIsFocusable);
10262     rect1child->setData(0, "rect1child1");
10263
10264     QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100);
10265     rect2->setParentItem(rect1);
10266     rect2->setFlag(QGraphicsItem::ItemIsPanel);
10267     rect2->setFlag(QGraphicsItem::ItemIsFocusable);
10268     rect2->setPos(50, 50);
10269     rect2->setData(0, "rect2");
10270
10271     QGraphicsRectItem *rect2child = scene.addRect(-10, -10, 20, 20);
10272     rect2child->setParentItem(rect2);
10273     rect2child->setFlag(QGraphicsItem::ItemIsFocusable);
10274     rect2child->setData(0, "rect2child1");
10275
10276     QEvent windowActivateEvent(QEvent::WindowActivate);
10277     QApplication::sendEvent(&scene, &windowActivateEvent);
10278
10279     EventSpy2 rect1Spy(&scene, rect1);
10280     EventSpy2 rect1childSpy(&scene, rect1child);
10281     EventSpy2 rect2Spy(&scene, rect2);
10282     EventSpy2 rect2childSpy(&scene, rect2child);
10283
10284     // activate rect1 and give it rect1child focus
10285     rect1->setActive(true);
10286     rect1child->setFocus();
10287     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10288
10289     // focus stays on rect1child when rect2 becomes modal
10290     rect2->setPanelModality(QGraphicsItem::SceneModal);
10291     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10292
10293     // but key events to rect1child should be neither delivered nor propagated
10294     sendKeyClick(&scene, Qt::Key_A);
10295     sendKeyClick(&scene, Qt::Key_S);
10296     sendKeyClick(&scene, Qt::Key_D);
10297     sendKeyClick(&scene, Qt::Key_F);
10298     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10299     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10300     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10301     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10302
10303     // change to panel modality, rect1child1 keeps focus
10304     rect2->setPanelModality(QGraphicsItem::PanelModal);
10305     QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child);
10306
10307     // still no key events
10308     sendKeyClick(&scene, Qt::Key_J);
10309     sendKeyClick(&scene, Qt::Key_K);
10310     sendKeyClick(&scene, Qt::Key_L);
10311     sendKeyClick(&scene, Qt::Key_Semicolon);
10312     QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0);
10313     QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0);
10314     QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0);
10315     QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0);
10316 }
10317
10318 void tst_QGraphicsItem::itemIsInFront()
10319 {
10320     QGraphicsScene scene;
10321     QGraphicsRectItem *rect1 = new QGraphicsRectItem;
10322     rect1->setData(0, "rect1");
10323     scene.addItem(rect1);
10324
10325     QGraphicsRectItem *rect1child1 = new QGraphicsRectItem(rect1);
10326     rect1child1->setZValue(1);
10327     rect1child1->setData(0, "rect1child1");
10328
10329     QGraphicsRectItem *rect1child2 = new QGraphicsRectItem(rect1);
10330     rect1child2->setParentItem(rect1);
10331     rect1child2->setData(0, "rect1child2");
10332
10333     QGraphicsRectItem *rect1child1_1 = new QGraphicsRectItem(rect1child1);
10334     rect1child1_1->setData(0, "rect1child1_1");
10335
10336     QGraphicsRectItem *rect1child1_2 = new QGraphicsRectItem(rect1child1);
10337     rect1child1_2->setFlag(QGraphicsItem::ItemStacksBehindParent);
10338     rect1child1_2->setData(0, "rect1child1_2");
10339
10340     QGraphicsRectItem *rect2 = new QGraphicsRectItem;
10341     rect2->setData(0, "rect2");
10342     scene.addItem(rect2);
10343
10344     QGraphicsRectItem *rect2child1 = new QGraphicsRectItem(rect2);
10345     rect2child1->setData(0, "rect2child1");
10346
10347     QCOMPARE(qt_closestItemFirst(rect1, rect1), false);
10348     QCOMPARE(qt_closestItemFirst(rect1, rect2), false);
10349     QCOMPARE(qt_closestItemFirst(rect1child1, rect2child1), false);
10350     QCOMPARE(qt_closestItemFirst(rect1child1, rect1child2), true);
10351     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child2), true);
10352     QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child1), true);
10353     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child2), true);
10354     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child1), false);
10355     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1), true);
10356     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2), false);
10357     QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2child1), false);
10358 }
10359
10360 class ScenePosChangeTester : public ItemChangeTester
10361 {
10362 public:
10363     ScenePosChangeTester()
10364     { }
10365     ScenePosChangeTester(QGraphicsItem *parent) : ItemChangeTester(parent)
10366     { }
10367 };
10368
10369 void tst_QGraphicsItem::scenePosChange()
10370 {
10371     ScenePosChangeTester* root = new ScenePosChangeTester;
10372     ScenePosChangeTester* child1 = new ScenePosChangeTester(root);
10373     ScenePosChangeTester* grandChild1 = new ScenePosChangeTester(child1);
10374     ScenePosChangeTester* child2 = new ScenePosChangeTester(root);
10375     ScenePosChangeTester* grandChild2 = new ScenePosChangeTester(child2);
10376
10377     child1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10378     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10379
10380     QVERIFY(child1->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10381     QVERIFY(grandChild2->flags() & QGraphicsItem::ItemSendsScenePositionChanges);
10382
10383     QGraphicsScene scene;
10384     scene.addItem(root);
10385
10386     // ignore uninteresting changes
10387     child1->clear();
10388     child2->clear();
10389     grandChild1->clear();
10390     grandChild2->clear();
10391
10392     // move whole tree
10393     root->moveBy(1.0, 1.0);
10394     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10395     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10396     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10397     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10398
10399     // move subtree
10400     child2->moveBy(1.0, 1.0);
10401     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10402     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10403     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10404     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10405
10406     // reparent
10407     grandChild2->setParentItem(child1);
10408     child1->moveBy(1.0, 1.0);
10409     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
10410     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10411     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10412     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10413
10414     // change flags
10415     grandChild1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
10416     grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false);
10417     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10418     child1->moveBy(1.0, 1.0);
10419     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10420     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10421     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10422     QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3);
10423
10424     // remove
10425     scene.removeItem(grandChild1);
10426     delete grandChild2; grandChild2 = 0;
10427     QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants()
10428     root->moveBy(1.0, 1.0);
10429     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 4);
10430     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10431     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10432
10433     root->setX(1);
10434     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 5);
10435     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10436     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10437
10438     root->setY(1);
10439     QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 6);
10440     QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
10441     QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0);
10442 }
10443
10444 void tst_QGraphicsItem::textItem_shortcuts()
10445 {
10446     QWidget w;
10447     QVBoxLayout l;
10448     w.setLayout(&l);
10449     QGraphicsScene scene;
10450     QGraphicsView view(&scene);
10451     l.addWidget(&view);
10452     QPushButton b("Push Me");
10453     l.addWidget(&b);
10454
10455     QGraphicsTextItem *item = scene.addText("Troll Text");
10456     item->setFlag(QGraphicsItem::ItemIsFocusable);
10457     item->setTextInteractionFlags(Qt::TextEditorInteraction);
10458     w.show();
10459     QVERIFY(QTest::qWaitForWindowExposed(&w));
10460
10461     item->setFocus();
10462     QTRY_VERIFY(item->hasFocus());
10463     QVERIFY(item->textCursor().selectedText().isEmpty());
10464
10465     // Shortcut should work (select all)
10466     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10467     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10468     QTextCursor tc = item->textCursor();
10469     tc.clearSelection();
10470     item->setTextCursor(tc);
10471     QVERIFY(item->textCursor().selectedText().isEmpty());
10472
10473     // Shortcut should also work if the text item has the focus and another widget
10474     // has the same shortcut.
10475     b.setShortcut(QKeySequence("CTRL+A"));
10476     QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
10477     QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText());
10478 }
10479
10480 void tst_QGraphicsItem::scroll()
10481 {
10482     // Create two overlapping rectangles in the scene:
10483     // +-------+
10484     // |       | <- item1
10485     // |   +-------+
10486     // |   |       |
10487     // +---|       | <- item2
10488     //     |       |
10489     //     +-------+
10490
10491     EventTester *item1 = new EventTester;
10492     item1->br = QRectF(0, 0, 200, 200);
10493     item1->brush = Qt::red;
10494     item1->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10495
10496     EventTester *item2 = new EventTester;
10497     item2->br = QRectF(0, 0, 200, 200);
10498     item2->brush = Qt::blue;
10499     item2->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
10500     item2->setPos(100, 100);
10501
10502     QGraphicsScene scene(0, 0, 300, 300);
10503     scene.addItem(item1);
10504     scene.addItem(item2);
10505
10506     MyGraphicsView view(&scene);
10507     view.setFrameStyle(0);
10508     view.show();
10509     QVERIFY(QTest::qWaitForWindowActive(&view));
10510     QTRY_VERIFY(view.repaints > 0);
10511
10512     view.reset();
10513     item1->reset();
10514     item2->reset();
10515
10516     const QRectF item1BoundingRect = item1->boundingRect();
10517     const QRectF item2BoundingRect = item2->boundingRect();
10518
10519     // Scroll item1:
10520     // Item1 should get full exposure
10521     // Item2 should get exposure for the part that overlaps item1.
10522     item1->scroll(0, -10);
10523     QTRY_VERIFY(view.repaints > 0);
10524     QCOMPARE(item1->lastExposedRect, item1BoundingRect);
10525
10526     QRectF expectedItem2Expose = item2BoundingRect;
10527     // NB! Adjusted by 2 pixels for antialiasing
10528     expectedItem2Expose &= item1->mapRectToItem(item2, item1BoundingRect.adjusted(-2, -2, 2, 2));
10529     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10530
10531     // Enable ItemCoordinateCache on item1.
10532     view.reset();
10533     item1->setCacheMode(QGraphicsItem::ItemCoordinateCache);
10534     QTRY_VERIFY(view.repaints > 0);
10535     view.reset();
10536     item1->reset();
10537     item2->reset();
10538
10539     // Scroll item1:
10540     // Item1 should only get expose for the newly exposed area (accelerated scroll).
10541     // Item2 should get exposure for the part that overlaps item1.
10542     item1->scroll(0, -10, QRectF(50, 50, 100, 100));
10543     QTRY_VERIFY(view.repaints > 0);
10544     QCOMPARE(item1->lastExposedRect, QRectF(50, 140, 100, 10));
10545
10546     expectedItem2Expose = item2BoundingRect;
10547     // NB! Adjusted by 2 pixels for antialiasing
10548     expectedItem2Expose &= item1->mapRectToItem(item2, QRectF(50, 50, 100, 100).adjusted(-2, -2, 2, 2));
10549     QCOMPARE(item2->lastExposedRect, expectedItem2Expose);
10550 }
10551
10552 Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlag);
10553
10554 void tst_QGraphicsItem::focusHandling_data()
10555 {
10556     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("focusFlag");
10557     QTest::addColumn<bool>("useStickyFocus");
10558     QTest::addColumn<int>("expectedFocusItem"); // 0: none, 1: focusableUnder, 2: itemWithFocus
10559
10560     QTest::newRow("Focus goes through.")
10561         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << false << 1;
10562
10563     QTest::newRow("Focus goes through, even with sticky scene.")
10564         << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << true  << 1;
10565
10566     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (but can still focus-out).")
10567         << QGraphicsItem::ItemStopsClickFocusPropagation << false << 0;
10568
10569     QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (and cannot focus-out if scene is sticky).")
10570         << QGraphicsItem::ItemStopsClickFocusPropagation << true << 2;
10571
10572     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses.")
10573         << QGraphicsItem::ItemStopsFocusHandling << false << 2;
10574
10575     QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses (even if scene is sticky).")
10576         << QGraphicsItem::ItemStopsFocusHandling << true << 2;
10577 }
10578
10579 void tst_QGraphicsItem::focusHandling()
10580 {
10581     QFETCH(QGraphicsItem::GraphicsItemFlag, focusFlag);
10582     QFETCH(bool, useStickyFocus);
10583     QFETCH(int, expectedFocusItem);
10584
10585     class MyItem : public QGraphicsRectItem
10586     {
10587     public:
10588         MyItem() : QGraphicsRectItem(0, 0, 100, 100) {}
10589         void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
10590         {
10591             painter->fillRect(boundingRect(), hasFocus() ? QBrush(Qt::red) : brush());
10592         }
10593     };
10594
10595     QGraphicsRectItem *noFocusOnTop = new MyItem;
10596     noFocusOnTop->setFlag(QGraphicsItem::ItemIsFocusable, false);
10597     noFocusOnTop->setBrush(Qt::yellow);
10598
10599     QGraphicsRectItem *focusableUnder = new MyItem;
10600     focusableUnder->setBrush(Qt::blue);
10601     focusableUnder->setFlag(QGraphicsItem::ItemIsFocusable);
10602     focusableUnder->setPos(50, 50);
10603
10604     QGraphicsRectItem *itemWithFocus = new MyItem;
10605     itemWithFocus->setBrush(Qt::black);
10606     itemWithFocus->setFlag(QGraphicsItem::ItemIsFocusable);
10607     itemWithFocus->setPos(250, 10);
10608
10609     QGraphicsScene scene(-50, -50, 400, 400);
10610     scene.addItem(noFocusOnTop);
10611     scene.addItem(focusableUnder);
10612     scene.addItem(itemWithFocus);
10613     scene.setStickyFocus(useStickyFocus);
10614
10615     noFocusOnTop->setFlag(focusFlag);
10616     focusableUnder->stackBefore(noFocusOnTop);
10617     itemWithFocus->setFocus();
10618
10619     QGraphicsView view(&scene);
10620     view.show();
10621     QVERIFY(QTest::qWaitForWindowExposed(&view));
10622
10623     QApplication::setActiveWindow(&view);
10624     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
10625     QVERIFY(itemWithFocus->hasFocus());
10626
10627     const QPointF mousePressPoint = noFocusOnTop->mapToScene(noFocusOnTop->boundingRect().center());
10628     const QList<QGraphicsItem *> itemsAtMousePressPosition = scene.items(mousePressPoint);
10629     QVERIFY(itemsAtMousePressPosition.contains(noFocusOnTop));
10630
10631     sendMousePress(&scene, mousePressPoint);
10632
10633     switch (expectedFocusItem) {
10634     case 0:
10635         QCOMPARE(scene.focusItem(), static_cast<QGraphicsRectItem *>(0));
10636         break;
10637     case 1:
10638         QCOMPARE(scene.focusItem(), focusableUnder);
10639         break;
10640     case 2:
10641         QCOMPARE(scene.focusItem(), itemWithFocus);
10642         break;
10643     }
10644
10645     // Sanity check - manually setting the focus must work regardless of our
10646     // focus handling flags:
10647     focusableUnder->setFocus();
10648     QCOMPARE(scene.focusItem(), focusableUnder);
10649 }
10650
10651 void tst_QGraphicsItem::touchEventPropagation_data()
10652 {
10653     QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("flag");
10654     QTest::addColumn<int>("expectedCount");
10655
10656     QTest::newRow("ItemIsPanel")
10657         << QGraphicsItem::ItemIsPanel << 0;
10658     QTest::newRow("ItemStopsClickFocusPropagation")
10659         << QGraphicsItem::ItemStopsClickFocusPropagation << 1;
10660     QTest::newRow("ItemStopsFocusHandling")
10661         << QGraphicsItem::ItemStopsFocusHandling << 1;
10662 }
10663
10664 void tst_QGraphicsItem::touchEventPropagation()
10665 {
10666     QFETCH(QGraphicsItem::GraphicsItemFlag, flag);
10667     QFETCH(int, expectedCount);
10668
10669     class Testee : public QGraphicsRectItem
10670     {
10671     public:
10672         int touchBeginEventCount;
10673
10674         Testee()
10675             : QGraphicsRectItem(0, 0, 100, 100)
10676             , touchBeginEventCount(0)
10677         {
10678             setAcceptTouchEvents(true);
10679             setFlag(QGraphicsItem::ItemIsFocusable, false);
10680         }
10681
10682         bool sceneEvent(QEvent *ev)
10683         {
10684             if (ev->type() == QEvent::TouchBegin)
10685                 ++touchBeginEventCount;
10686
10687             return QGraphicsRectItem::sceneEvent(ev);
10688         }
10689     };
10690
10691     Testee *touchEventReceiver = new Testee;
10692     QGraphicsItem *topMost = new QGraphicsRectItem(touchEventReceiver->boundingRect());
10693
10694     QGraphicsScene scene;
10695     scene.addItem(topMost);
10696     scene.addItem(touchEventReceiver);
10697
10698     topMost->setAcceptTouchEvents(true);
10699     topMost->setZValue(FLT_MAX);
10700     topMost->setFlag(QGraphicsItem::ItemIsFocusable, false);
10701     topMost->setFlag(flag, true);
10702
10703     QGraphicsView view(&scene);
10704     view.setSceneRect(touchEventReceiver->boundingRect());
10705     view.show();
10706     QVERIFY(QTest::qWaitForWindowExposed(&view));
10707
10708     QCOMPARE(touchEventReceiver->touchBeginEventCount, 0);
10709
10710     QTouchEvent::TouchPoint tp(0);
10711     tp.setState(Qt::TouchPointPressed);
10712     tp.setScenePos(view.sceneRect().center());
10713     tp.setLastScenePos(view.sceneRect().center());
10714
10715     QList<QTouchEvent::TouchPoint> touchPoints;
10716     touchPoints << tp;
10717
10718     sendMousePress(&scene, tp.scenePos());
10719     QTouchDevice *device = new QTouchDevice;
10720     device->setType(QTouchDevice::TouchScreen);
10721     QWindowSystemInterface::registerTouchDevice(device);
10722     QTouchEvent touchBegin(QEvent::TouchBegin, device, Qt::NoModifier, Qt::TouchPointPressed, touchPoints);
10723
10724     qApp->sendEvent(&scene, &touchBegin);
10725     QCOMPARE(touchEventReceiver->touchBeginEventCount, expectedCount);
10726 }
10727
10728 void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations()
10729 {
10730     // Make sure we don't invalidate the cache when applying simple
10731     // (90, 180, 270, 360) rotation transforms to the item.
10732     QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 300, 200);
10733     item->setBrush(Qt::red);
10734     item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
10735
10736     QGraphicsScene scene;
10737     scene.setSceneRect(0, 0, 300, 200);
10738     scene.addItem(item);
10739
10740     MyGraphicsView view(&scene);
10741     view.show();
10742     QVERIFY(QTest::qWaitForWindowExposed(&view));
10743     QTRY_VERIFY(view.repaints > 0);
10744
10745     QGraphicsItemCache *itemCache = QGraphicsItemPrivate::get(item)->extraItemCache();
10746     QVERIFY(itemCache);
10747     QPixmapCache::Key currentKey = itemCache->deviceData.value(view.viewport()).key;
10748
10749     // Trigger an update and verify that the cache is unchanged.
10750     QPixmapCache::Key oldKey = currentKey;
10751     view.reset();
10752     view.viewport()->update();
10753     QTRY_VERIFY(view.repaints > 0);
10754     currentKey = itemCache->deviceData.value(view.viewport()).key;
10755     QCOMPARE(currentKey, oldKey);
10756
10757     // Check 90, 180, 270 and 360 degree rotations.
10758     for (int angle = 90; angle <= 360; angle += 90) {
10759         // Rotate item and verify that the cache was invalidated.
10760         oldKey = currentKey;
10761         view.reset();
10762         QTransform transform;
10763         transform.translate(150, 100);
10764         transform.rotate(angle);
10765         transform.translate(-150, -100);
10766         item->setTransform(transform);
10767         QTRY_VERIFY(view.repaints > 0);
10768         currentKey = itemCache->deviceData.value(view.viewport()).key;
10769         QVERIFY(currentKey != oldKey);
10770
10771         // IMPORTANT PART:
10772         // Trigger an update and verify that the cache is unchanged.
10773         oldKey = currentKey;
10774         view.reset();
10775         view.viewport()->update();
10776         QTRY_VERIFY(view.repaints > 0);
10777         currentKey = itemCache->deviceData.value(view.viewport()).key;
10778         QCOMPARE(currentKey, oldKey);
10779     }
10780
10781     // 45 degree rotation.
10782     oldKey = currentKey;
10783     view.reset();
10784     QTransform transform;
10785     transform.translate(150, 100);
10786     transform.rotate(45);
10787     transform.translate(-150, -100);
10788     item->setTransform(transform);
10789     QTRY_VERIFY(view.repaints > 0);
10790     currentKey = itemCache->deviceData.value(view.viewport()).key;
10791     QVERIFY(currentKey != oldKey);
10792
10793     // Trigger an update and verify that the cache was invalidated.
10794     // We should always invalidate the cache for non-trivial transforms.
10795     oldKey = currentKey;
10796     view.reset();
10797     view.viewport()->update();
10798     QTRY_VERIFY(view.repaints > 0);
10799     currentKey = itemCache->deviceData.value(view.viewport()).key;
10800     QVERIFY(currentKey != oldKey);
10801 }
10802
10803 void tst_QGraphicsItem::QTBUG_5418_textItemSetDefaultColor()
10804 {
10805     struct Item : public QGraphicsTextItem
10806     {
10807         int painted;
10808         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
10809         {
10810             painted++;
10811             QGraphicsTextItem::paint(painter, opt, wid);
10812         }
10813     };
10814
10815     Item *i = new Item;
10816     i->painted = 0;
10817     i->setPlainText("I AM A TROLL");
10818
10819     QGraphicsScene scene;
10820     QGraphicsView view(&scene);
10821     view.show();
10822     QVERIFY(QTest::qWaitForWindowExposed(&view));
10823     scene.addItem(i);
10824     QApplication::processEvents();
10825     QTRY_VERIFY(i->painted);
10826     QApplication::processEvents();
10827
10828     i->painted = 0;
10829     QColor col(Qt::red);
10830     i->setDefaultTextColor(col);
10831     QApplication::processEvents();
10832     QTRY_COMPARE(i->painted, 1); //check that changing the color force an update
10833
10834     i->painted = false;
10835     QImage image(400, 200, QImage::Format_RGB32);
10836     image.fill(0);
10837     QPainter painter(&image);
10838     scene.render(&painter);
10839     painter.end();
10840     QCOMPARE(i->painted, 1);
10841
10842     int numRedPixel = 0;
10843     QRgb rgb = col.rgb();
10844     for (int y = 0; y < image.height(); ++y) {
10845         for (int x = 0; x < image.width(); ++x) {
10846             // Because of antialiasing we allow a certain range of errors here.
10847             QRgb pixel = image.pixel(x, y);
10848             if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) +
10849                 qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) +
10850                 qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) {
10851                 if (++numRedPixel >= 10) {
10852                     return;
10853                 }
10854             }
10855         }
10856     }
10857     QCOMPARE(numRedPixel, -1); //color not found, FAIL!
10858
10859     i->painted = 0;
10860     i->setDefaultTextColor(col);
10861     QApplication::processEvents();
10862     QCOMPARE(i->painted, 0); //same color as before should not trigger an update (QTBUG-6242)
10863 }
10864
10865 void tst_QGraphicsItem::QTBUG_6738_missingUpdateWithSetParent()
10866 {
10867     // In all 3 test cases below the reparented item should disappear
10868     EventTester *parent = new EventTester;
10869     EventTester *child = new EventTester(parent);
10870     EventTester *child2 = new EventTester(parent);
10871     EventTester *child3 = new EventTester(parent);
10872     EventTester *child4 = new EventTester(parent);
10873
10874     child->setPos(10, 10);
10875     child2->setPos(20, 20);
10876     child3->setPos(30, 30);
10877     child4->setPos(40, 40);
10878
10879     QGraphicsScene scene;
10880     scene.addItem(parent);
10881
10882     MyGraphicsView view(&scene);
10883     view.show();
10884     qApp->setActiveWindow(&view);
10885     QVERIFY(QTest::qWaitForWindowActive(&view));
10886     QTRY_VERIFY(view.repaints > 0);
10887
10888     // test case #1
10889     view.reset();
10890     child2->setVisible(false);
10891     child2->setParentItem(child);
10892
10893     QTRY_VERIFY(view.repaints == 1);
10894
10895     // test case #2
10896     view.reset();
10897     child3->setOpacity(0.0);
10898     child3->setParentItem(child);
10899
10900     QTRY_VERIFY(view.repaints == 1);
10901
10902     // test case #3
10903     view.reset();
10904     child4->setParentItem(child);
10905     child4->setVisible(false);
10906
10907     QTRY_VERIFY(view.repaints == 1);
10908 }
10909
10910 void tst_QGraphicsItem::QT_2653_fullUpdateDiscardingOpacityUpdate()
10911 {
10912     QGraphicsScene scene(0, 0, 200, 200);
10913     MyGraphicsView view(&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     childYellow->setOpacity(0.0);
10926     parentGreen->setOpacity(0.0);
10927
10928     // set any of the flags below to trigger a fullUpdate to reproduce the bug:
10929     // ItemIgnoresTransformations, ItemClipsChildrenToShape, ItemIsSelectable
10930     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
10931
10932     view.show();
10933     QVERIFY(QTest::qWaitForWindowActive(&view));
10934     view.reset();
10935
10936     parentGreen->setOpacity(1.0);
10937
10938     QTRY_COMPARE(view.repaints, 1);
10939
10940     view.reset();
10941     childYellow->repaints = 0;
10942
10943     childYellow->setOpacity(1.0);
10944
10945     QTRY_COMPARE(view.repaints, 1);
10946     QTRY_COMPARE(childYellow->repaints, 1);
10947 }
10948
10949 void tst_QGraphicsItem::QTBUG_7714_fullUpdateDiscardingOpacityUpdate2()
10950 {
10951     QGraphicsScene scene(0, 0, 200, 200);
10952     MyGraphicsView view(&scene);
10953     MyGraphicsView origView(&scene);
10954
10955     EventTester *parentGreen = new EventTester();
10956     parentGreen->setGeometry(QRectF(20, 20, 100, 100));
10957     parentGreen->brush = Qt::green;
10958
10959     EventTester *childYellow = new EventTester(parentGreen);
10960     childYellow->setGeometry(QRectF(10, 10, 50, 50));
10961     childYellow->brush = Qt::yellow;
10962
10963     scene.addItem(parentGreen);
10964
10965     origView.show();
10966     QVERIFY(QTest::qWaitForWindowActive(&origView));
10967     origView.setGeometry(origView.width() + 20, 20,
10968                          origView.width(), origView.height());
10969
10970     parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations);
10971
10972     origView.reset();
10973     childYellow->setOpacity(0.0);
10974
10975     QTRY_COMPARE(origView.repaints, 1);
10976
10977     view.show();
10978     qApp->setActiveWindow(&view);
10979     QVERIFY(QTest::qWaitForWindowActive(&view));
10980     view.reset();
10981     origView.reset();
10982
10983     childYellow->setOpacity(1.0);
10984
10985     QTRY_COMPARE(origView.repaints, 1);
10986     QTRY_COMPARE(view.repaints, 1);
10987 }
10988
10989 void tst_QGraphicsItem::QT_2649_focusScope()
10990 {
10991     QGraphicsScene *scene = new QGraphicsScene;
10992
10993     QGraphicsRectItem *subFocusItem = new QGraphicsRectItem;
10994     subFocusItem->setFlags(QGraphicsItem::ItemIsFocusable);
10995     subFocusItem->setFocus();
10996     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
10997
10998     QGraphicsRectItem *scope = new QGraphicsRectItem;
10999     scope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope);
11000     scope->setFocus();
11001     subFocusItem->setParentItem(scope);
11002     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11003     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11004     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11005     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11006
11007     QGraphicsRectItem *rootItem = new QGraphicsRectItem;
11008     rootItem->setFlags(QGraphicsItem::ItemIsFocusable);
11009     scope->setParentItem(rootItem);
11010     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11011     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11012     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11013     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11014     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11015     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11016
11017     scene->addItem(rootItem);
11018
11019     QEvent windowActivate(QEvent::WindowActivate);
11020     qApp->sendEvent(scene, &windowActivate);
11021     scene->setFocus();
11022
11023     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11024     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11025     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11026     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11027     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11028     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11029     QVERIFY(subFocusItem->hasFocus());
11030
11031     scope->hide();
11032
11033     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)0);
11034     QCOMPARE(scope->focusItem(), (QGraphicsItem *)0);
11035     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)0);
11036     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11037     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11038     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11039     QVERIFY(!subFocusItem->hasFocus());
11040
11041     scope->show();
11042
11043     QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem);
11044     QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem);
11045     QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem);
11046     QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0);
11047     QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem);
11048     QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0);
11049     QVERIFY(subFocusItem->hasFocus());
11050
11051     // This should not crash
11052     scope->hide();
11053     delete scene;
11054 }
11055
11056 class MyGraphicsItemWithItemChange : public QGraphicsWidget
11057 {
11058 public:
11059     MyGraphicsItemWithItemChange(QGraphicsItem *parent = 0) : QGraphicsWidget(parent)
11060     {}
11061
11062     QVariant itemChange(GraphicsItemChange change, const QVariant &value)
11063     {
11064         if (change == QGraphicsItem::ItemSceneHasChanged) {
11065             foreach (QGraphicsView *view, scene()->views()) {
11066                 //We trigger a sort of unindexed items in the BSP
11067                 view->sceneRect();
11068             }
11069         }
11070         return QGraphicsWidget::itemChange(change, value);
11071     }
11072 };
11073
11074 void tst_QGraphicsItem::sortItemsWhileAdding()
11075 {
11076     QGraphicsScene scene;
11077     QGraphicsView view(&scene);
11078     QGraphicsWidget grandGrandParent;
11079     grandGrandParent.resize(200, 200);
11080     scene.addItem(&grandGrandParent);
11081     QGraphicsWidget grandParent;
11082     grandParent.resize(200, 200);
11083     QGraphicsWidget parent(&grandParent);
11084     parent.resize(200, 200);
11085     MyGraphicsItemWithItemChange item(&parent);
11086     grandParent.setParentItem(&grandGrandParent);
11087 }
11088
11089 void tst_QGraphicsItem::doNotMarkFullUpdateIfNotInScene()
11090 {
11091     struct Item : public QGraphicsTextItem
11092     {
11093         int painted;
11094         void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid)
11095         {
11096             painted++;
11097             QGraphicsTextItem::paint(painter, opt, wid);
11098         }
11099     };
11100     QGraphicsScene scene;
11101     MyGraphicsView view(&scene);
11102     Item *item = new Item;
11103     item->painted = 0;
11104     item->setPlainText("Grandparent");
11105     Item *item2 = new Item;
11106     item2->setPlainText("parent");
11107     item2->painted = 0;
11108     Item *item3 = new Item;
11109     item3->setPlainText("child");
11110     item3->painted = 0;
11111     QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect;
11112     effect->setOpacity(0.5);
11113     item2->setGraphicsEffect(effect);
11114     item3->setParentItem(item2);
11115     item2->setParentItem(item);
11116     scene.addItem(item);
11117     view.show();
11118     QTest::qWaitForWindowActive(view.windowHandle());
11119     view.activateWindow();
11120     QTRY_VERIFY(view.isActiveWindow());
11121     QTRY_VERIFY(view.repaints >= 1);
11122     int count = view.repaints;
11123     QTRY_COMPARE(item->painted, count);
11124     // cached as graphics effects, not painted multiple times
11125     QTRY_COMPARE(item2->painted, 1);
11126     QTRY_COMPARE(item3->painted, 1);
11127     item2->update();
11128     QApplication::processEvents();
11129     QTRY_COMPARE(item->painted, count + 1);
11130     QTRY_COMPARE(item2->painted, 2);
11131     QTRY_COMPARE(item3->painted, 2);
11132     item2->update();
11133     QApplication::processEvents();
11134     QTRY_COMPARE(item->painted, count + 2);
11135     QTRY_COMPARE(item2->painted, 3);
11136     QTRY_COMPARE(item3->painted, 3);
11137 }
11138
11139 void tst_QGraphicsItem::itemDiesDuringDraggingOperation()
11140 {
11141     QGraphicsScene scene;
11142     QGraphicsView view(&scene);
11143     QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
11144     item->setFlag(QGraphicsItem::ItemIsMovable);
11145     item->setAcceptDrops(true);
11146     scene.addItem(item);
11147     view.show();
11148     QApplication::setActiveWindow(&view);
11149     QVERIFY(QTest::qWaitForWindowActive(&view));
11150     QCOMPARE(QApplication::activeWindow(), (QWidget *)&view);
11151     QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
11152     dragEnter.setScenePos(item->boundingRect().center());
11153     QApplication::sendEvent(&scene, &dragEnter);
11154     QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragMove);
11155     event.setScenePos(item->boundingRect().center());
11156     QApplication::sendEvent(&scene, &event);
11157     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == item);
11158     delete item;
11159     QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == 0);
11160 }
11161
11162 void tst_QGraphicsItem::QTBUG_12112_focusItem()
11163 {
11164     QGraphicsScene scene;
11165     QGraphicsView view(&scene);
11166     QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20);
11167     item1->setFlag(QGraphicsItem::ItemIsFocusable);
11168     QGraphicsRectItem *item2 = new QGraphicsRectItem(20, 20, 20, 20);
11169     item2->setFlag(QGraphicsItem::ItemIsFocusable);
11170     item1->setFocus();
11171     scene.addItem(item2);
11172     scene.addItem(item1);
11173
11174     view.show();
11175     QApplication::setActiveWindow(&view);
11176     QVERIFY(QTest::qWaitForWindowActive(&view));
11177     QCOMPARE(QApplication::activeWindow(), (QWidget *)&view);
11178
11179     QVERIFY(item1->focusItem());
11180     QVERIFY(!item2->focusItem());
11181
11182     item2->setFocus();
11183     QVERIFY(!item1->focusItem());
11184     QVERIFY(item2->focusItem());
11185 }
11186
11187 void tst_QGraphicsItem::QTBUG_13473_sceneposchange()
11188 {
11189     ScenePosChangeTester* parent = new ScenePosChangeTester;
11190     ScenePosChangeTester* child = new ScenePosChangeTester(parent);
11191
11192     // parent's disabled ItemSendsGeometryChanges flag must not affect
11193     // child's scene pos change notifications
11194     parent->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
11195     child->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
11196
11197     QGraphicsScene scene;
11198     scene.addItem(parent);
11199
11200     // ignore uninteresting changes
11201     parent->clear();
11202     child->clear();
11203
11204     // move
11205     parent->moveBy(1.0, 1.0);
11206     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1);
11207
11208     // transform
11209     parent->setTransform(QTransform::fromScale(0.5, 0.5));
11210     QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2);
11211 }
11212
11213 class MyGraphicsWidget : public QGraphicsWidget {
11214 Q_OBJECT
11215 public:
11216     MyGraphicsWidget()
11217         : QGraphicsWidget(0)
11218     {
11219         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11220         QLatin1String wiseWords("AZ BUKI VEDI");
11221         QString sentence(wiseWords);
11222         QStringList words = sentence.split(QLatin1Char(' '), QString::SkipEmptyParts);
11223         for (int i = 0; i < words.count(); ++i) {
11224             QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(this);
11225             QLabel *label = new QLabel(words.at(i));
11226             proxy->setWidget(label);
11227             proxy->setFocusPolicy(Qt::StrongFocus);
11228             proxy->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
11229             if (i%2 == 0)
11230                 proxy->setVisible(false);
11231             proxy->setFocus();
11232             lay->addItem(proxy);
11233         }
11234         setLayout(lay);
11235     }
11236
11237 };
11238
11239 class MyWidgetWindow : public QGraphicsWidget
11240 {
11241 public:
11242     MyWidgetWindow()
11243         : QGraphicsWidget(0, Qt::Window)
11244     {
11245         QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Vertical);
11246         MyGraphicsWidget *widget = new MyGraphicsWidget();
11247         lay->addItem(widget);
11248         setLayout(lay);
11249     }
11250 };
11251
11252 void tst_QGraphicsItem::QTBUG_16374_crashInDestructor()
11253 {
11254     QGraphicsScene scene;
11255     QGraphicsView view(&scene);
11256
11257     MyWidgetWindow win;
11258     scene.addItem(&win);
11259
11260     view.show();
11261     QVERIFY(QTest::qWaitForWindowExposed(&view));
11262 }
11263
11264 void tst_QGraphicsItem::QTBUG_20699_focusScopeCrash()
11265 {
11266     QGraphicsScene scene;
11267     QGraphicsView view(&scene);
11268     QGraphicsPixmapItem fs;
11269     fs.setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11270     scene.addItem(&fs);
11271     QGraphicsPixmapItem* fs2 = new QGraphicsPixmapItem(&fs);
11272     fs2->setFlags(QGraphicsItem::ItemIsFocusScope | QGraphicsItem::ItemIsFocusable);
11273     QGraphicsPixmapItem* fi2 = new QGraphicsPixmapItem(&fs);
11274     fi2->setFlags(QGraphicsItem::ItemIsFocusable);
11275     QGraphicsPixmapItem* fi = new QGraphicsPixmapItem(fs2);
11276     fi->setFlags(QGraphicsItem::ItemIsFocusable);
11277     fs.setFocus();
11278     fi->setFocus();
11279
11280     view.show();
11281     QVERIFY(QTest::qWaitForWindowExposed(&view));
11282
11283     fi->setParentItem(fi2);
11284     fi->setFocus();
11285     fs.setFocus();
11286     fi->setParentItem(fs2);
11287     fi->setFocus();
11288     fs2->setFocus();
11289     fs.setFocus();
11290     fi->setParentItem(fi2);
11291     fi->setFocus();
11292     fs.setFocus();
11293 }
11294
11295 QTEST_MAIN(tst_QGraphicsItem)
11296 #include "tst_qgraphicsitem.moc"