474ac47ea1d5459731735c423114e0ce9b13d25d
[profile/ivi/qtbase.git] / tests / auto / widgets / graphicsview / qgraphicsview / tst_qgraphicsview.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 <qgraphicsitem.h>
46 #include <qgraphicsscene.h>
47 #include <qgraphicssceneevent.h>
48 #include <qgraphicsview.h>
49 #include <qgraphicswidget.h>
50 #include <qgraphicsproxywidget.h>
51
52 #include <math.h>
53
54 #include <QtWidgets/QLabel>
55 #if !defined(QT_NO_STYLE_WINDOWS)
56 #include <QtWidgets/QWindowsStyle>
57 #endif
58 #if !defined(QT_NO_STYLE_PLASTIQUE)
59 #include <QtWidgets/QPlastiqueStyle>
60 #endif
61 #include <QtGui/QPainterPath>
62 #include <QtWidgets/QRubberBand>
63 #include <QtWidgets/QScrollBar>
64 #include <QtWidgets/QStyleOption>
65 #include <QtWidgets/QBoxLayout>
66 #include <QtWidgets/QStyle>
67 #include <QtWidgets/QPushButton>
68 #include <QtWidgets/QDesktopWidget>
69 #include <private/qgraphicsscene_p.h>
70 #include <private/qgraphicsview_p.h>
71 #include "../../../shared/platforminputcontext.h"
72 #include <private/qinputmethod_p.h>
73
74 #include "../../../qtest-config.h"
75
76 Q_DECLARE_METATYPE(QList<int>)
77 Q_DECLARE_METATYPE(QList<QRectF>)
78 Q_DECLARE_METATYPE(QMatrix)
79 Q_DECLARE_METATYPE(QPainterPath)
80 Q_DECLARE_METATYPE(QPointF)
81 Q_DECLARE_METATYPE(QPolygonF)
82 Q_DECLARE_METATYPE(QRectF)
83 Q_DECLARE_METATYPE(Qt::ScrollBarPolicy)
84
85 #ifdef Q_OS_MAC
86 //On mac we get full update. So check that the expected region is contained inside the actual
87 #define COMPARE_REGIONS(ACTUAL, EXPECTED) QVERIFY((EXPECTED).subtracted(ACTUAL).isEmpty())
88 #else
89 #define COMPARE_REGIONS QCOMPARE
90 #endif
91
92 static void sendMousePress(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton)
93 {
94     QMouseEvent event(QEvent::MouseButtonPress, point, widget->mapToGlobal(point), button, 0, 0);
95     QApplication::sendEvent(widget, &event);
96 }
97
98 static void sendMouseMove(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons buttons = 0)
99 {
100     QTest::mouseMove(widget, point);
101     QMouseEvent event(QEvent::MouseMove, point, button, buttons, 0);
102     QApplication::sendEvent(widget, &event);
103     QApplication::processEvents();
104 }
105
106 static void sendMouseRelease(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton)
107 {
108     QMouseEvent event(QEvent::MouseButtonRelease, point, widget->mapToGlobal(point), button, 0, 0);
109     QApplication::sendEvent(widget, &event);
110 }
111
112 class EventSpy : public QObject
113 {
114     Q_OBJECT
115 public:
116     EventSpy(QObject *watched, QEvent::Type type)
117         : _count(0), spied(type)
118     {
119         watched->installEventFilter(this);
120     }
121
122     int count() const { return _count; }
123     void reset() { _count = 0; }
124
125 protected:
126     bool eventFilter(QObject *watched, QEvent *event)
127     {
128         Q_UNUSED(watched);
129         if (event->type() == spied)
130             ++_count;
131         return false;
132     }
133
134     int _count;
135     QEvent::Type spied;
136 };
137
138 #if defined QT_BUILD_INTERNAL
139 class FriendlyGraphicsScene : public QGraphicsScene
140 {
141     friend class tst_QGraphicsView;
142     Q_DECLARE_PRIVATE(QGraphicsScene);
143 };
144 #endif
145
146 class tst_QGraphicsView : public QObject
147 {
148     Q_OBJECT
149
150 private slots:
151     void initTestCase();
152     void cleanup();
153     void construction();
154     void renderHints();
155     void alignment();
156     void interactive();
157     void scene();
158     void setScene();
159     void deleteScene();
160     void sceneRect();
161     void sceneRect_growing();
162     void setSceneRect();
163     void viewport();
164     void dragMode_scrollHand();
165     void dragMode_rubberBand();
166     void rubberBandSelectionMode();
167     void backgroundBrush();
168     void foregroundBrush();
169     void matrix();
170     void matrix_convenience();
171     void matrix_combine();
172     void centerOnPoint();
173     void centerOnItem();
174     void ensureVisibleRect();
175     void fitInView();
176     void itemsAtPoint();
177 #if defined QT_BUILD_INTERNAL
178     void itemsAtPosition_data();
179     void itemsAtPosition();
180 #endif
181     void itemsInRect();
182     void itemsInRect_cosmeticAdjust_data();
183     void itemsInRect_cosmeticAdjust();
184     void itemsInPoly();
185     void itemsInPath();
186     void itemAt();
187     void itemAt2();
188     void mapToScene();
189     void mapToScenePoint();
190     void mapToSceneRect_data();
191     void mapToSceneRect();
192     void mapToScenePoly();
193     void mapToScenePath();
194     void mapFromScenePoint();
195     void mapFromSceneRect();
196     void mapFromScenePoly();
197     void mapFromScenePath();
198     void sendEvent();
199     void wheelEvent();
200 #ifndef QTEST_NO_CURSOR
201     void cursor();
202     void cursor2();
203 #endif
204     void transformationAnchor();
205     void resizeAnchor();
206     void viewportUpdateMode();
207     void viewportUpdateMode2();
208 #ifndef QT_NO_DRAGANDDROP
209     void acceptDrops();
210 #endif
211     void optimizationFlags();
212     void optimizationFlags_dontSavePainterState();
213     void optimizationFlags_dontSavePainterState2_data();
214     void optimizationFlags_dontSavePainterState2();
215     void levelOfDetail_data();
216     void levelOfDetail();
217     void scrollBarRanges_data();
218     void scrollBarRanges();
219     void acceptMousePressEvent();
220     void replayMouseMove();
221     void itemsUnderMouse();
222     void embeddedViews();
223     void scrollAfterResize_data();
224     void scrollAfterResize();
225     void moveItemWhileScrolling_data();
226     void moveItemWhileScrolling();
227     void centerOnDirtyItem();
228     void mouseTracking();
229     void mouseTracking2();
230     void mouseTracking3();
231     void render();
232     void exposeRegion();
233     void update_data();
234     void update();
235     void update2_data();
236     void update2();
237     void update_ancestorClipsChildrenToShape();
238     void update_ancestorClipsChildrenToShape2();
239     void inputMethodSensitivity();
240     void inputContextReset();
241     void indirectPainting();
242     void compositionModeInDrawBackground();
243
244     // task specific tests below me
245     void task172231_untransformableItems();
246     void task180429_mouseReleaseDragMode();
247     void task187791_setSceneCausesUpdate();
248     void task186827_deleteReplayedItem();
249     void task207546_focusCrash();
250     void task210599_unsetDragWhileDragging();
251     void task236394_sendShortcutOverrideEvent();
252     void task239729_noViewUpdate_data();
253     void task239729_noViewUpdate();
254     void task239047_fitInViewSmallViewport();
255     void task245469_itemsAtPointWithClip();
256     void task253415_reconnectUpdateSceneOnSceneChanged();
257     void task255529_transformationAnchorMouseAndViewportMargins();
258     void task259503_scrollingArtifacts();
259     void QTBUG_4151_clipAndIgnore_data();
260     void QTBUG_4151_clipAndIgnore();
261     void QTBUG_5859_exposedRect();
262 #ifndef QTEST_NO_CURSOR
263     void QTBUG_7438_cursor();
264 #endif
265     void hoverLeave();
266     void QTBUG_16063_microFocusRect();
267
268 public slots:
269     void dummySlot() {}
270 };
271
272 void tst_QGraphicsView::initTestCase()
273 {
274 #ifdef Q_OS_WINCE_WM
275     qApp->setAutoMaximizeThreshold(-1);
276 #endif
277 }
278
279 void tst_QGraphicsView::cleanup()
280 {
281     // ensure not even skipped tests with custom input context leave it dangling
282     QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
283     inputMethodPrivate->testContext = 0;
284 }
285
286 void tst_QGraphicsView::construction()
287 {
288     QGraphicsView view;
289     QCOMPARE(view.renderHints(), QPainter::TextAntialiasing);
290     QCOMPARE(view.dragMode(), QGraphicsView::NoDrag);
291     QVERIFY(view.isInteractive());
292     QVERIFY(!view.scene());
293     QCOMPARE(view.sceneRect(), QRectF());
294     QVERIFY(view.viewport());
295     QCOMPARE(view.viewport()->metaObject()->className(), "QWidget");
296     QCOMPARE(view.matrix(), QMatrix());
297     QVERIFY(view.items().isEmpty());
298     QVERIFY(view.items(QPoint()).isEmpty());
299     QVERIFY(view.items(QRect()).isEmpty());
300     QVERIFY(view.items(QPolygon()).isEmpty());
301     QVERIFY(view.items(QPainterPath()).isEmpty());
302     QVERIFY(!view.itemAt(QPoint()));
303     QCOMPARE(view.mapToScene(QPoint()), QPointF());
304     QCOMPARE(view.mapToScene(QRect()), QPolygonF());
305     QCOMPARE(view.mapToScene(QPolygon()), QPolygonF());
306     QCOMPARE(view.mapFromScene(QPointF()), QPoint());
307     QPolygon poly;
308     poly << QPoint() << QPoint() << QPoint() << QPoint();
309     QCOMPARE(view.mapFromScene(QRectF()), poly);
310     QCOMPARE(view.mapFromScene(QPolygonF()), QPolygon());
311     QCOMPARE(view.transformationAnchor(), QGraphicsView::AnchorViewCenter);
312     QCOMPARE(view.resizeAnchor(), QGraphicsView::NoAnchor);
313     view.show();
314     QVERIFY(QTest::qWaitForWindowExposed(&view));
315 }
316
317 class TestItem : public QGraphicsItem
318 {
319 public:
320     QRectF boundingRect() const
321     { return QRectF(-10, -10, 20, 20); }
322
323     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
324     { hints = painter->renderHints(); painter->drawRect(boundingRect()); }
325
326     bool sceneEvent(QEvent *event)
327     {
328         events << event->type();
329         return QGraphicsItem::sceneEvent(event);
330     }
331
332     QList<QEvent::Type> events;
333     QPainter::RenderHints hints;
334 };
335
336 void tst_QGraphicsView::renderHints()
337 {
338     QGraphicsView view;
339     QCOMPARE(view.renderHints(), QPainter::TextAntialiasing);
340     view.setRenderHint(QPainter::TextAntialiasing, false);
341     QCOMPARE(view.renderHints(), 0);
342     view.setRenderHint(QPainter::Antialiasing, false);
343     QCOMPARE(view.renderHints(), 0);
344     view.setRenderHint(QPainter::TextAntialiasing, true);
345     QCOMPARE(view.renderHints(), QPainter::TextAntialiasing);
346     view.setRenderHint(QPainter::Antialiasing);
347     QCOMPARE(view.renderHints(), QPainter::TextAntialiasing | QPainter::Antialiasing);
348     view.setRenderHints(0);
349     QCOMPARE(view.renderHints(), 0);
350
351     TestItem *item = new TestItem;
352     QGraphicsScene scene;
353     scene.addItem(item);
354
355     view.setScene(&scene);
356
357     view.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen);
358     QCOMPARE(view.renderHints(), QPainter::TextAntialiasing | QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen);
359
360     QCOMPARE(item->hints, 0);
361     view.show();
362     QVERIFY(QTest::qWaitForWindowExposed(&view));
363     view.repaint();
364     QTRY_COMPARE(item->hints, view.renderHints());
365
366     view.setRenderHints(QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen);
367     QCOMPARE(view.renderHints(), QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen);
368
369     view.repaint();
370     QTRY_COMPARE(item->hints, view.renderHints());
371 }
372
373 void tst_QGraphicsView::alignment()
374 {
375     QGraphicsScene scene;
376     scene.addRect(QRectF(-10, -10, 20, 20));
377
378     QGraphicsView view(&scene);
379     view.show();
380     QVERIFY(QTest::qWaitForWindowExposed(&view));
381
382     for (int i = 0; i < 3; ++i) {
383         for (int j = 0; j < 3; ++j) {
384             Qt::Alignment alignment = 0;
385             switch (i) {
386             case 0:
387                 alignment |= Qt::AlignLeft;
388                 break;
389             case 1:
390                 alignment |= Qt::AlignHCenter;
391                 break;
392             case 2:
393             default:
394                 alignment |= Qt::AlignRight;
395                 break;
396             }
397             switch (j) {
398             case 0:
399                 alignment |= Qt::AlignTop;
400                 break;
401             case 1:
402                 alignment |= Qt::AlignVCenter;
403                 break;
404             case 2:
405             default:
406                 alignment |= Qt::AlignBottom;
407                 break;
408             }
409             view.setAlignment(alignment);
410             QCOMPARE(view.alignment(), alignment);
411
412             for (int k = 0; k < 3; ++k) {
413                 view.resize(100 + k * 25, 100 + k * 25);
414                 QApplication::processEvents();
415             }
416         }
417     }
418 }
419
420 void tst_QGraphicsView::interactive()
421 {
422     TestItem *item = new TestItem;
423     item->setFlags(QGraphicsItem::ItemIsMovable);
424     QCOMPARE(item->events.size(), 0);
425
426     QGraphicsScene scene(-200, -200, 400, 400);
427     scene.addItem(item);
428
429     QGraphicsView view(&scene);
430     view.setFixedSize(300, 300);
431     QCOMPARE(item->events.size(), 0);
432     view.show();
433     view.activateWindow();
434     QVERIFY(QTest::qWaitForWindowActive(&view));
435
436     QTRY_COMPARE(item->events.size(), 1); // activate
437
438     QPoint itemPoint = view.mapFromScene(item->scenePos());
439
440     QVERIFY(view.itemAt(itemPoint));
441
442     for (int i = 0; i < 100; ++i) {
443         sendMousePress(view.viewport(), itemPoint);
444         QCOMPARE(item->events.size(), i * 5 + 3);
445         QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GrabMouse);
446         QCOMPARE(item->events.at(item->events.size() - 1), QEvent::GraphicsSceneMousePress);
447         sendMouseRelease(view.viewport(), itemPoint);
448         QCOMPARE(item->events.size(), i * 5 + 5);
449         QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GraphicsSceneMouseRelease);
450         QCOMPARE(item->events.at(item->events.size() - 1), QEvent::UngrabMouse);
451         QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, itemPoint, view.mapToGlobal(itemPoint));
452         QApplication::sendEvent(view.viewport(), &contextEvent);
453         QCOMPARE(item->events.size(), i * 5 + 6);
454         QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu);
455     }
456
457     view.setInteractive(false);
458
459     for (int i = 0; i < 100; ++i) {
460         sendMousePress(view.viewport(), itemPoint);
461         QCOMPARE(item->events.size(), 501);
462         QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu);
463         sendMouseRelease(view.viewport(), itemPoint);
464         QCOMPARE(item->events.size(), 501);
465         QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu);
466         QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, itemPoint, view.mapToGlobal(itemPoint));
467         QApplication::sendEvent(view.viewport(), &contextEvent);
468         QCOMPARE(item->events.size(), 501);
469         QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu);
470     }
471 }
472
473 void tst_QGraphicsView::scene()
474 {
475     QGraphicsView view;
476     QVERIFY(!view.scene());
477     view.setScene(0);
478     QVERIFY(!view.scene());
479
480     {
481         QGraphicsScene scene;
482         view.setScene(&scene);
483         QCOMPARE(view.scene(), &scene);
484     }
485
486     QCOMPARE(view.scene(), (QGraphicsScene *)0);
487 }
488
489 void tst_QGraphicsView::setScene()
490 {
491     QGraphicsScene scene(-1000, -1000, 2000, 2000);
492
493     QGraphicsView view(&scene);
494     view.show();
495     QVERIFY(QTest::qWaitForWindowExposed(&view));
496
497     QCOMPARE(view.sceneRect(), scene.sceneRect());
498
499     QVERIFY(view.horizontalScrollBar()->isVisible());
500     QVERIFY(view.verticalScrollBar()->isVisible());
501     QVERIFY(!view.horizontalScrollBar()->isHidden());
502     QVERIFY(!view.verticalScrollBar()->isHidden());
503
504     view.setScene(0);
505
506     QTest::qWait(25);
507
508     QVERIFY(!view.horizontalScrollBar()->isVisible());
509     QVERIFY(!view.verticalScrollBar()->isVisible());
510     QVERIFY(!view.horizontalScrollBar()->isHidden());
511     QVERIFY(!view.verticalScrollBar()->isHidden());
512
513     QCOMPARE(view.sceneRect(), QRectF());
514 }
515
516 void tst_QGraphicsView::deleteScene()
517 {
518     QGraphicsScene *scene = new QGraphicsScene;
519     QGraphicsView view1(scene);
520     view1.show();
521     QGraphicsView view2(scene);
522     view2.show();
523     QGraphicsView view3(scene);
524     view3.show();
525     delete scene;
526     QCOMPARE(view1.scene(), (QGraphicsScene *)0);
527     QCOMPARE(view2.scene(), (QGraphicsScene *)0);
528     QCOMPARE(view3.scene(), (QGraphicsScene *)0);
529 }
530
531 void tst_QGraphicsView::sceneRect()
532 {
533     QGraphicsView view;
534     QCOMPARE(view.sceneRect(), QRectF());
535
536     view.setSceneRect(QRectF(-100, -100, 200, 200));
537     QCOMPARE(view.sceneRect(), QRectF(-100, -100, 200, 200));
538     view.setSceneRect(-100, -100, 200, 200);
539     QCOMPARE(view.sceneRect(), QRectF(-100, -100, 200, 200));
540
541     view.setSceneRect(QRectF());
542     QCOMPARE(view.sceneRect(), QRectF());
543     QGraphicsScene scene;
544     QGraphicsRectItem *item = scene.addRect(QRectF(-100, -100, 100, 100));
545
546     view.setScene(&scene);
547
548     QCOMPARE(view.sceneRect(), QRectF(-100, -100, 100, 100));
549     item->moveBy(-100, -100);
550     QCOMPARE(view.sceneRect(), QRectF(-200, -200, 200, 200));
551     item->moveBy(100, 100);
552     QCOMPARE(view.sceneRect(), QRectF(-200, -200, 200, 200));
553
554     view.setScene(0);
555     view.setSceneRect(QRectF());
556     QCOMPARE(view.sceneRect(), QRectF());
557 }
558
559 void tst_QGraphicsView::sceneRect_growing()
560 {
561     QWidget toplevel;
562
563     QGraphicsScene scene;
564     for (int i = 0; i < 100; ++i)
565         scene.addText(QString("(0, %1)").arg((i - 50) * 20))->setPos(0, (i - 50) * 20);
566
567     QGraphicsView view(&scene, &toplevel);
568     view.setFixedSize(200, 200);
569     toplevel.show();
570
571     int size = 200;
572     scene.setSceneRect(-size, -size, size * 2, size * 2);
573     QCOMPARE(view.sceneRect(), scene.sceneRect());
574
575     QTest::qWait(25);
576
577     QPointF topLeft = view.mapToScene(0, 0);
578
579     for (int i = 0; i < 5; ++i) {
580         size *= 2;
581         scene.setSceneRect(-size, -size, size * 2, size * 2);
582
583         QApplication::processEvents();
584
585         QCOMPARE(view.sceneRect(), scene.sceneRect());
586         QCOMPARE(view.mapToScene(0, 0), topLeft);
587         view.setSceneRect(-size, -size, size * 2, size * 2);
588         QCOMPARE(view.mapToScene(0, 0), topLeft);
589         view.setSceneRect(QRectF());
590     }
591 }
592
593 void tst_QGraphicsView::setSceneRect()
594 {
595     QRectF rect1(-100, -100, 200, 200);
596     QRectF rect2(-300, -300, 150, 150);
597
598     QGraphicsScene scene;
599     QGraphicsView view(&scene);
600
601     scene.setSceneRect(rect1);
602     QCOMPARE(scene.sceneRect(), rect1);
603     QCOMPARE(view.sceneRect(), rect1);
604
605     scene.setSceneRect(rect2);
606     QCOMPARE(scene.sceneRect(), rect2);
607     QCOMPARE(view.sceneRect(), rect2);
608
609     view.setSceneRect(rect1);
610     QCOMPARE(scene.sceneRect(), rect2);
611     QCOMPARE(view.sceneRect(), rect1);
612
613     view.setSceneRect(rect2);
614     QCOMPARE(scene.sceneRect(), rect2);
615     QCOMPARE(view.sceneRect(), rect2);
616
617     scene.setSceneRect(rect1);
618     QCOMPARE(scene.sceneRect(), rect1);
619     QCOMPARE(view.sceneRect(), rect2);
620
621     // extreme transformations will max out the scrollbars' ranges.
622     view.setSceneRect(-2000000, -2000000, 4000000, 4000000);
623     view.scale(9000, 9000);
624     QCOMPARE(view.horizontalScrollBar()->minimum(), INT_MIN);
625     QCOMPARE(view.horizontalScrollBar()->maximum(), INT_MAX);
626     QCOMPARE(view.verticalScrollBar()->minimum(), INT_MIN);
627     QCOMPARE(view.verticalScrollBar()->maximum(), INT_MAX);
628 }
629
630 void tst_QGraphicsView::viewport()
631 {
632     QGraphicsScene scene;
633     scene.addText("GraphicsView");
634
635     QGraphicsView view(&scene);
636     QVERIFY(view.viewport() != 0);
637
638     view.show();
639     QTest::qWait(25);
640
641     QPointer<QWidget> widget = new QWidget;
642     view.setViewport(widget);
643     QCOMPARE(view.viewport(), (QWidget *)widget);
644
645     view.show();
646     QTest::qWait(25);
647
648     view.setViewport(0);
649     QVERIFY(widget.isNull());
650     QVERIFY(view.viewport() != 0);
651     QVERIFY(view.viewport() != widget);
652
653     view.show();
654     QTest::qWait(25);
655 }
656
657 void tst_QGraphicsView::dragMode_scrollHand()
658 {
659     for (int j = 0; j < 2; ++j) {
660         QGraphicsView view;
661         QCOMPARE(view.dragMode(), QGraphicsView::NoDrag);
662
663         view.setSceneRect(-1000, -1000, 2000, 2000);
664         view.setFixedSize(100, 100);
665         view.show();
666
667         QVERIFY(QTest::qWaitForWindowExposed(&view));
668         QApplication::processEvents();
669
670         view.setInteractive(j ? false : true);
671
672         QGraphicsScene scene;
673         scene.addRect(QRectF(-100, -100, 5, 5));
674         scene.addRect(QRectF(95, -100, 5, 5));
675         scene.addRect(QRectF(95, 95, 5, 5));
676         QGraphicsItem *item = scene.addRect(QRectF(-100, 95, 5, 5));
677         item->setFlag(QGraphicsItem::ItemIsSelectable);
678         item->setSelected(true);
679         QVERIFY(item->isSelected());
680         QVERIFY(!view.scene());
681
682         view.setDragMode(QGraphicsView::ScrollHandDrag);
683
684         for (int i = 0; i < 2; ++i) {
685             // ScrollHandDrag
686 #ifndef QTEST_NO_CURSOR
687             Qt::CursorShape cursorShape = view.viewport()->cursor().shape();
688 #endif
689             int horizontalScrollBarValue = view.horizontalScrollBar()->value();
690             int verticalScrollBarValue = view.verticalScrollBar()->value();
691             {
692                 // Press
693                 QMouseEvent event(QEvent::MouseButtonPress,
694                                   view.viewport()->rect().center(),
695                                   Qt::LeftButton, Qt::LeftButton, 0);
696                 event.setAccepted(true);
697                 QApplication::sendEvent(view.viewport(), &event);
698                 QVERIFY(event.isAccepted());
699             }
700             QApplication::processEvents();
701
702             QTRY_VERIFY(item->isSelected());
703
704             for (int k = 0; k < 4; ++k) {
705 #ifndef QTEST_NO_CURSOR
706                 QCOMPARE(view.viewport()->cursor().shape(), Qt::ClosedHandCursor);
707 #endif
708                 {
709                     // Move
710                     QMouseEvent event(QEvent::MouseMove,
711                                       view.viewport()->rect().center() + QPoint(10, 0),
712                                       Qt::LeftButton, Qt::LeftButton, 0);
713                     event.setAccepted(true);
714                     QApplication::sendEvent(view.viewport(), &event);
715                     QVERIFY(event.isAccepted());
716                 }
717                 QVERIFY(item->isSelected());
718                 QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue - 10);
719                 QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue);
720                 {
721                     // Move
722                     QMouseEvent event(QEvent::MouseMove,
723                                       view.viewport()->rect().center() + QPoint(10, 10),
724                                       Qt::LeftButton, Qt::LeftButton, 0);
725                     event.setAccepted(true);
726                     QApplication::sendEvent(view.viewport(), &event);
727                     QVERIFY(event.isAccepted());
728                 }
729                 QVERIFY(item->isSelected());
730                 QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue - 10);
731                 QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue - 10);
732             }
733
734             {
735                 // Release
736                 QMouseEvent event(QEvent::MouseButtonRelease,
737                                   view.viewport()->rect().center() + QPoint(10, 10),
738                                   Qt::LeftButton, Qt::LeftButton, 0);
739                 event.setAccepted(true);
740                 QApplication::sendEvent(view.viewport(), &event);
741                 QVERIFY(event.isAccepted());
742             }
743             QApplication::processEvents();
744
745             QTRY_VERIFY(item->isSelected());
746             QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue - 10);
747             QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue - 10);
748 #ifndef QTEST_NO_CURSOR
749             QCOMPARE(view.viewport()->cursor().shape(), cursorShape);
750 #endif
751
752             // Check that items are not unselected because of a scroll hand drag.
753             QVERIFY(item->isSelected());
754
755             // Check that a click will still unselect the item.
756             {
757                 // Press
758                 QMouseEvent event(QEvent::MouseButtonPress,
759                                   view.viewport()->rect().center() + QPoint(10, 10),
760                                   Qt::LeftButton, Qt::LeftButton, 0);
761                 QApplication::sendEvent(view.viewport(), &event);
762             }
763             {
764                 // Release
765                 QMouseEvent event(QEvent::MouseButtonRelease,
766                                   view.viewport()->rect().center() + QPoint(10, 10),
767                                   Qt::LeftButton, Qt::LeftButton, 0);
768                 QApplication::sendEvent(view.viewport(), &event);
769             }
770
771             if (view.isInteractive()) {
772                 if (view.scene()) {
773                     QVERIFY(!item->isSelected());
774                     item->setSelected(true);
775                 } else {
776                     QVERIFY(item->isSelected());
777                 }
778             } else {
779                 QVERIFY(item->isSelected());
780             }
781
782             view.setScene(&scene);
783         }
784     }
785 }
786
787 void tst_QGraphicsView::dragMode_rubberBand()
788 {
789     QGraphicsView view;
790     QCOMPARE(view.dragMode(), QGraphicsView::NoDrag);
791
792     view.setSceneRect(-1000, -1000, 2000, 2000);
793     view.show();
794
795     QGraphicsScene scene;
796     scene.addRect(QRectF(-100, -100, 25, 25))->setFlag(QGraphicsItem::ItemIsSelectable);
797     scene.addRect(QRectF(75, -100, 25, 25))->setFlag(QGraphicsItem::ItemIsSelectable);
798     scene.addRect(QRectF(75, 75, 25, 25))->setFlag(QGraphicsItem::ItemIsSelectable);
799     scene.addRect(QRectF(-100, 75, 25, 25))->setFlag(QGraphicsItem::ItemIsSelectable);
800
801     view.setDragMode(QGraphicsView::RubberBandDrag);
802
803     QVERIFY(QTest::qWaitForWindowExposed(&view));
804     QApplication::processEvents();
805
806     for (int i = 0; i < 2; ++i) {
807         // RubberBandDrag
808 #ifndef QTEST_NO_CURSOR
809         Qt::CursorShape cursorShape = view.viewport()->cursor().shape();
810 #endif
811         int horizontalScrollBarValue = view.horizontalScrollBar()->value();
812         int verticalScrollBarValue = view.verticalScrollBar()->value();
813         {
814             // Press
815             QMouseEvent event(QEvent::MouseButtonPress,
816                               view.viewport()->rect().center(),
817                               Qt::LeftButton, Qt::LeftButton, 0);
818             event.setAccepted(true);
819             QApplication::sendEvent(view.viewport(), &event);
820             QVERIFY(event.isAccepted());
821         }
822 #ifndef QTEST_NO_CURSOR
823         QCOMPARE(view.viewport()->cursor().shape(), cursorShape);
824 #endif
825
826         QApplication::processEvents();
827
828         {
829             // Move
830             QMouseEvent event(QEvent::MouseMove,
831                               view.viewport()->rect().center() + QPoint(100, 0),
832                               Qt::LeftButton, Qt::LeftButton, 0);
833             event.setAccepted(true);
834             QApplication::sendEvent(view.viewport(), &event);
835             QVERIFY(event.isAccepted());
836         }
837         QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue);
838         QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue);
839
840         // We don't use QRubberBand as of 4.3; the band is drawn internally.
841         QVERIFY(!qFindChild<QRubberBand *>(&view));
842
843         QTest::qWait(25);
844
845         {
846             // Move
847             QMouseEvent event(QEvent::MouseMove,
848                               view.viewport()->rect().center() + QPoint(100, 100),
849                               Qt::LeftButton, Qt::LeftButton, 0);
850             event.setAccepted(true);
851             QApplication::sendEvent(view.viewport(), &event);
852             QVERIFY(event.isAccepted());
853         }
854         QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue);
855         QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue);
856
857         QTest::qWait(25);
858
859         {
860             // Release
861             QMouseEvent event(QEvent::MouseButtonRelease,
862                               view.viewport()->rect().center() + QPoint(100, 100),
863                               Qt::LeftButton, Qt::LeftButton, 0);
864             event.setAccepted(true);
865             QApplication::sendEvent(view.viewport(), &event);
866             QVERIFY(event.isAccepted());
867         }
868         QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue);
869         QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue);
870 #ifndef QTEST_NO_CURSOR
871         QCOMPARE(view.viewport()->cursor().shape(), cursorShape);
872 #endif
873
874         QTest::qWait(25);
875
876         if (view.scene())
877             QCOMPARE(scene.selectedItems().size(), 1);
878
879         view.setScene(&scene);
880         view.centerOn(0, 0);
881     }
882 }
883
884 void tst_QGraphicsView::rubberBandSelectionMode()
885 {
886     QWidget toplevel;
887
888     QGraphicsScene scene;
889     QGraphicsRectItem *rect = scene.addRect(QRectF(10, 10, 80, 80));
890     rect->setFlag(QGraphicsItem::ItemIsSelectable);
891
892     QGraphicsView view(&scene, &toplevel);
893     QCOMPARE(view.rubberBandSelectionMode(), Qt::IntersectsItemShape);
894     view.setDragMode(QGraphicsView::RubberBandDrag);
895     view.resize(120, 120);
896     toplevel.show();
897
898     // Disable mouse tracking to prevent the window system from sending mouse
899     // move events to the viewport while we are synthesizing events. If
900     // QGraphicsView gets a mouse move event with no buttons down, it'll
901     // terminate the rubber band.
902     view.viewport()->setMouseTracking(false);
903
904     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>());
905     sendMousePress(view.viewport(), QPoint(), Qt::LeftButton);
906     sendMouseMove(view.viewport(), view.viewport()->rect().center(),
907                   Qt::LeftButton, Qt::LeftButton);
908     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << rect);
909     sendMouseRelease(view.viewport(), QPoint(), Qt::LeftButton);
910
911     view.setRubberBandSelectionMode(Qt::ContainsItemShape);
912     QCOMPARE(view.rubberBandSelectionMode(), Qt::ContainsItemShape);
913     sendMousePress(view.viewport(), QPoint(), Qt::LeftButton);
914     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>());
915     sendMouseMove(view.viewport(), view.viewport()->rect().center(),
916                   Qt::LeftButton, Qt::LeftButton);
917     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>());
918     sendMouseMove(view.viewport(), view.viewport()->rect().bottomRight(),
919                   Qt::LeftButton, Qt::LeftButton);
920     QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << rect);
921 }
922
923 void tst_QGraphicsView::backgroundBrush()
924 {
925     QGraphicsScene scene;
926     QGraphicsView view(&scene);
927     scene.setBackgroundBrush(Qt::blue);
928     QCOMPARE(scene.backgroundBrush(), QBrush(Qt::blue));
929
930     view.show();
931     QTest::qWait(25);
932
933     scene.setBackgroundBrush(QBrush());
934     QCOMPARE(scene.backgroundBrush(), QBrush());
935     QTest::qWait(25);
936
937     QRadialGradient gradient(0, 0, 10);
938     gradient.setSpread(QGradient::RepeatSpread);
939     scene.setBackgroundBrush(gradient);
940
941     QCOMPARE(scene.backgroundBrush(), QBrush(gradient));
942     QTest::qWait(25);
943 }
944
945 void tst_QGraphicsView::foregroundBrush()
946 {
947     QGraphicsScene scene;
948     QGraphicsView view(&scene);
949     scene.setForegroundBrush(Qt::blue);
950     QCOMPARE(scene.foregroundBrush(), QBrush(Qt::blue));
951
952     view.show();
953     QTest::qWait(25);
954
955     scene.setForegroundBrush(QBrush());
956     QCOMPARE(scene.foregroundBrush(), QBrush());
957     QTest::qWait(25);
958
959     QRadialGradient gradient(0, 0, 10);
960     gradient.setSpread(QGradient::RepeatSpread);
961     scene.setForegroundBrush(gradient);
962
963     QCOMPARE(scene.foregroundBrush(), QBrush(gradient));
964     QTest::qWait(25);
965
966     for (int i = 0; i < 50; ++i) {
967         QRadialGradient gradient(view.rect().center() + QPoint(int(sin(i / 2.0) * 10), int(cos(i / 2.0) * 10)), 10);
968         gradient.setColorAt(0, Qt::transparent);
969         gradient.setColorAt(0.5, Qt::black);
970         gradient.setColorAt(1, Qt::transparent);
971         gradient.setSpread(QGradient::RepeatSpread);
972         scene.setForegroundBrush(gradient);
973
974         QRadialGradient gradient2(view.rect().center() + QPoint(int(sin(i / 1.7) * 10), int(cos(i / 1.7) * 10)), 10);
975         gradient2.setColorAt(0, Qt::transparent);
976         gradient2.setColorAt(0.5, Qt::black);
977         gradient2.setColorAt(1, Qt::transparent);
978         gradient2.setSpread(QGradient::RepeatSpread);
979         scene.setBackgroundBrush(gradient2);
980
981         QRadialGradient gradient3(view.rect().center() + QPoint(int(sin(i / 1.85) * 10), int(cos(i / 1.85) * 10)), 10);
982         gradient3.setColorAt(0, Qt::transparent);
983         gradient3.setColorAt(0.5, Qt::black);
984         gradient3.setColorAt(1, Qt::transparent);
985         gradient3.setSpread(QGradient::RepeatSpread);
986         scene.setBackgroundBrush(gradient3);
987
988         QApplication::processEvents();
989     }
990
991     view.setSceneRect(-1000, -1000, 2000, 2000);
992     for (int i = -500; i < 500; i += 10) {
993         view.centerOn(i, 0);
994         QApplication::processEvents();
995         QApplication::processEvents();
996     }
997     for (int i = -500; i < 500; i += 10) {
998         view.centerOn(0, i);
999         QApplication::processEvents();
1000         QApplication::processEvents();
1001     }
1002 }
1003
1004 void tst_QGraphicsView::matrix()
1005 {
1006     {
1007         QGraphicsScene scene;
1008         QGraphicsView view(&scene);
1009         view.show();
1010
1011         // Show rendering of background with no scene
1012         for (int i = 0; i < 50; ++i) {
1013             view.rotate(5);
1014             QRadialGradient gradient(view.rect().center() + QPoint(int(sin(i / 2.0) * 10), int(cos(i / 2.0) * 10)), 10);
1015             gradient.setColorAt(0, Qt::transparent);
1016             gradient.setColorAt(0.5, Qt::black);
1017             gradient.setColorAt(1, Qt::transparent);
1018             gradient.setSpread(QGradient::RepeatSpread);
1019             scene.setForegroundBrush(gradient);
1020             QRadialGradient gradient2(view.rect().center() + QPoint(int(sin(i / 1.7) * 10), int(cos(i / 1.7) * 10)), 10);
1021             gradient2.setColorAt(0, Qt::transparent);
1022             gradient2.setColorAt(0.5, Qt::black);
1023             gradient2.setColorAt(1, Qt::transparent);
1024             gradient2.setSpread(QGradient::RepeatSpread);
1025             scene.setBackgroundBrush(gradient2);
1026             QApplication::processEvents();
1027             QApplication::processEvents();
1028         }
1029     }
1030
1031     // Test transformation extremes, see if they cause crashes
1032     {
1033         QGraphicsScene scene;
1034         scene.addText("GraphicsView rotated clockwise");
1035
1036         QGraphicsView view(&scene);
1037         view.show();
1038         for (int i = 0; i < 160; ++i) {
1039             view.rotate(18);
1040             QApplication::processEvents();
1041             QApplication::processEvents();
1042         }
1043         /*
1044           // These cause a crash
1045         for (int i = 0; i < 40; ++i) {
1046             view.shear(1.2, 1.2);
1047             QTest::qWait(20);
1048         }
1049         for (int i = 0; i < 40; ++i) {
1050             view.shear(-1.2, -1.2);
1051             QTest::qWait(20);
1052         }
1053         */
1054         for (int i = 0; i < 20; ++i) {
1055             view.scale(1.2, 1.2);
1056             QApplication::processEvents();
1057             QApplication::processEvents();
1058         }
1059         for (int i = 0; i < 20; ++i) {
1060             view.scale(0.6, 0.6);
1061             QApplication::processEvents();
1062             QApplication::processEvents();
1063         }
1064     }
1065 }
1066
1067 void tst_QGraphicsView::matrix_convenience()
1068 {
1069     QGraphicsView view;
1070     QCOMPARE(view.matrix(), QMatrix());
1071
1072     // Check the convenience functions
1073     view.rotate(90);
1074     QCOMPARE(view.matrix(), QMatrix().rotate(90));
1075     view.scale(2, 2);
1076     QCOMPARE(view.matrix(), QMatrix().scale(2, 2) * QMatrix().rotate(90));
1077     view.shear(1.2, 1.2);
1078     QCOMPARE(view.matrix(), QMatrix().shear(1.2, 1.2) * QMatrix().scale(2, 2) * QMatrix().rotate(90));
1079     view.translate(1, 1);
1080     QCOMPARE(view.matrix(), QMatrix().translate(1, 1) * QMatrix().shear(1.2, 1.2) * QMatrix().scale(2, 2) * QMatrix().rotate(90));
1081 }
1082
1083 void tst_QGraphicsView::matrix_combine()
1084 {
1085     // Check matrix combining
1086     QGraphicsView view;
1087     QCOMPARE(view.matrix(), QMatrix());
1088     view.setMatrix(QMatrix().rotate(90), true);
1089     view.setMatrix(QMatrix().rotate(90), true);
1090     view.setMatrix(QMatrix().rotate(90), true);
1091     view.setMatrix(QMatrix().rotate(90), true);
1092     QCOMPARE(view.matrix(), QMatrix());
1093
1094     view.resetMatrix();
1095     QCOMPARE(view.matrix(), QMatrix());
1096     view.setMatrix(QMatrix().rotate(90), false);
1097     view.setMatrix(QMatrix().rotate(90), false);
1098     view.setMatrix(QMatrix().rotate(90), false);
1099     view.setMatrix(QMatrix().rotate(90), false);
1100     QCOMPARE(view.matrix(), QMatrix().rotate(90));
1101 }
1102
1103 void tst_QGraphicsView::centerOnPoint()
1104 {
1105     QWidget toplevel;
1106
1107     QGraphicsScene scene;
1108     scene.addEllipse(QRectF(-100, -100, 50, 50));
1109     scene.addEllipse(QRectF(50, -100, 50, 50));
1110     scene.addEllipse(QRectF(-100, 50, 50, 50));
1111     scene.addEllipse(QRectF(50, 50, 50, 50));
1112
1113     QGraphicsView view(&scene, &toplevel);
1114     view.setSceneRect(-400, -400, 800, 800);
1115     view.setFixedSize(100, 100);
1116     toplevel.show();
1117
1118     int tolerance = 5;
1119
1120     for (int i = 0; i < 3; ++i) {
1121         for (int y = -100; y < 100; y += 23) {
1122             for (int x = -100; x < 100; x += 23) {
1123                 view.centerOn(x, y);
1124                 QPoint viewCenter = view.mapToScene(view.viewport()->rect().center()).toPoint();
1125
1126                 // Fuzzy compare
1127                 if (viewCenter.x() < x - tolerance || viewCenter.x() > x + tolerance
1128                     || viewCenter.y() < y - tolerance || viewCenter.y() > y + tolerance) {
1129                     QString error = QString("Compared values are not the same\n\tActual: (%1, %2)\n\tExpected: (%3, %4)")
1130                                     .arg(viewCenter.x()).arg(viewCenter.y()).arg(x).arg(y);
1131                     QFAIL(qPrintable(error));
1132                 }
1133
1134                 QApplication::processEvents();
1135             }
1136         }
1137
1138         view.rotate(13);
1139         view.scale(1.5, 1.5);
1140         view.shear(1.25, 1.25);
1141     }
1142 }
1143
1144 void tst_QGraphicsView::centerOnItem()
1145 {
1146     QGraphicsScene scene;
1147     QGraphicsItem *items[4];
1148     items[0] = scene.addEllipse(QRectF(-25, -25, 50, 50));
1149     items[1] = scene.addEllipse(QRectF(-25, -25, 50, 50));
1150     items[2] = scene.addEllipse(QRectF(-25, -25, 50, 50));
1151     items[3] = scene.addEllipse(QRectF(-25, -25, 50, 50));
1152     items[0]->setPos(-100, -100);
1153     items[1]->setPos(100, -100);
1154     items[2]->setPos(-100, 100);
1155     items[3]->setPos(100, 100);
1156
1157     QGraphicsView view(&scene);
1158     view.setSceneRect(-1000, -1000, 2000, 2000);
1159     view.show();
1160     QVERIFY(QTest::qWaitForWindowExposed(&view));
1161     int tolerance = 7;
1162
1163     for (int x = 0; x < 3; ++x) {
1164         for (int i = 0; i < 4; ++i) {
1165             QApplication::processEvents();
1166             view.centerOn(items[i]);
1167
1168             QPoint viewCenter = view.mapToScene(view.viewport()->rect().center()).toPoint();
1169             qreal x = items[i]->pos().x();
1170             qreal y = items[i]->pos().y();
1171
1172             // Fuzzy compare
1173             if (viewCenter.x() < x - tolerance || viewCenter.x() > x + tolerance
1174                 || viewCenter.y() < y - tolerance || viewCenter.y() > y + tolerance) {
1175                 QString error = QString("Compared values are not the same\n\tActual: (%1, %2)\n\tExpected: (%3, %4)")
1176                                 .arg(viewCenter.x()).arg(viewCenter.y()).arg(x).arg(y);
1177                 QFAIL(qPrintable(error));
1178             }
1179
1180             QApplication::processEvents();
1181         }
1182
1183         view.rotate(13);
1184         view.scale(1.5, 1.5);
1185         view.shear(1.25, 1.25);
1186     }
1187 }
1188
1189 void tst_QGraphicsView::ensureVisibleRect()
1190 {
1191     QWidget toplevel;
1192
1193     QGraphicsScene scene;
1194     QGraphicsItem *items[4];
1195     items[0] = scene.addEllipse(QRectF(-25, -25, 50, 50), QPen(Qt::black), QBrush(Qt::green));
1196     items[1] = scene.addEllipse(QRectF(-25, -25, 50, 50), QPen(Qt::black), QBrush(Qt::red));
1197     items[2] = scene.addEllipse(QRectF(-25, -25, 50, 50), QPen(Qt::black), QBrush(Qt::blue));
1198     items[3] = scene.addEllipse(QRectF(-25, -25, 50, 50), QPen(Qt::black), QBrush(Qt::yellow));
1199     scene.addLine(QLineF(0, -100, 0, 100), QPen(Qt::blue, 2));
1200     scene.addLine(QLineF(-100, 0, 100, 0), QPen(Qt::blue, 2));
1201     items[0]->setPos(-100, -100);
1202     items[1]->setPos(100, -100);
1203     items[2]->setPos(-100, 100);
1204     items[3]->setPos(100, 100);
1205
1206     QGraphicsItem *icon = scene.addEllipse(QRectF(-10, -10, 20, 20), QPen(Qt::black), QBrush(Qt::gray));
1207
1208     QGraphicsView view(&scene, &toplevel);
1209     view.setSceneRect(-500, -500, 1000, 1000);
1210     view.setFixedSize(250, 250);
1211     toplevel.show();
1212     QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
1213
1214     for (int y = -100; y < 100; y += 25) {
1215         for (int x = -100; x < 100; x += 13) {
1216
1217             icon->setPos(x, y);
1218
1219             switch (x & 3) {
1220             case 0:
1221                 view.centerOn(-500, -500);
1222                 break;
1223             case 1:
1224                 view.centerOn(500, -500);
1225                 break;
1226             case 2:
1227                 view.centerOn(-500, 500);
1228                 break;
1229             case 3:
1230             default:
1231                 view.centerOn(500, 500);
1232                 break;
1233             }
1234
1235             QVERIFY(!view.viewport()->rect().contains(view.mapFromScene(x, y)));
1236
1237             for (int margin = 10; margin < 60; margin += 15) {
1238                 view.ensureVisible(x, y, 0, 0, margin, margin);
1239
1240                 QRect viewRect = view.viewport()->rect();
1241                 QPoint viewPoint = view.mapFromScene(x, y);
1242
1243                 QVERIFY(viewRect.contains(viewPoint));
1244                 QVERIFY(qAbs(viewPoint.x() - viewRect.left()) >= margin -1);
1245                 QVERIFY(qAbs(viewPoint.x() - viewRect.right()) >= margin -1);
1246                 QVERIFY(qAbs(viewPoint.y() - viewRect.top()) >= margin -1);
1247                 QVERIFY(qAbs(viewPoint.y() - viewRect.bottom()) >= margin -1);
1248
1249                 QApplication::processEvents();
1250             }
1251         }
1252         view.rotate(5);
1253         view.scale(1.05, 1.05);
1254         view.translate(30, -30);
1255     }
1256 }
1257
1258 void tst_QGraphicsView::fitInView()
1259 {
1260     QGraphicsScene scene;
1261     QGraphicsItem *items[4];
1262     items[0] = scene.addEllipse(QRectF(-25, -25, 100, 20), QPen(Qt::black), QBrush(Qt::green));
1263     items[1] = scene.addEllipse(QRectF(-25, -25, 20, 100), QPen(Qt::black), QBrush(Qt::red));
1264     items[2] = scene.addEllipse(QRectF(-25, -25, 50, 50), QPen(Qt::black), QBrush(Qt::blue));
1265     items[3] = scene.addEllipse(QRectF(-25, -25, 50, 50), QPen(Qt::black), QBrush(Qt::yellow));
1266     scene.addLine(QLineF(0, -100, 0, 100), QPen(Qt::blue, 2));
1267     scene.addLine(QLineF(-100, 0, 100, 0), QPen(Qt::blue, 2));
1268     items[0]->setPos(-100, -100);
1269     items[1]->setPos(100, -100);
1270     items[2]->setPos(-100, 100);
1271     items[3]->setPos(100, 100);
1272
1273     items[0]->rotate(30);
1274     items[1]->rotate(-30);
1275
1276 #if defined(Q_OS_WINCE)
1277     //Is the standard scrollbar size
1278     int scrollbarSize = qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent) - 13;
1279 #endif
1280
1281     QGraphicsView view(&scene);
1282     view.setSceneRect(-400, -400, 800, 800);
1283
1284 #if defined(Q_OS_WINCE)
1285     //We need to take in account the scrollbar size for the WindowsMobilStyle
1286     view.setFixedSize(400 + scrollbarSize, 200 + scrollbarSize);
1287 #else
1288     view.setFixedSize(400, 200);
1289 #endif
1290
1291     view.show();
1292     view.fitInView(scene.itemsBoundingRect(), Qt::IgnoreAspectRatio);
1293     qApp->processEvents();
1294
1295     // Sampled coordinates.
1296     QVERIFY(!view.itemAt(45, 41));
1297     QVERIFY(!view.itemAt(297, 44));
1298     QVERIFY(!view.itemAt(359, 143));
1299     QCOMPARE(view.itemAt(79, 22), items[0]);
1300     QCOMPARE(view.itemAt(329, 41), items[1]);
1301     QCOMPARE(view.itemAt(38, 158), items[2]);
1302     QCOMPARE(view.itemAt(332, 160), items[3]);
1303
1304     view.fitInView(items[0], Qt::IgnoreAspectRatio);
1305     qApp->processEvents();
1306
1307     QCOMPARE(view.itemAt(19, 13), items[0]);
1308     QCOMPARE(view.itemAt(91, 47), items[0]);
1309     QCOMPARE(view.itemAt(202, 94), items[0]);
1310     QCOMPARE(view.itemAt(344, 161), items[0]);
1311     QVERIFY(!view.itemAt(236, 54));
1312     QVERIFY(!view.itemAt(144, 11));
1313     QVERIFY(!view.itemAt(29, 69));
1314     QVERIFY(!view.itemAt(251, 167));
1315
1316     view.fitInView(items[0], Qt::KeepAspectRatio);
1317     qApp->processEvents();
1318
1319     QCOMPARE(view.itemAt(325, 170), items[0]);
1320     QCOMPARE(view.itemAt(206, 74), items[0]);
1321     QCOMPARE(view.itemAt(190, 115), items[0]);
1322     QCOMPARE(view.itemAt(55, 14), items[0]);
1323     QVERIFY(!view.itemAt(109, 4));
1324     QVERIFY(!view.itemAt(244, 68));
1325     QVERIFY(!view.itemAt(310, 125));
1326     QVERIFY(!view.itemAt(261, 168));
1327
1328     view.fitInView(items[0], Qt::KeepAspectRatioByExpanding);
1329     qApp->processEvents();
1330
1331     QCOMPARE(view.itemAt(18, 10), items[0]);
1332     QCOMPARE(view.itemAt(95, 4), items[0]);
1333     QCOMPARE(view.itemAt(279, 175), items[0]);
1334     QCOMPARE(view.itemAt(359, 170), items[0]);
1335     QVERIFY(!view.itemAt(370, 166));
1336     QVERIFY(!view.itemAt(136, 7));
1337     QVERIFY(!view.itemAt(31, 44));
1338     QVERIFY(!view.itemAt(203, 153));
1339 }
1340
1341 void tst_QGraphicsView::itemsAtPoint()
1342 {
1343     QGraphicsScene scene;
1344     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(1);
1345     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(0);
1346     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(2);
1347     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(-1);
1348     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(3);
1349
1350     QGraphicsView view;
1351     QVERIFY(view.items(0, 0).isEmpty());
1352
1353     view.setScene(&scene);
1354     view.setSceneRect(-10000, -10000, 20000, 20000);
1355     view.show();
1356
1357     QList<QGraphicsItem *> items = view.items(view.viewport()->rect().center());
1358     QCOMPARE(items.size(), 5);
1359     QCOMPARE(items.takeFirst()->zValue(), qreal(3));
1360     QCOMPARE(items.takeFirst()->zValue(), qreal(2));
1361     QCOMPARE(items.takeFirst()->zValue(), qreal(1));
1362     QCOMPARE(items.takeFirst()->zValue(), qreal(0));
1363     QCOMPARE(items.takeFirst()->zValue(), qreal(-1));
1364 }
1365
1366 #if defined QT_BUILD_INTERNAL
1367 void tst_QGraphicsView::itemsAtPosition_data()
1368 {
1369     QTest::addColumn<float>("rotation");
1370     QTest::addColumn<float>("scale");
1371     QTest::addColumn<QPoint>("viewPos");
1372     QTest::addColumn<bool>("ignoreTransform");
1373     QTest::addColumn<bool>("hit");
1374     QTest::newRow("scaled + ignore transform, no hit") << 0.0f << 1000.0f << QPoint(0, 0) << true << false;
1375     QTest::newRow("scaled + ignore transform, hit") << 0.0f << 1000.0f << QPoint(100, 100) << true << true;
1376     QTest::newRow("rotated + scaled, no hit") << 45.0f << 2.0f << QPoint(90, 90) << false << false;
1377     QTest::newRow("rotated + scaled, hit") << 45.0f << 2.0f << QPoint(100, 100) << false << true;
1378 }
1379
1380 void tst_QGraphicsView::itemsAtPosition()
1381 {
1382     QFETCH(float, rotation);
1383     QFETCH(float, scale);
1384     QFETCH(QPoint, viewPos);
1385     QFETCH(bool, ignoreTransform);
1386     QFETCH(bool, hit);
1387
1388     FriendlyGraphicsScene scene;
1389     scene.setSceneRect(QRect(-100, -100, 200, 200));
1390     QGraphicsItem *item = scene.addRect(-5, -5, 10, 10);
1391
1392     if (ignoreTransform)
1393         item->setFlag(QGraphicsItem::ItemIgnoresTransformations);
1394
1395     QGraphicsView view;
1396     view.setFrameStyle(QFrame::NoFrame);
1397     view.resize(200, 200);
1398     view.scale(scale, scale);
1399     view.rotate(rotation);
1400     view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1401     view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1402     view.setScene(&scene);
1403     view.show();
1404     QVERIFY(QTest::qWaitForWindowExposed(&view));
1405
1406     QPoint screenPos = view.viewport()->mapToGlobal(viewPos);
1407     QPointF scenePos = view.mapToScene(viewPos);
1408     QGraphicsScenePrivate *viewPrivate = scene.d_func();
1409     QList<QGraphicsItem *> items;
1410     items = viewPrivate->itemsAtPosition(screenPos, scenePos, view.viewport());
1411     QCOMPARE(!items.empty(), hit);
1412 }
1413 #endif
1414
1415 void tst_QGraphicsView::itemsInRect()
1416 {
1417     QGraphicsScene scene;
1418     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(1);
1419     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(0);
1420     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(2);
1421     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(-1);
1422     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(3);
1423
1424     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(5);
1425     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(4);
1426     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(6);
1427     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(3);
1428     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(7);
1429
1430     QGraphicsView view;
1431     QVERIFY(view.items(QRect(-100, -100, 200, 200)).isEmpty());
1432     view.setScene(&scene);
1433     view.setSceneRect(-10000, -10000, 20000, 20000);
1434     view.show();
1435
1436     QRect leftRect = view.mapFromScene(-30, -10, 20, 20).boundingRect();
1437     QRect rightRect = view.mapFromScene(30, -10, 20, 20).boundingRect();
1438
1439     QList<QGraphicsItem *> items = view.items(leftRect);
1440     QCOMPARE(items.size(), 5);
1441     QCOMPARE(items.takeFirst()->zValue(), qreal(3));
1442     QCOMPARE(items.takeFirst()->zValue(), qreal(2));
1443     QCOMPARE(items.takeFirst()->zValue(), qreal(1));
1444     QCOMPARE(items.takeFirst()->zValue(), qreal(0));
1445     QCOMPARE(items.takeFirst()->zValue(), qreal(-1));
1446
1447     items = view.items(rightRect);
1448     QCOMPARE(items.size(), 5);
1449     QCOMPARE(items.takeFirst()->zValue(), qreal(7));
1450     QCOMPARE(items.takeFirst()->zValue(), qreal(6));
1451     QCOMPARE(items.takeFirst()->zValue(), qreal(5));
1452     QCOMPARE(items.takeFirst()->zValue(), qreal(4));
1453     QCOMPARE(items.takeFirst()->zValue(), qreal(3));
1454 }
1455
1456 class CountPaintItem : public QGraphicsRectItem
1457 {
1458 public:
1459     int numPaints;
1460
1461     CountPaintItem(const QRectF &rect)
1462         : QGraphicsRectItem(rect), numPaints(0)
1463     { }
1464
1465     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
1466     {
1467         ++numPaints;
1468         QGraphicsRectItem::paint(painter, option, widget);
1469     }
1470 };
1471
1472 void tst_QGraphicsView::itemsInRect_cosmeticAdjust_data()
1473 {
1474     QTest::addColumn<QRect>("updateRect");
1475     QTest::addColumn<int>("numPaints");
1476     QTest::addColumn<bool>("adjustForAntialiasing");
1477
1478     // Aliased.
1479     QTest::newRow("nil") << QRect() << 1 << false;
1480     QTest::newRow("0, 0, 300, 100") << QRect(0, 0, 300, 100) << 1 << false;
1481     QTest::newRow("0, 0, 100, 300") << QRect(0, 0, 100, 300) << 1 << false;
1482     QTest::newRow("200, 0, 100, 300") << QRect(200, 0, 100, 300) << 1 << false;
1483     QTest::newRow("0, 200, 300, 100") << QRect(0, 200, 300, 100) << 1 << false;
1484     QTest::newRow("0, 0, 300, 99") << QRect(0, 0, 300, 99) << 0 << false;
1485     QTest::newRow("0, 0, 99, 300") << QRect(0, 0, 99, 300) << 0 << false;
1486     QTest::newRow("201, 0, 99, 300") << QRect(201, 0, 99, 300) << 0 << false;
1487     QTest::newRow("0, 201, 300, 99") << QRect(0, 201, 300, 99) << 0 << false;
1488
1489     // Anti-aliased.
1490     QTest::newRow("nil") << QRect() << 1 << true;
1491     QTest::newRow("0, 0, 300, 100") << QRect(0, 0, 300, 100) << 1 << true;
1492     QTest::newRow("0, 0, 100, 300") << QRect(0, 0, 100, 300) << 1 << true;
1493     QTest::newRow("200, 0, 100, 300") << QRect(200, 0, 100, 300) << 1 << true;
1494     QTest::newRow("0, 200, 300, 100") << QRect(0, 200, 300, 100) << 1 << true;
1495     QTest::newRow("0, 0, 300, 99") << QRect(0, 0, 300, 99) << 1 << true;
1496     QTest::newRow("0, 0, 99, 300") << QRect(0, 0, 99, 300) << 1 << true;
1497     QTest::newRow("201, 0, 99, 300") << QRect(201, 0, 99, 300) << 1 << true;
1498     QTest::newRow("0, 201, 300, 99") << QRect(0, 201, 300, 99) << 1 << true;
1499     QTest::newRow("0, 0, 300, 98") << QRect(0, 0, 300, 98) << 0 << false;
1500     QTest::newRow("0, 0, 98, 300") << QRect(0, 0, 98, 300) << 0 << false;
1501     QTest::newRow("202, 0, 98, 300") << QRect(202, 0, 98, 300) << 0 << false;
1502     QTest::newRow("0, 202, 300, 98") << QRect(0, 202, 300, 98) << 0 << false;
1503 }
1504
1505 void tst_QGraphicsView::itemsInRect_cosmeticAdjust()
1506 {
1507     QFETCH(QRect, updateRect);
1508     QFETCH(int, numPaints);
1509     QFETCH(bool, adjustForAntialiasing);
1510
1511     QGraphicsScene scene(-100, -100, 200, 200);
1512     CountPaintItem *rect = new CountPaintItem(QRectF(-50, -50, 100, 100));
1513     scene.addItem(rect);
1514
1515     QGraphicsView view(&scene);
1516     view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, !adjustForAntialiasing);
1517     view.setRenderHint(QPainter::Antialiasing, adjustForAntialiasing);
1518     view.setFrameStyle(0);
1519     view.resize(300, 300);
1520     view.show();
1521     QVERIFY(QTest::qWaitForWindowActive(&view));
1522     QTRY_VERIFY(rect->numPaints > 0);
1523
1524     rect->numPaints = 0;
1525     if (updateRect.isNull())
1526         view.viewport()->update();
1527     else
1528         view.viewport()->update(updateRect);
1529     qApp->processEvents();
1530     QTRY_COMPARE(rect->numPaints, numPaints);
1531 }
1532
1533 void tst_QGraphicsView::itemsInPoly()
1534 {
1535     QGraphicsScene scene;
1536     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(1);
1537     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(0);
1538     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(2);
1539     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(-1);
1540     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(3);
1541
1542     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(5);
1543     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(4);
1544     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(6);
1545     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(3);
1546     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(7);
1547
1548     QGraphicsView view;
1549     QVERIFY(view.items(QPolygon()).isEmpty());
1550     view.setScene(&scene);
1551     view.setSceneRect(-10000, -10000, 20000, 20000);
1552     view.show();
1553
1554     QPolygon leftPoly = view.mapFromScene(QRectF(-30, -10, 20, 20));
1555     QPolygon rightPoly = view.mapFromScene(QRectF(30, -10, 20, 20));
1556
1557     QList<QGraphicsItem *> items = view.items(leftPoly);
1558     QCOMPARE(items.size(), 5);
1559     QCOMPARE(items.takeFirst()->zValue(), qreal(3));
1560     QCOMPARE(items.takeFirst()->zValue(), qreal(2));
1561     QCOMPARE(items.takeFirst()->zValue(), qreal(1));
1562     QCOMPARE(items.takeFirst()->zValue(), qreal(0));
1563     QCOMPARE(items.takeFirst()->zValue(), qreal(-1));
1564
1565     items = view.items(rightPoly);
1566     QCOMPARE(items.size(), 5);
1567     QCOMPARE(items.takeFirst()->zValue(), qreal(7));
1568     QCOMPARE(items.takeFirst()->zValue(), qreal(6));
1569     QCOMPARE(items.takeFirst()->zValue(), qreal(5));
1570     QCOMPARE(items.takeFirst()->zValue(), qreal(4));
1571     QCOMPARE(items.takeFirst()->zValue(), qreal(3));
1572 }
1573
1574 void tst_QGraphicsView::itemsInPath()
1575 {
1576     QGraphicsScene scene;
1577     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(1);
1578     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(0);
1579     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(2);
1580     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(-1);
1581     scene.addRect(QRectF(-30, -10, 20, 20))->setZValue(3);
1582
1583     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(5);
1584     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(4);
1585     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(6);
1586     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(3);
1587     scene.addRect(QRectF(30, -10, 20, 20))->setZValue(7);
1588
1589     QGraphicsView view;
1590     QVERIFY(view.items(QPainterPath()).isEmpty());
1591     view.setScene(&scene);
1592     view.translate(100, 400);
1593     view.rotate(22.3);
1594     view.setSceneRect(-10000, -10000, 20000, 20000);
1595     view.show();
1596
1597     QPainterPath leftPath;
1598     leftPath.addEllipse(QRect(view.mapFromScene(-30, -10), QSize(20, 20)));
1599
1600     QPainterPath rightPath;
1601     rightPath.addEllipse(QRect(view.mapFromScene(30, -10), QSize(20, 20)));
1602
1603     QList<QGraphicsItem *> items = view.items(leftPath);
1604
1605     QCOMPARE(items.size(), 5);
1606     QCOMPARE(items.takeFirst()->zValue(), qreal(3));
1607     QCOMPARE(items.takeFirst()->zValue(), qreal(2));
1608     QCOMPARE(items.takeFirst()->zValue(), qreal(1));
1609     QCOMPARE(items.takeFirst()->zValue(), qreal(0));
1610     QCOMPARE(items.takeFirst()->zValue(), qreal(-1));
1611
1612     items = view.items(rightPath);
1613     QCOMPARE(items.size(), 5);
1614     QCOMPARE(items.takeFirst()->zValue(), qreal(7));
1615     QCOMPARE(items.takeFirst()->zValue(), qreal(6));
1616     QCOMPARE(items.takeFirst()->zValue(), qreal(5));
1617     QCOMPARE(items.takeFirst()->zValue(), qreal(4));
1618     QCOMPARE(items.takeFirst()->zValue(), qreal(3));
1619 }
1620
1621 void tst_QGraphicsView::itemAt()
1622 {
1623     QGraphicsScene scene;
1624     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(1);
1625     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(0);
1626     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(2);
1627     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(-1);
1628     scene.addRect(QRectF(-10, -10, 20, 20))->setZValue(3);
1629
1630     QGraphicsView view;
1631     QCOMPARE(view.itemAt(0, 0), (QGraphicsItem *)0);
1632
1633     view.setScene(&scene);
1634     view.setSceneRect(-10000, -10000, 20000, 20000);
1635     view.show();
1636
1637     QCOMPARE(view.itemAt(0, 0), (QGraphicsItem *)0);
1638     QGraphicsItem* item = view.itemAt(view.viewport()->rect().center());
1639     QVERIFY(item);
1640     QCOMPARE(item->zValue(), qreal(3));
1641 }
1642
1643 void tst_QGraphicsView::itemAt2()
1644 {
1645     // test precision of the itemAt() function with items that are smaller
1646     // than 1 pixel.
1647     QGraphicsScene scene(0, 0, 100, 100);
1648
1649     // Add a 0.5x0.5 item at position 0 on the scene, top-left corner at -0.25, -0.25.
1650     QGraphicsItem *item = scene.addRect(QRectF(-0.25, -0.25, 0.5, 0.5), QPen(Qt::black, 0.1));
1651
1652     QGraphicsView view(&scene);
1653     view.setFixedSize(200, 200);
1654     view.setTransformationAnchor(QGraphicsView::NoAnchor);
1655     view.setRenderHint(QPainter::Antialiasing);
1656     view.show();
1657     QVERIFY(QTest::qWaitForWindowExposed(&view));
1658     QApplication::processEvents();
1659
1660     QPoint itemViewPoint = view.mapFromScene(item->scenePos());
1661
1662     for (int i = 0; i < 3; ++i) {
1663         QVERIFY(view.itemAt(itemViewPoint));
1664         QVERIFY(!view.items(itemViewPoint).isEmpty());
1665         QVERIFY(view.itemAt(itemViewPoint + QPoint(-1, 0)));
1666         QVERIFY(!view.items(itemViewPoint + QPoint(-1, 0)).isEmpty());
1667         QVERIFY(view.itemAt(itemViewPoint + QPoint(-1, -1)));
1668         QVERIFY(!view.items(itemViewPoint + QPoint(-1, -1)).isEmpty());
1669         QVERIFY(view.itemAt(itemViewPoint + QPoint(0, -1)));
1670         QVERIFY(!view.items(itemViewPoint + QPoint(0, -1)).isEmpty());
1671         item->moveBy(0.1, 0);
1672     }
1673
1674     // Here
1675     QVERIFY(view.itemAt(itemViewPoint));
1676     QVERIFY(!view.items(itemViewPoint).isEmpty());
1677     QVERIFY(view.itemAt(itemViewPoint + QPoint(0, -1)));
1678     QVERIFY(!view.items(itemViewPoint + QPoint(0, -1)).isEmpty());
1679
1680     if (sizeof(qreal) != sizeof(double))
1681         QSKIP("Skipped due to rounding errors");
1682
1683     // Not here
1684     QVERIFY(!view.itemAt(itemViewPoint + QPoint(-1, 0)));
1685     QVERIFY(view.items(itemViewPoint + QPoint(-1, 0)).isEmpty());
1686     QVERIFY(!view.itemAt(itemViewPoint + QPoint(-1, -1)));
1687     QVERIFY(view.items(itemViewPoint + QPoint(-1, -1)).isEmpty());
1688 }
1689
1690 void tst_QGraphicsView::mapToScene()
1691 {
1692     // Uncomment the commented-out code to see what's going on. It doesn't
1693     // affect the test; it just slows it down.
1694
1695     QGraphicsScene scene;
1696     scene.addPixmap(QPixmap("3D-Qt-1-2.png"));
1697
1698     QWidget topLevel;
1699     QGraphicsView view(&topLevel);
1700     view.setScene(&scene);
1701     view.setSceneRect(-500, -500, 1000, 1000);
1702 #if defined(Q_OS_WINCE)
1703     QSize viewSize(200,200);
1704 #else
1705     QSize viewSize(300,300);
1706 #endif
1707
1708     view.setFixedSize(viewSize);
1709     topLevel.show();
1710     QApplication::processEvents();
1711     QVERIFY(view.isVisible());
1712     QCOMPARE(view.size(), viewSize);
1713
1714     // First once without setting the scene rect
1715 #ifdef Q_PROCESSOR_ARM
1716     const int step = 20;
1717 #else
1718     const int step = 5;
1719 #endif
1720
1721     for (int x = 0; x < view.width(); x += step) {
1722         for (int y = 0; y < view.height(); y += step) {
1723             QCOMPARE(view.mapToScene(QPoint(x, y)),
1724                      QPointF(view.horizontalScrollBar()->value() + x,
1725                              view.verticalScrollBar()->value() + y));
1726         }
1727     }
1728
1729     for (int sceneRectHeight = 250; sceneRectHeight < 1000; sceneRectHeight += 250) {
1730         for (int sceneRectWidth = 250; sceneRectWidth < 1000; sceneRectWidth += 250) {
1731             view.setSceneRect(QRectF(-int(sceneRectWidth / 2), -int(sceneRectHeight / 2),
1732                                      sceneRectWidth, sceneRectHeight));
1733             QApplication::processEvents();
1734
1735             int hmin = view.horizontalScrollBar()->minimum();
1736             int hmax = view.horizontalScrollBar()->maximum();
1737             int hstep = (hmax - hmin) / 3;
1738             int vmin = view.verticalScrollBar()->minimum();
1739             int vmax = view.verticalScrollBar()->maximum();
1740             int vstep = (vmax - vmin) / 3;
1741
1742             for (int hscrollValue = hmin; hscrollValue < hmax; hscrollValue += hstep) {
1743                 for (int vscrollValue = vmin; vscrollValue < vmax; vscrollValue += vstep) {
1744
1745                     view.horizontalScrollBar()->setValue(hscrollValue);
1746                     view.verticalScrollBar()->setValue(vscrollValue);
1747                     QApplication::processEvents();
1748
1749                     int h = view.horizontalScrollBar()->value();
1750                     int v = view.verticalScrollBar()->value();
1751
1752                     for (int x = 0; x < view.width(); x += step) {
1753                         for (int y = 0; y < view.height(); y += step) {
1754                             QCOMPARE(view.mapToScene(QPoint(x, y)), QPointF(h + x, v + y));
1755                             QCOMPARE(view.mapFromScene(QPointF(h + x, v + y)), QPoint(x, y));
1756                         }
1757                     }
1758                 }
1759             }
1760         }
1761     }
1762 }
1763
1764 void tst_QGraphicsView::mapToScenePoint()
1765 {
1766     QGraphicsScene scene;
1767     QGraphicsView view(&scene);
1768     view.rotate(90);
1769     view.setFixedSize(117, 117);
1770     view.show();
1771     QPoint center = view.viewport()->rect().center();
1772     QCOMPARE(view.mapToScene(center + QPoint(10, 0)),
1773              view.mapToScene(center) + QPointF(0, -10));
1774 }
1775
1776 void tst_QGraphicsView::mapToSceneRect_data()
1777 {
1778     QTest::addColumn<QRect>("viewRect");
1779     QTest::addColumn<QPolygonF>("scenePoly");
1780     QTest::addColumn<qreal>("rotation");
1781
1782     QTest::newRow("nil") << QRect() << QPolygonF() << qreal(0);
1783     QTest::newRow("0, 0, 1, 1") << QRect(0, 0, 1, 1) << QPolygonF(QRectF(0, 0, 1, 1)) << qreal(0);
1784     QTest::newRow("0, 0, 10, 10") << QRect(0, 0, 10, 10) << QPolygonF(QRectF(0, 0, 10, 10)) << qreal(0);
1785     QTest::newRow("nil") << QRect() << QPolygonF() << qreal(90);
1786     QPolygonF p;
1787     p << QPointF(0, 0) << QPointF(0, -1) << QPointF(1, -1) << QPointF(1, 0) << QPointF(0, 0);
1788     QTest::newRow("0, 0, 1, 1") << QRect(0, 0, 1, 1)
1789                                 << p
1790                                 << qreal(90);
1791     p.clear();
1792     p << QPointF(0, 0) << QPointF(0, -10) << QPointF(10, -10) << QPointF(10, 0) << QPointF(0, 0);
1793     QTest::newRow("0, 0, 10, 10") << QRect(0, 0, 10, 10)
1794                                   << p
1795                                   << qreal(90);
1796 }
1797
1798 void tst_QGraphicsView::mapToSceneRect()
1799 {
1800     QFETCH(QRect, viewRect);
1801     QFETCH(QPolygonF, scenePoly);
1802     QFETCH(qreal, rotation);
1803
1804     QGraphicsScene scene(-1000, -1000, 2000, 2000);
1805     scene.addRect(25, -25, 50, 50);
1806     QGraphicsView view(&scene);
1807     view.setFrameStyle(0);
1808     view.setAlignment(Qt::AlignTop | Qt::AlignLeft);
1809     view.setFixedSize(200, 200);
1810     view.setTransformationAnchor(QGraphicsView::NoAnchor);
1811     view.setResizeAnchor(QGraphicsView::NoAnchor);
1812     view.show();
1813
1814     view.rotate(rotation);
1815
1816     QPolygonF poly = view.mapToScene(viewRect);
1817     if (!poly.isEmpty())
1818         poly << poly[0];
1819
1820     QCOMPARE(poly, scenePoly);
1821 }
1822
1823 void tst_QGraphicsView::mapToScenePoly()
1824 {
1825     QGraphicsScene scene;
1826     QGraphicsView view(&scene);
1827     view.translate(100, 100);
1828     view.setFixedSize(117, 117);
1829     view.show();
1830     QPoint center = view.viewport()->rect().center();
1831     QRect rect(center + QPoint(10, 0), QSize(10, 10));
1832
1833     QPolygon poly;
1834     poly << rect.topLeft();
1835     poly << rect.topRight();
1836     poly << rect.bottomRight();
1837     poly << rect.bottomLeft();
1838
1839     QPolygonF poly2;
1840     poly2 << view.mapToScene(rect.topLeft());
1841     poly2 << view.mapToScene(rect.topRight());
1842     poly2 << view.mapToScene(rect.bottomRight());
1843     poly2 << view.mapToScene(rect.bottomLeft());
1844
1845     QCOMPARE(view.mapToScene(poly), poly2);
1846 }
1847
1848 void tst_QGraphicsView::mapToScenePath()
1849 {
1850     QGraphicsScene scene;
1851     QGraphicsView view(&scene);
1852     view.setSceneRect(-300, -300, 600, 600);
1853     view.translate(10, 10);
1854     view.setFixedSize(300, 300);
1855     view.show();
1856     QRect rect(QPoint(10, 0), QSize(10, 10));
1857
1858     QPainterPath path;
1859     path.addRect(rect);
1860
1861     QPainterPath path2;
1862     path2.addRect(rect.translated(view.horizontalScrollBar()->value() - 10,
1863                                   view.verticalScrollBar()->value() - 10));
1864     QCOMPARE(view.mapToScene(path), path2);
1865 }
1866
1867 void tst_QGraphicsView::mapFromScenePoint()
1868 {
1869     {
1870         QGraphicsScene scene;
1871         QGraphicsView view(&scene);
1872         view.rotate(90);
1873         view.scale(10, 10);
1874         view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1875         view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1876         view.show();
1877
1878         QPoint mapped = view.mapFromScene(0, 0);
1879         QPoint center = view.viewport()->rect().center();
1880         if (qAbs(mapped.x() - center.x()) >= 2
1881             || qAbs(mapped.y() - center.y()) >= 2) {
1882             QString error = QString("Compared values are not the same\n\tActual: (%1, %2)\n\tExpected: (%3, %4)")
1883                             .arg(mapped.x()).arg(mapped.y()).arg(center.x()).arg(center.y());
1884             QFAIL(qPrintable(error));
1885         }
1886     }
1887     {
1888         QWidget toplevel;
1889
1890         QGraphicsScene scene(0, 0, 200, 200);
1891         scene.addRect(QRectF(0, 0, 200, 200), QPen(Qt::black, 1));
1892         QGraphicsView view(&scene, &toplevel);
1893         view.ensurePolished();
1894         view.resize(view.sizeHint());
1895         toplevel.show();
1896
1897         QCOMPARE(view.mapFromScene(0, 0), QPoint(0, 0));
1898         QCOMPARE(view.mapFromScene(0.4, 0.4), QPoint(0, 0));
1899         QCOMPARE(view.mapFromScene(0.5, 0.5), QPoint(1, 1));
1900         QCOMPARE(view.mapFromScene(0.9, 0.9), QPoint(1, 1));
1901         QCOMPARE(view.mapFromScene(1.0, 1.0), QPoint(1, 1));
1902         QCOMPARE(view.mapFromScene(100, 100), QPoint(100, 100));
1903         QCOMPARE(view.mapFromScene(100.5, 100.5), QPoint(101, 101));
1904         QCOMPARE(view.mapToScene(0, 0), QPointF(0, 0));
1905         QCOMPARE(view.mapToScene(1, 1), QPointF(1, 1));
1906         QCOMPARE(view.mapToScene(100, 100), QPointF(100, 100));
1907     }
1908 }
1909
1910 void tst_QGraphicsView::mapFromSceneRect()
1911 {
1912     QGraphicsScene scene;
1913     QWidget topLevel;
1914     QGraphicsView view(&scene,&topLevel);
1915     view.rotate(90);
1916     view.setFixedSize(200, 200);
1917     view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1918     view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1919     topLevel.show();
1920     QTest::qWait(25);
1921
1922     QPolygon polygon;
1923     polygon << QPoint(98, 98);
1924     polygon << QPoint(98, 108);
1925     polygon << QPoint(88, 108);
1926     polygon << QPoint(88, 98);
1927
1928
1929     QPolygon viewPolygon = view.mapFromScene(0, 0, 10, 10);
1930     for (int i = 0; i < 4; ++i) {
1931         QVERIFY(qAbs(viewPolygon[i].x() - polygon[i].x()) < 3);
1932         QVERIFY(qAbs(viewPolygon[i].y() - polygon[i].y()) < 3);
1933     }
1934
1935     QPoint pt = view.mapFromScene(QPointF());
1936     QPolygon p;
1937     p << pt << pt << pt << pt;
1938     QCOMPARE(view.mapFromScene(QRectF()), p);
1939 }
1940
1941 void tst_QGraphicsView::mapFromScenePoly()
1942 {
1943     QGraphicsScene scene;
1944     QGraphicsView view(&scene);
1945     view.rotate(90);
1946     view.setFixedSize(200, 200);
1947     view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1948     view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1949     view.show();
1950
1951     QPolygonF polygon;
1952     polygon << QPoint(0, 0);
1953     polygon << QPoint(10, 0);
1954     polygon << QPoint(10, 10);
1955     polygon << QPoint(0, 10);
1956
1957     QPolygon polygon2;
1958     polygon2 << QPoint(98, 98);
1959     polygon2 << QPoint(98, 108);
1960     polygon2 << QPoint(88, 108);
1961     polygon2 << QPoint(88, 98);
1962
1963     QPolygon viewPolygon = view.mapFromScene(polygon);
1964     for (int i = 0; i < 4; ++i) {
1965         QVERIFY(qAbs(viewPolygon[i].x() - polygon2[i].x()) < 3);
1966         QVERIFY(qAbs(viewPolygon[i].y() - polygon2[i].y()) < 3);
1967     }
1968 }
1969
1970 void tst_QGraphicsView::mapFromScenePath()
1971 {
1972     QGraphicsScene scene;
1973     QGraphicsView view(&scene);
1974     view.rotate(90);
1975     view.setFixedSize(200, 200);
1976     view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1977     view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1978     view.show();
1979
1980     QPolygonF polygon;
1981     polygon << QPoint(0, 0);
1982     polygon << QPoint(10, 0);
1983     polygon << QPoint(10, 10);
1984     polygon << QPoint(0, 10);
1985     QPainterPath path;
1986     path.addPolygon(polygon);
1987
1988     QPolygon polygon2;
1989     polygon2 << QPoint(98, 98);
1990     polygon2 << QPoint(98, 108);
1991     polygon2 << QPoint(88, 108);
1992     polygon2 << QPoint(88, 98);
1993     QPainterPath path2;
1994     path2.addPolygon(polygon2);
1995
1996     QPolygonF pathPoly = view.mapFromScene(path).toFillPolygon();
1997     QPolygonF path2Poly = path2.toFillPolygon();
1998
1999     for (int i = 0; i < pathPoly.size(); ++i) {
2000         QVERIFY(qAbs(pathPoly[i].x() - path2Poly[i].x()) < 3);
2001         QVERIFY(qAbs(pathPoly[i].y() - path2Poly[i].y()) < 3);
2002     }
2003 }
2004
2005 void tst_QGraphicsView::sendEvent()
2006 {
2007     QGraphicsScene scene;
2008
2009     TestItem *item = new TestItem;
2010     scene.addItem(item);
2011     item->setFlag(QGraphicsItem::ItemIsFocusable);
2012     item->setFlag(QGraphicsItem::ItemIsMovable);
2013
2014     QGraphicsView view(&scene);
2015     view.show();
2016     QApplication::setActiveWindow(&view);
2017     QVERIFY(QTest::qWaitForWindowActive(&view));
2018     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2019
2020     item->setFocus();
2021
2022     QCOMPARE(scene.focusItem(), (QGraphicsItem *)item);
2023     QCOMPARE(item->events.size(), 2);
2024     QCOMPARE(item->events.last(), QEvent::FocusIn);
2025
2026     QPoint itemPoint = view.mapFromScene(item->scenePos());
2027     sendMousePress(view.viewport(), itemPoint);
2028     QCOMPARE(item->events.size(), 4);
2029     QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GrabMouse);
2030     QCOMPARE(item->events.at(item->events.size() - 1), QEvent::GraphicsSceneMousePress);
2031
2032     QMouseEvent mouseMoveEvent(QEvent::MouseMove, itemPoint, view.viewport()->mapToGlobal(itemPoint),
2033                                 Qt::LeftButton, Qt::LeftButton, 0);
2034     QApplication::sendEvent(view.viewport(), &mouseMoveEvent);
2035     QCOMPARE(item->events.size(), 5);
2036     QCOMPARE(item->events.last(), QEvent::GraphicsSceneMouseMove);
2037
2038     QMouseEvent mouseReleaseEvent(QEvent::MouseButtonRelease, itemPoint,
2039                                   view.viewport()->mapToGlobal(itemPoint),
2040                                   Qt::LeftButton, 0, 0);
2041     QApplication::sendEvent(view.viewport(), &mouseReleaseEvent);
2042     QCOMPARE(item->events.size(), 7);
2043     QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GraphicsSceneMouseRelease);
2044     QCOMPARE(item->events.at(item->events.size() - 1), QEvent::UngrabMouse);
2045
2046     QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Space, 0);
2047     QApplication::sendEvent(view.viewport(), &keyPress);
2048     QCOMPARE(item->events.size(), 9);
2049     QCOMPARE(item->events.at(item->events.size() - 2), QEvent::ShortcutOverride);
2050     QCOMPARE(item->events.last(), QEvent::KeyPress);
2051 }
2052
2053 class MouseWheelScene : public QGraphicsScene
2054 {
2055 public:
2056     Qt::Orientation orientation;
2057
2058     void wheelEvent(QGraphicsSceneWheelEvent *event)
2059     {
2060         orientation = event->orientation();
2061         QGraphicsScene::wheelEvent(event);
2062     }
2063 };
2064
2065 void tst_QGraphicsView::wheelEvent()
2066 {
2067     // Create a scene with an invalid orientation.
2068     MouseWheelScene scene;
2069     scene.orientation = Qt::Orientation(-1);
2070
2071     QGraphicsWidget *widget = new QGraphicsWidget;
2072     widget->setGeometry(0, 0, 400, 400);
2073     widget->setFocusPolicy(Qt::WheelFocus);
2074
2075     EventSpy spy(widget, QEvent::GraphicsSceneWheel);
2076     QCOMPARE(spy.count(), 0);
2077
2078     scene.addItem(widget);
2079
2080     // Assign a view.
2081     QGraphicsView view(&scene);
2082     view.show();
2083     QApplication::setActiveWindow(&view);
2084     QVERIFY(QTest::qWaitForWindowActive(&view));
2085     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2086
2087
2088     // Send a wheel event with horizontal orientation.
2089     {
2090         QWheelEvent event(view.mapFromScene(widget->boundingRect().center()),
2091                           view.mapToGlobal(view.mapFromScene(widget->boundingRect().center())),
2092                           120, 0, 0, Qt::Horizontal);
2093         QApplication::sendEvent(view.viewport(), &event);
2094         QCOMPARE(scene.orientation, Qt::Horizontal);
2095     }
2096
2097     // Send a wheel event with vertical orientation.
2098     {
2099         QWheelEvent event(view.mapFromScene(widget->boundingRect().center()),
2100                           view.mapToGlobal(view.mapFromScene(widget->boundingRect().center())),
2101                           120, 0, 0, Qt::Vertical);
2102         QApplication::sendEvent(view.viewport(), &event);
2103         QCOMPARE(scene.orientation, Qt::Vertical);
2104     }
2105
2106     QCOMPARE(spy.count(), 2);
2107     QVERIFY(widget->hasFocus());
2108 }
2109
2110 #ifndef QTEST_NO_CURSOR
2111 void tst_QGraphicsView::cursor()
2112 {
2113     QGraphicsScene scene;
2114     QGraphicsItem *item = scene.addRect(QRectF(-10, -10, 20, 20));
2115     item->setCursor(Qt::IBeamCursor);
2116
2117     QGraphicsView view(&scene);
2118     view.setFixedSize(400, 400);
2119     view.show();
2120     QVERIFY(QTest::qWaitForWindowExposed(&view));
2121
2122     QCOMPARE(view.viewport()->cursor().shape(), QCursor().shape());
2123     view.viewport()->setCursor(Qt::PointingHandCursor);
2124     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2125
2126     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
2127     QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
2128
2129     sendMouseMove(view.viewport(), QPoint(5, 5));
2130     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2131 }
2132 #endif
2133
2134 #ifndef QTEST_NO_CURSOR
2135 void tst_QGraphicsView::cursor2()
2136 {
2137     QGraphicsScene scene;
2138     QGraphicsItem *item = scene.addRect(QRectF(-10, -10, 20, 20));
2139     item->setCursor(Qt::IBeamCursor);
2140     item->setZValue(1);
2141
2142     QGraphicsItem *item2 = scene.addRect(QRectF(-20, -20, 40, 40));
2143     item2->setZValue(0);
2144
2145     QGraphicsView view(&scene);
2146     view.viewport()->setCursor(Qt::PointingHandCursor);
2147     view.setFixedSize(400, 400);
2148     view.show();
2149     QVERIFY(QTest::qWaitForWindowExposed(&view));
2150
2151     sendMouseMove(view.viewport(), view.mapFromScene(-30, -30));
2152     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2153     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
2154     QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
2155     sendMouseMove(view.viewport(), view.mapFromScene(-30, -30));
2156     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2157     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
2158     QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
2159     sendMouseMove(view.viewport(), view.mapFromScene(-15, 0));
2160     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2161
2162     view.setDragMode(QGraphicsView::ScrollHandDrag);
2163
2164     sendMouseMove(view.viewport(), view.mapFromScene(-30, -30));
2165     QCOMPARE(view.viewport()->cursor().shape(), Qt::OpenHandCursor);
2166     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
2167     QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
2168     sendMouseMove(view.viewport(), view.mapFromScene(-15, -15));
2169     QCOMPARE(view.viewport()->cursor().shape(), Qt::OpenHandCursor);
2170
2171     view.setDragMode(QGraphicsView::NoDrag);
2172     QCOMPARE(view.viewport()->cursor().shape(), Qt::ArrowCursor);
2173     view.viewport()->setCursor(Qt::PointingHandCursor);
2174     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2175
2176     item2->setCursor(Qt::SizeAllCursor);
2177
2178     sendMouseMove(view.viewport(), view.mapFromScene(-30, -30));
2179     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2180     sendMouseMove(view.viewport(), view.mapFromScene(-15, -15));
2181     QCOMPARE(view.viewport()->cursor().shape(), Qt::SizeAllCursor);
2182     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
2183     QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
2184     sendMouseMove(view.viewport(), view.mapFromScene(-15, -15));
2185     QCOMPARE(view.viewport()->cursor().shape(), Qt::SizeAllCursor);
2186     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
2187     QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
2188     sendMouseMove(view.viewport(), view.mapFromScene(-30, -30));
2189     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
2190
2191     view.setDragMode(QGraphicsView::ScrollHandDrag);
2192
2193     sendMouseMove(view.viewport(), view.mapFromScene(-30, -30));
2194     QCOMPARE(view.viewport()->cursor().shape(), Qt::OpenHandCursor);
2195     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
2196     QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor);
2197     sendMouseMove(view.viewport(), view.mapFromScene(-15, -15));
2198     QCOMPARE(view.viewport()->cursor().shape(), Qt::SizeAllCursor);
2199 }
2200 #endif
2201
2202 void tst_QGraphicsView::transformationAnchor()
2203 {
2204     QGraphicsScene scene(-1000, -1000, 2000, 2000);
2205     scene.addRect(QRectF(-50, -50, 100, 100), QPen(Qt::black), QBrush(Qt::blue));
2206
2207     QGraphicsView view(&scene);
2208
2209     for (int i = 0; i < 2; ++i) {
2210         view.resize(100, 100);
2211         view.show();
2212
2213         if (i == 0) {
2214             QCOMPARE(view.transformationAnchor(), QGraphicsView::AnchorViewCenter);
2215         } else {
2216             view.setTransformationAnchor(QGraphicsView::NoAnchor);
2217         }
2218         view.centerOn(0, 0);
2219         view.horizontalScrollBar()->setValue(100);
2220         QApplication::processEvents();
2221
2222         QPointF center = view.mapToScene(view.viewport()->rect().center());
2223
2224         view.scale(10, 10);
2225
2226         QPointF newCenter = view.mapToScene(view.viewport()->rect().center());
2227
2228         if (i == 0) {
2229             qreal slack = 3;
2230             QVERIFY(qAbs(newCenter.x() - center.x()) < slack);
2231             QVERIFY(qAbs(newCenter.y() - center.y()) < slack);
2232         } else {
2233             qreal slack = qreal(0.3);
2234             QVERIFY(qAbs(newCenter.x() - center.x() / 10) < slack);
2235             QVERIFY(qAbs(newCenter.y() - center.y() / 10) < slack);
2236         }
2237     }
2238 }
2239
2240 void tst_QGraphicsView::resizeAnchor()
2241 {
2242     QGraphicsScene scene(-1000, -1000, 2000, 2000);
2243     scene.addRect(QRectF(-50, -50, 100, 100), QPen(Qt::black), QBrush(Qt::blue));
2244
2245     QGraphicsView view(&scene);
2246
2247     for (int i = 0; i < 2; ++i) {
2248         view.resize(100, 100);
2249         view.show();
2250         QVERIFY(QTest::qWaitForWindowExposed(&view));
2251         QApplication::processEvents();
2252
2253         if (i == 0) {
2254             QCOMPARE(view.resizeAnchor(), QGraphicsView::NoAnchor);
2255         } else {
2256             view.setResizeAnchor(QGraphicsView::AnchorViewCenter);
2257         }
2258         view.centerOn(0, 0);
2259         QTest::qWait(25);
2260
2261         QPointF f = view.mapToScene(50, 50);
2262         QPointF center = view.mapToScene(view.viewport()->rect().center());
2263
2264         QApplication::processEvents();
2265
2266         for (int size = 200; size <= 400; size += 25) {
2267             view.resize(size, size);
2268             if (i == 0) {
2269                 QTRY_COMPARE(view.mapToScene(50, 50), f);
2270                 QTRY_VERIFY(view.mapToScene(view.viewport()->rect().center()) != center);
2271             } else {
2272                 QTRY_VERIFY(view.mapToScene(50, 50) != f);
2273
2274                 QPointF newCenter = view.mapToScene(view.viewport()->rect().center());
2275                 int slack = 3;
2276                 QVERIFY(qAbs(newCenter.x() - center.x()) < slack);
2277                 QVERIFY(qAbs(newCenter.y() - center.y()) < slack);
2278             }
2279             QApplication::processEvents();
2280         }
2281     }
2282 }
2283
2284 class CustomView : public QGraphicsView
2285 {
2286     Q_OBJECT
2287 public:
2288     CustomView(QGraphicsScene *s = 0) : QGraphicsView(s) {}
2289     CustomView(QGraphicsScene *s, QWidget *parent)
2290         : QGraphicsView(s, parent) {}
2291     QList<QRegion> lastUpdateRegions;
2292     bool painted;
2293
2294 protected:
2295     void paintEvent(QPaintEvent *event)
2296     {
2297         lastUpdateRegions << event->region();
2298         painted = true;
2299         QGraphicsView::paintEvent(event);
2300     }
2301 };
2302
2303 void tst_QGraphicsView::viewportUpdateMode()
2304 {
2305     QGraphicsScene scene(0, 0, 100, 100);
2306     scene.setBackgroundBrush(Qt::red);
2307
2308     CustomView view;
2309     QDesktopWidget desktop;
2310     view.setFixedSize(QSize(500, 500).boundedTo(desktop.availableGeometry().size())); // 500 is too big for all common smartphones
2311     view.setScene(&scene);
2312     QCOMPARE(view.viewportUpdateMode(), QGraphicsView::MinimalViewportUpdate);
2313
2314     // Show the view, and initialize our test.
2315     view.show();
2316     qApp->setActiveWindow(&view);
2317     QVERIFY(QTest::qWaitForWindowActive(&view));
2318     QTRY_VERIFY(!view.lastUpdateRegions.isEmpty());
2319     view.lastUpdateRegions.clear();
2320
2321     // Issue two scene updates.
2322     scene.update(QRectF(0, 0, 10, 10));
2323     scene.update(QRectF(20, 0, 10, 10));
2324     QTest::qWait(50);
2325
2326     // The view gets two updates for the update scene updates.
2327     QTRY_VERIFY(!view.lastUpdateRegions.isEmpty());
2328 #ifndef Q_OS_MAC //cocoa doesn't support drawing regions
2329     QCOMPARE(view.lastUpdateRegions.last().rects().size(), 2);
2330     QCOMPARE(view.lastUpdateRegions.last().rects().at(0).size(), QSize(14, 14));
2331     QCOMPARE(view.lastUpdateRegions.last().rects().at(1).size(), QSize(14, 14));
2332 #endif
2333
2334     // Set full update mode.
2335     view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
2336     QCOMPARE(view.viewportUpdateMode(), QGraphicsView::FullViewportUpdate);
2337     view.lastUpdateRegions.clear();
2338
2339     // Issue two scene updates.
2340     scene.update(QRectF(0, 0, 10, 10));
2341     scene.update(QRectF(20, 0, 10, 10));
2342     qApp->processEvents();
2343     qApp->processEvents();
2344
2345     // The view gets one full viewport update for the update scene updates.
2346     QCOMPARE(view.lastUpdateRegions.last().rects().size(), 1);
2347     QCOMPARE(view.lastUpdateRegions.last().rects().at(0).size(), view.viewport()->size());
2348     view.lastUpdateRegions.clear();
2349
2350     // Set smart update mode
2351     view.setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
2352     QCOMPARE(view.viewportUpdateMode(), QGraphicsView::SmartViewportUpdate);
2353
2354     // Issue 100 mini-updates
2355     for (int i = 0; i < 10; ++i) {
2356         for (int j = 0; j < 10; ++j) {
2357             scene.update(QRectF(i * 3, j * 3, 1, 1));
2358         }
2359     }
2360     qApp->processEvents();
2361     qApp->processEvents();
2362
2363     // The view gets one bounding rect update.
2364     QCOMPARE(view.lastUpdateRegions.last().rects().size(), 1);
2365     QCOMPARE(view.lastUpdateRegions.last().rects().at(0).size(), QSize(32, 32));
2366
2367     // Set no update mode
2368     view.setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
2369     QCOMPARE(view.viewportUpdateMode(), QGraphicsView::NoViewportUpdate);
2370
2371     // Issue two scene updates.
2372     view.lastUpdateRegions.clear();
2373     TestItem item;
2374     scene.addItem(&item);
2375     item.moveBy(10, 10);
2376     scene.update(QRectF(0, 0, 10, 10));
2377     scene.update(QRectF(20, 0, 10, 10));
2378     qApp->processEvents();
2379     qApp->processEvents();
2380
2381     // The view should not get any painting calls from the scene updates
2382     QCOMPARE(view.lastUpdateRegions.size(), 0);
2383 }
2384
2385 void tst_QGraphicsView::viewportUpdateMode2()
2386 {
2387     QWidget toplevel;
2388
2389     // Create a view with viewport rect equal to QRect(0, 0, 200, 200).
2390     QGraphicsScene dummyScene;
2391     CustomView view(0, &toplevel);
2392     view.painted = false;
2393     view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
2394     view.setScene(&dummyScene);
2395     view.ensurePolished(); // make sure we get the right content margins
2396     int left, top, right, bottom;
2397     view.getContentsMargins(&left, &top, &right, &bottom);
2398     view.resize(200 + left + right, 200 + top + bottom);
2399     toplevel.show();
2400     qApp->setActiveWindow(&toplevel);
2401     QVERIFY(QTest::qWaitForWindowActive(&toplevel));
2402     QTRY_VERIFY(view.painted);
2403     const QRect viewportRect = view.viewport()->rect();
2404     QCOMPARE(viewportRect, QRect(0, 0, 200, 200));
2405
2406 #if defined QT_BUILD_INTERNAL
2407     QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
2408
2409     QRect boundingRect;
2410     const QRect rect1(0, 0, 10, 10);
2411     QVERIFY(viewPrivate->updateRect(rect1));
2412     QVERIFY(!viewPrivate->fullUpdatePending);
2413     boundingRect |= rect1;
2414     QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect);
2415
2416     const QRect rect2(50, 50, 10, 10);
2417     QVERIFY(viewPrivate->updateRect(rect2));
2418     QVERIFY(!viewPrivate->fullUpdatePending);
2419     boundingRect |= rect2;
2420     QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect);
2421
2422     const QRect rect3(190, 190, 10, 10);
2423     QVERIFY(viewPrivate->updateRect(rect3));
2424     QVERIFY(viewPrivate->fullUpdatePending);
2425     boundingRect |= rect3;
2426     QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect);
2427
2428     view.lastUpdateRegions.clear();
2429     viewPrivate->processPendingUpdates();
2430     QTest::qWait(50);
2431     QCOMPARE(view.lastUpdateRegions.size(), 1);
2432     // Note that we adjust by 2 for antialiasing.
2433     QCOMPARE(view.lastUpdateRegions.at(0), QRegion(boundingRect.adjusted(-2, -2, 2, 2) & viewportRect));
2434 #endif
2435 }
2436
2437 #ifndef QT_NO_DRAGANDDROP
2438 void tst_QGraphicsView::acceptDrops()
2439 {
2440     QGraphicsView view;
2441
2442     // Excepted default behavior.
2443     QVERIFY(view.acceptDrops());
2444     QVERIFY(view.viewport()->acceptDrops());
2445
2446     // Excepted behavior with no drops.
2447     view.setAcceptDrops(false);
2448     QVERIFY(!view.acceptDrops());
2449     QVERIFY(!view.viewport()->acceptDrops());
2450
2451     // Setting a widget with drops on a QGraphicsView without drops.
2452     QWidget *widget = new QWidget;
2453     widget->setAcceptDrops(true);
2454     view.setViewport(widget);
2455     QVERIFY(!view.acceptDrops());
2456     QVERIFY(!view.viewport()->acceptDrops());
2457
2458     // Switching the view to accept drops.
2459     view.setAcceptDrops(true);
2460     QVERIFY(view.acceptDrops());
2461     QVERIFY(view.viewport()->acceptDrops());
2462
2463     // Setting a widget with no drops on a QGraphicsView with drops.
2464     widget = new QWidget;
2465     widget->setAcceptDrops(false);
2466     view.setViewport(widget);
2467     QVERIFY(view.viewport()->acceptDrops());
2468     QVERIFY(view.acceptDrops());
2469
2470     // Switching the view to not accept drops.
2471     view.setAcceptDrops(false);
2472     QVERIFY(!view.viewport()->acceptDrops());
2473 }
2474 #endif
2475
2476 void tst_QGraphicsView::optimizationFlags()
2477 {
2478     QGraphicsView view;
2479     QVERIFY(!view.optimizationFlags());
2480
2481     view.setOptimizationFlag(QGraphicsView::DontClipPainter);
2482     QVERIFY(view.optimizationFlags() & QGraphicsView::DontClipPainter);
2483     view.setOptimizationFlag(QGraphicsView::DontClipPainter, false);
2484     QVERIFY(!view.optimizationFlags());
2485
2486     view.setOptimizationFlag(QGraphicsView::DontSavePainterState);
2487     QVERIFY(view.optimizationFlags() & QGraphicsView::DontSavePainterState);
2488     view.setOptimizationFlag(QGraphicsView::DontSavePainterState, false);
2489     QVERIFY(!view.optimizationFlags());
2490
2491     view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing);
2492     QVERIFY(view.optimizationFlags() & QGraphicsView::DontAdjustForAntialiasing);
2493     view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, false);
2494     QVERIFY(!view.optimizationFlags());
2495
2496     view.setOptimizationFlags(QGraphicsView::DontAdjustForAntialiasing
2497                               | QGraphicsView::DontClipPainter);
2498     QCOMPARE(view.optimizationFlags(), QGraphicsView::OptimizationFlags(QGraphicsView::DontAdjustForAntialiasing
2499              | QGraphicsView::DontClipPainter));
2500 }
2501
2502 class MessUpPainterItem : public QGraphicsRectItem
2503 {
2504 public:
2505     MessUpPainterItem(const QRectF &rect) : QGraphicsRectItem(rect), dirtyPainter(false)
2506     { }
2507
2508     bool dirtyPainter;
2509
2510     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
2511     {
2512         dirtyPainter = (painter->pen().width() != 0);
2513         painter->setPen(QPen(Qt::black, 1.0));
2514     }
2515 };
2516
2517 class MyGraphicsView : public QGraphicsView
2518 {
2519 public:
2520       MyGraphicsView(QGraphicsScene * scene) : QGraphicsView(scene)
2521       { }
2522
2523       void drawBackground(QPainter * painter, const QRectF & rect) {
2524           painter->setCompositionMode(QPainter::CompositionMode_Source);
2525           painter->drawRect(rect);
2526       }
2527
2528       void drawItems (QPainter * painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[]) {
2529            if (!(optimizationFlags() & QGraphicsView::DontSavePainterState))
2530                QCOMPARE(painter->compositionMode(),QPainter::CompositionMode_SourceOver);
2531            else
2532                QCOMPARE(painter->compositionMode(),QPainter::CompositionMode_Source);
2533            QGraphicsView::drawItems(painter,numItems,items,options);
2534       }
2535 };
2536
2537 void tst_QGraphicsView::optimizationFlags_dontSavePainterState()
2538 {
2539     MessUpPainterItem *parent = new MessUpPainterItem(QRectF(0, 0, 100, 100));
2540     MessUpPainterItem *child = new MessUpPainterItem(QRectF(0, 0, 100, 100));
2541     child->setParentItem(parent);
2542
2543     QGraphicsScene scene;
2544     scene.addItem(parent);
2545
2546     QGraphicsView view(&scene);
2547     view.show();
2548     QVERIFY(QTest::qWaitForWindowExposed(&view));
2549     view.viewport()->repaint();
2550
2551     QVERIFY(!parent->dirtyPainter);
2552     QVERIFY(!child->dirtyPainter);
2553
2554     view.setOptimizationFlags(QGraphicsView::DontSavePainterState);
2555     view.viewport()->repaint();
2556
2557 #ifdef Q_OS_MAC
2558     // Repaint on Mac OS X actually does require spinning the event loop.
2559     QTest::qWait(100);
2560 #endif
2561     QVERIFY(!parent->dirtyPainter);
2562     QVERIFY(child->dirtyPainter);
2563
2564     MyGraphicsView painter(&scene);
2565     painter.show();
2566     QVERIFY(QTest::qWaitForWindowExposed(&painter));
2567
2568     MyGraphicsView painter2(&scene);
2569     painter2.setOptimizationFlag(QGraphicsView::DontSavePainterState,true);
2570     painter2.show();
2571     QVERIFY(QTest::qWaitForWindowExposed(&painter2));
2572 }
2573
2574 void tst_QGraphicsView::optimizationFlags_dontSavePainterState2_data()
2575 {
2576     QTest::addColumn<bool>("savePainter");
2577     QTest::addColumn<bool>("indirectPainting");
2578     QTest::newRow("With painter state protection, without indirect painting") << true << false;
2579     QTest::newRow("Without painter state protection, without indirect painting") << false << false;
2580     QTest::newRow("With painter state protectionm, with indirect painting") << true << true;
2581     QTest::newRow("Without painter state protection, with indirect painting") << false << true;
2582 }
2583
2584 void tst_QGraphicsView::optimizationFlags_dontSavePainterState2()
2585 {
2586     QFETCH(bool, savePainter);
2587     QFETCH(bool, indirectPainting);
2588
2589     class MyScene : public QGraphicsScene
2590     {
2591     public:
2592         void drawBackground(QPainter *p, const QRectF &)
2593         { transformInDrawBackground = p->worldTransform(); opacityInDrawBackground = p->opacity(); }
2594
2595         void drawForeground(QPainter *p, const QRectF &)
2596         { transformInDrawForeground = p->worldTransform(); opacityInDrawForeground = p->opacity(); }
2597
2598         QTransform transformInDrawBackground;
2599         QTransform transformInDrawForeground;
2600         qreal opacityInDrawBackground;
2601         qreal opacityInDrawForeground;
2602     };
2603
2604     MyScene scene;
2605     // Add transformed dummy items to make sure the painter's worldTransform() is changed in drawItems.
2606     scene.addRect(0, 0, 20, 20)->setTransform(QTransform::fromScale(2, 2));
2607     scene.addRect(50, 50, 20, 20)->setTransform(QTransform::fromTranslate(200, 200));
2608
2609     foreach (QGraphicsItem *item, scene.items())
2610         item->setOpacity(0.6);
2611
2612     CustomView view(&scene);
2613     if (!savePainter)
2614         view.setOptimizationFlag(QGraphicsView::DontSavePainterState);
2615     view.setOptimizationFlag(QGraphicsView::IndirectPainting, indirectPainting);
2616     view.rotate(45);
2617     view.scale(1.5, 1.5);
2618     view.show();
2619     QVERIFY(QTest::qWaitForWindowExposed(&view));
2620
2621     // Make sure the view is repainted; otherwise the tests below will fail.
2622     view.viewport()->repaint();
2623     QTest::qWait(200);
2624     QVERIFY(view.painted);
2625
2626     // Make sure the painter's world transform is preserved after drawItems.
2627     QTransform expectedTransform = view.viewportTransform();
2628     QVERIFY(!expectedTransform.isIdentity());
2629     QCOMPARE(scene.transformInDrawForeground, expectedTransform);
2630     QCOMPARE(scene.transformInDrawBackground, expectedTransform);
2631
2632     qreal expectedOpacity = 1.0;
2633     QCOMPARE(scene.opacityInDrawBackground, expectedOpacity);
2634     QCOMPARE(scene.opacityInDrawForeground, expectedOpacity);
2635
2636     // Trigger more painting, this time from QGraphicsScene::render.
2637     QImage image(scene.sceneRect().size().toSize(), QImage::Format_RGB32);
2638     QPainter painter(&image);
2639     scene.render(&painter);
2640     painter.end();
2641
2642     expectedTransform = QTransform();
2643     QCOMPARE(scene.transformInDrawForeground, expectedTransform);
2644     QCOMPARE(scene.transformInDrawBackground, expectedTransform);
2645     QCOMPARE(scene.opacityInDrawBackground, expectedOpacity);
2646     QCOMPARE(scene.opacityInDrawForeground, expectedOpacity);
2647
2648     // Trigger more painting with another opacity on the painter.
2649     painter.begin(&image);
2650     painter.setOpacity(0.4);
2651     expectedOpacity = 0.4;
2652     scene.render(&painter);
2653     painter.end();
2654
2655     QCOMPARE(scene.transformInDrawForeground, expectedTransform);
2656     QCOMPARE(scene.transformInDrawBackground, expectedTransform);
2657     QCOMPARE(scene.opacityInDrawBackground, expectedOpacity);
2658     QCOMPARE(scene.opacityInDrawForeground, expectedOpacity);
2659 }
2660
2661 class LodItem : public QGraphicsRectItem
2662 {
2663 public:
2664     LodItem(const QRectF &rect) : QGraphicsRectItem(rect), lastLod(-42)
2665     { }
2666
2667     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *viewport)
2668     {
2669         lastLod = option->levelOfDetailFromTransform(painter->worldTransform());
2670         QGraphicsRectItem::paint(painter, option, viewport);
2671     }
2672
2673     qreal lastLod;
2674 };
2675
2676 void tst_QGraphicsView::levelOfDetail_data()
2677 {
2678     QTest::addColumn<QTransform>("transform");
2679     QTest::addColumn<qreal>("lod");
2680
2681     QTest::newRow("1:4, 1:4") << QTransform().scale(0.25, 0.25) << qreal(0.25);
2682     QTest::newRow("1:2, 1:4") << QTransform().scale(0.5, 0.25) << qreal(::sqrt(0.125));
2683     QTest::newRow("4:1, 1:2") << QTransform().scale(0.25, 0.5) << qreal(::sqrt(0.125));
2684
2685     QTest::newRow("1:2, 1:2") << QTransform().scale(0.5, 0.5) << qreal(0.5);
2686     QTest::newRow("1:1, 1:2") << QTransform().scale(1, 0.5) << qreal(::sqrt(0.5));
2687     QTest::newRow("2:1, 1:1") << QTransform().scale(0.5, 1) << qreal(::sqrt(0.5));
2688
2689     QTest::newRow("1:1, 1:1") << QTransform().scale(1, 1) << qreal(1.0);
2690     QTest::newRow("2:1, 1:1") << QTransform().scale(2, 1) << qreal(::sqrt(2.0));
2691     QTest::newRow("1:1, 2:1") << QTransform().scale(2, 1) << qreal(::sqrt(2.0));
2692     QTest::newRow("2:1, 2:1") << QTransform().scale(2, 2) << qreal(2.0);
2693     QTest::newRow("2:1, 4:1") << QTransform().scale(2, 4) << qreal(::sqrt(8.0));
2694     QTest::newRow("4:1, 2:1") << QTransform().scale(4, 2) << qreal(::sqrt(8.0));
2695     QTest::newRow("4:1, 4:1") << QTransform().scale(4, 4) << qreal(4.0);
2696 }
2697
2698 void tst_QGraphicsView::levelOfDetail()
2699 {
2700     QFETCH(QTransform, transform);
2701     QFETCH(qreal, lod);
2702
2703     LodItem *item = new LodItem(QRectF(0, 0, 100, 100));
2704
2705     QGraphicsScene scene;
2706     scene.addItem(item);
2707
2708     QGraphicsView view(&scene);
2709     view.show();
2710     QVERIFY(QTest::qWaitForWindowExposed(&view));
2711
2712     QTRY_COMPARE(item->lastLod, qreal(1));
2713
2714     view.setTransform(transform);
2715
2716     QTRY_COMPARE(item->lastLod, lod);
2717 }
2718
2719 // Moved to tst_qgraphicsview_2.cpp
2720 extern void _scrollBarRanges_data();
2721
2722 void tst_QGraphicsView::scrollBarRanges_data()
2723 {
2724     _scrollBarRanges_data();
2725 }
2726
2727 // Simulates motif scrollbar for range tests
2728 class FauxMotifStyle : public QCommonStyle {
2729 public:
2730     int styleHint(StyleHint hint, const QStyleOption *option,
2731                   const QWidget *widget, QStyleHintReturn *returnData) const {
2732         if (hint == QStyle::SH_ScrollView_FrameOnlyAroundContents)
2733             return true;
2734         return QCommonStyle::styleHint(hint, option, widget, returnData);
2735     }
2736
2737     int pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *widget) const {
2738         if (m == QStyle::PM_ScrollView_ScrollBarSpacing)
2739             return 4;
2740         return QCommonStyle::pixelMetric(m, opt, widget);
2741     }
2742 };
2743
2744 void tst_QGraphicsView::scrollBarRanges()
2745 {
2746     QFETCH(QSize, viewportSize);
2747     QFETCH(QRectF, sceneRect);
2748     QFETCH(QTransform, transform);
2749     QFETCH(Qt::ScrollBarPolicy, hbarpolicy);
2750     QFETCH(Qt::ScrollBarPolicy, vbarpolicy);
2751     QFETCH(int, hmin);
2752     QFETCH(int, hmax);
2753     QFETCH(int, vmin);
2754     QFETCH(int, vmax);
2755     QFETCH(bool, useMotif);
2756     QFETCH(bool, useStyledPanel);
2757
2758     QGraphicsScene scene(sceneRect);
2759     scene.addRect(sceneRect, QPen(Qt::blue), QBrush(QColor(Qt::green)));
2760     QGraphicsView view(&scene);
2761     view.setRenderHint(QPainter::Antialiasing);
2762     view.setTransform(transform);
2763     view.setFrameStyle(useStyledPanel ? QFrame::StyledPanel : QFrame::NoFrame);
2764
2765     if (useMotif) {
2766 #if !defined(QT_NO_STYLE_WINDOWS)
2767         view.setStyle(new FauxMotifStyle);
2768 #else
2769         QSKIP("No Windows style compiled.");
2770 #endif
2771     } else {
2772 #if defined(Q_OS_WINCE)
2773         view.setStyle(new QWindowsStyle);
2774 #elif !defined(QT_NO_STYLE_PLASTIQUE)
2775         view.setStyle(new QPlastiqueStyle);
2776 #endif
2777     }
2778     view.setStyleSheet(" "); // enables style propagation ;-)
2779
2780     int adjust = 0;
2781     if (useStyledPanel)
2782         adjust = view.style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
2783     view.resize(viewportSize + QSize(adjust, adjust));
2784
2785     view.setHorizontalScrollBarPolicy(hbarpolicy);
2786     view.setVerticalScrollBarPolicy(vbarpolicy);
2787
2788     view.show();
2789     QVERIFY(QTest::qWaitForWindowExposed(&view));
2790
2791     QCOMPARE(view.horizontalScrollBar()->minimum(), hmin);
2792     QCOMPARE(view.verticalScrollBar()->minimum(), vmin);
2793     QCOMPARE(view.horizontalScrollBar()->maximum(), hmax);
2794     QCOMPARE(view.verticalScrollBar()->maximum(), vmax);
2795 }
2796
2797 class TestView : public QGraphicsView
2798 {
2799 public:
2800     TestView(QGraphicsScene *scene)
2801         : QGraphicsView(scene), accepted(false)
2802     { }
2803
2804     bool accepted;
2805
2806 protected:
2807     void mousePressEvent(QMouseEvent *event)
2808     {
2809         QGraphicsView::mousePressEvent(event);
2810         accepted = event->isAccepted();
2811     }
2812 };
2813
2814 void tst_QGraphicsView::acceptMousePressEvent()
2815 {
2816     QGraphicsScene scene;
2817
2818     TestView view(&scene);
2819     view.show();
2820     QVERIFY(QTest::qWaitForWindowExposed(&view));
2821
2822     QMouseEvent event(QEvent::MouseButtonPress,
2823                       view.viewport()->rect().center(),
2824                       view.viewport()->mapToGlobal(view.viewport()->rect().center()),
2825                       Qt::LeftButton, 0, 0);
2826     event.setAccepted(false);
2827     QApplication::sendEvent(view.viewport(), &event);
2828     QVERIFY(!view.accepted);
2829
2830     scene.addRect(0, 0, 2000, 2000)->setFlag(QGraphicsItem::ItemIsMovable);
2831
2832     qApp->processEvents(); // ensure scene rect is updated
2833
2834     QApplication::sendEvent(view.viewport(), &event);
2835     QVERIFY(view.accepted);
2836 }
2837
2838 void tst_QGraphicsView::replayMouseMove()
2839 {
2840     // An empty scene in a view. The view will send the events to the scene in
2841     // any case. Note that the view doesn't have to be shown - the mouse event
2842     // sending functions below send the events directly to the viewport.
2843     QGraphicsScene scene(-10000, -10000, 20000, 20000);
2844     QGraphicsView view(&scene);
2845
2846     EventSpy sceneSpy(&scene, QEvent::GraphicsSceneMouseMove);
2847     EventSpy viewSpy(view.viewport(), QEvent::MouseMove);
2848
2849     sendMousePress(view.viewport(), view.viewport()->rect().center());
2850
2851     // One mouse event should be translated into one scene event.
2852     for (int i = 0; i < 3; ++i) {
2853         sendMouseMove(view.viewport(), view.viewport()->rect().center(),
2854                       Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton));
2855         QCOMPARE(viewSpy.count(), i + 1);
2856         QCOMPARE(sceneSpy.count(), i + 1);
2857     }
2858
2859     // When the view is transformed, the view should get no more events.  But
2860     // the scene should get replays.
2861     for (int i = 0; i < 3; ++i) {
2862         view.rotate(10);
2863         QCOMPARE(viewSpy.count(), 3);
2864         QCOMPARE(sceneSpy.count(), 3 + i + 1);
2865     }
2866
2867     // When the view is scrolled, the view should get no more events.  But the
2868     // scene should get replays.
2869     for (int i = 0; i < 3; ++i) {
2870         view.horizontalScrollBar()->setValue((i + 1) * 10);
2871         QCOMPARE(viewSpy.count(), 3);
2872         QCOMPARE(sceneSpy.count(), 6 + i + 1);
2873     }
2874 }
2875
2876 void tst_QGraphicsView::itemsUnderMouse()
2877 {
2878    QGraphicsScene scene;
2879    QGraphicsProxyWidget w;
2880    w.setWidget(new QPushButton("W"));
2881    w.resize(50,50);
2882    QGraphicsProxyWidget w2(&w);
2883    w2.setWidget(new QPushButton("W2"));
2884    w2.resize(50,50);
2885    QGraphicsProxyWidget w3(&w2);
2886    w3.setWidget(new QPushButton("W3"));
2887    w3.resize(50,50);
2888    w.setZValue(150);
2889    w2.setZValue(50);
2890    w3.setZValue(0);
2891    scene.addItem(&w);
2892
2893    QGraphicsView view(&scene);
2894    view.show();
2895    QVERIFY(QTest::qWaitForWindowExposed(&view));
2896
2897    QCOMPARE(view.items(view.mapFromScene(w3.boundingRect().center())).first(),
2898             static_cast<QGraphicsItem *>(&w3));
2899    w2.setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
2900    QCOMPARE(view.items(view.mapFromScene(w3.boundingRect().center())).first(),
2901             static_cast<QGraphicsItem *>(&w3));
2902 }
2903
2904 class QGraphicsTextItem_task172231 : public QGraphicsTextItem
2905 {
2906 public:
2907     QGraphicsTextItem_task172231(const QString & text, QGraphicsItem * parent = 0)
2908         : QGraphicsTextItem(text, parent) {}
2909     QRectF exposedRect;
2910     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
2911     {
2912         exposedRect = option->exposedRect;
2913         QGraphicsTextItem::paint(painter, option, widget);
2914     }
2915 };
2916
2917 void tst_QGraphicsView::task172231_untransformableItems()
2918 {
2919     // check fix in QGraphicsView::paintEvent()
2920
2921     QGraphicsScene scene;
2922
2923     QGraphicsTextItem_task172231 *text =
2924         new QGraphicsTextItem_task172231("abcdefghijklmnopqrstuvwxyz");
2925     text->setFlag(QGraphicsItem::ItemIgnoresTransformations);
2926     scene.addItem(text);
2927
2928     QGraphicsView view(&scene);
2929
2930     view.scale(2, 1);
2931     view.show();
2932     QApplication::setActiveWindow(&view);
2933     QVERIFY(QTest::qWaitForWindowActive(&view));
2934     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2935
2936     QRectF origExposedRect = text->exposedRect;
2937
2938     view.resize(int(0.75 * view.width()), view.height());
2939     qApp->processEvents();
2940
2941     QCOMPARE(text->exposedRect, origExposedRect);
2942
2943     // notice that the fix also goes into QGraphicsView::render()
2944     // and QGraphicsScene::render(), but in duplicated code that
2945     // is pending a refactoring, so for now we omit autotesting
2946     // these functions separately
2947 }
2948
2949 class MousePressReleaseScene : public QGraphicsScene
2950 {
2951 public:
2952     MousePressReleaseScene()
2953         : presses(0), releases(0)
2954     { }
2955     int presses;
2956     int releases;
2957
2958 protected:
2959     void mousePressEvent(QGraphicsSceneMouseEvent *event)
2960     { ++presses; QGraphicsScene::mousePressEvent(event); }
2961     void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
2962     { ++releases; QGraphicsScene::mouseReleaseEvent(event); }
2963 };
2964
2965 void tst_QGraphicsView::task180429_mouseReleaseDragMode()
2966 {
2967     MousePressReleaseScene scene;
2968
2969     QGraphicsView view(&scene);
2970     view.show();
2971
2972     sendMousePress(view.viewport(), view.viewport()->rect().center());
2973     QCOMPARE(scene.presses, 1);
2974     QCOMPARE(scene.releases, 0);
2975     sendMouseRelease(view.viewport(), view.viewport()->rect().center());
2976     QCOMPARE(scene.presses, 1);
2977     QCOMPARE(scene.releases, 1);
2978
2979     view.setDragMode(QGraphicsView::RubberBandDrag);
2980     sendMousePress(view.viewport(), view.viewport()->rect().center());
2981     QCOMPARE(scene.presses, 2);
2982     QCOMPARE(scene.releases, 1);
2983     sendMouseRelease(view.viewport(), view.viewport()->rect().center());
2984     QCOMPARE(scene.presses, 2);
2985     QCOMPARE(scene.releases, 2);
2986 }
2987
2988 void tst_QGraphicsView::task187791_setSceneCausesUpdate()
2989 {
2990     QGraphicsScene scene(0, 0, 200, 200);
2991     QGraphicsView view(&scene);
2992     view.show();
2993     qApp->setActiveWindow(&view);
2994     QVERIFY(QTest::qWaitForWindowShown(&view));
2995
2996     EventSpy updateSpy(view.viewport(), QEvent::Paint);
2997     QCOMPARE(updateSpy.count(), 0);
2998
2999     view.setScene(0);
3000     QApplication::processEvents();
3001     QTRY_COMPARE(updateSpy.count(), 1);
3002     view.setScene(&scene);
3003     QApplication::processEvents();
3004     QTRY_COMPARE(updateSpy.count(), 2);
3005 }
3006
3007 class MouseMoveCounter : public QGraphicsView
3008 {
3009 public:
3010     MouseMoveCounter() : mouseMoves(0)
3011     { }
3012     int mouseMoves;
3013 protected:
3014     void mouseMoveEvent(QMouseEvent *event)
3015     {
3016         ++mouseMoves;
3017         QGraphicsView::mouseMoveEvent(event);
3018         foreach (QGraphicsItem *item, scene()->items()) {
3019             scene()->removeItem(item);
3020             delete item;
3021         }
3022         scene()->addRect(0, 0, 50, 50);
3023         scene()->addRect(0, 0, 100, 100);
3024     }
3025 };
3026
3027 void tst_QGraphicsView::task186827_deleteReplayedItem()
3028 {
3029     // make sure the mouse is not over the window, causing spontaneous mouse moves
3030     QCursor::setPos(1, 1);
3031
3032     QGraphicsScene scene;
3033     scene.addRect(0, 0, 50, 50);
3034     scene.addRect(0, 0, 100, 100);
3035
3036     MouseMoveCounter view;
3037     view.setScene(&scene);
3038     view.show();
3039     QVERIFY(QTest::qWaitForWindowExposed(&view));
3040     view.viewport()->setMouseTracking(true);
3041
3042     QCOMPARE(view.mouseMoves, 0);
3043     {
3044         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(25, 25), Qt::NoButton, 0, 0);
3045         QApplication::sendEvent(view.viewport(), &event);
3046     }
3047     QCOMPARE(view.mouseMoves, 1);
3048     QTest::qWait(25);
3049     QTRY_COMPARE(view.mouseMoves, 1);
3050     QTest::qWait(25);
3051     {
3052         QMouseEvent event(QEvent::MouseMove, view.mapFromScene(25, 25), Qt::NoButton, 0, 0);
3053         QApplication::sendEvent(view.viewport(), &event);
3054     }
3055     QCOMPARE(view.mouseMoves, 2);
3056     QTest::qWait(15);
3057 }
3058
3059 void tst_QGraphicsView::task207546_focusCrash()
3060 {
3061     class _Widget : public QWidget
3062     {
3063     public:
3064         bool focusNextPrevChild(bool next) { return QWidget::focusNextPrevChild(next); }
3065     } widget;
3066
3067     widget.setLayout(new QVBoxLayout());
3068     QGraphicsView *gr1 = new QGraphicsView(&widget);
3069     QGraphicsView *gr2 = new QGraphicsView(&widget);
3070     widget.layout()->addWidget(gr1);
3071     widget.layout()->addWidget(gr2);
3072     widget.show();
3073     widget.activateWindow();
3074     QApplication::setActiveWindow(&widget);
3075     QVERIFY(QTest::qWaitForWindowActive(&widget));
3076     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&widget));
3077     widget.focusNextPrevChild(true);
3078     QCOMPARE(static_cast<QWidget *>(gr2), widget.focusWidget());
3079 }
3080
3081 void tst_QGraphicsView::task210599_unsetDragWhileDragging()
3082 {
3083     QGraphicsScene scene(0, 0, 400, 400);
3084     QGraphicsView view(&scene);
3085     view.setGeometry(0, 0, 200, 200);
3086     view.show();
3087
3088     QPoint origPos = QPoint(100, 100);
3089     QPoint step1Pos = QPoint(100, 110);
3090     QPoint step2Pos = QPoint(100, 120);
3091
3092     // Enable and do a drag
3093     {
3094         view.setDragMode(QGraphicsView::ScrollHandDrag);
3095         QMouseEvent press(QEvent::MouseButtonPress, origPos, Qt::LeftButton, 0, 0);
3096         QMouseEvent move(QEvent::MouseMove, step1Pos, Qt::LeftButton, 0, 0);
3097         QApplication::sendEvent(view.viewport(), &press);
3098         QApplication::sendEvent(view.viewport(), &move);
3099     }
3100
3101     // unset drag and release mouse, inverse order
3102     {
3103         view.setDragMode(QGraphicsView::NoDrag);
3104         QMouseEvent release(QEvent::MouseButtonRelease, step1Pos, Qt::LeftButton, 0, 0);
3105         QApplication::sendEvent(view.viewport(), &release);
3106     }
3107
3108     QPoint basePos = view.mapFromScene(0, 0);
3109
3110     // reset drag, and move mouse without holding button down.
3111     {
3112         view.setDragMode(QGraphicsView::ScrollHandDrag);
3113         QMouseEvent move(QEvent::MouseMove, step2Pos, Qt::LeftButton, 0, 0);
3114         QApplication::sendEvent(view.viewport(), &move);
3115     }
3116
3117     // Check that no draggin has occurred...
3118     QCOMPARE(basePos, view.mapFromScene(0, 0));
3119 }
3120
3121 void tst_QGraphicsView::task236394_sendShortcutOverrideEvent()
3122 {
3123     QGraphicsView view;
3124     view.show();
3125     QKeyEvent event(QEvent::ShortcutOverride, Qt::Key_A, 0, QString("A"));
3126     QApplication::sendEvent(&view, &event);
3127 }
3128
3129 class ChangedListener : public QObject
3130 {
3131     Q_OBJECT
3132 public:
3133     QList<QList<QRectF> > changes;
3134
3135 public slots:
3136     void changed(const QList<QRectF> &dirty)
3137     {
3138         changes << dirty;
3139     }
3140 };
3141
3142 void tst_QGraphicsView::task239729_noViewUpdate_data()
3143 {
3144     QTest::addColumn<bool>("a");
3145
3146     QTest::newRow("a") << false;
3147     QTest::newRow("b") << true;
3148 }
3149
3150 void tst_QGraphicsView::task239729_noViewUpdate()
3151 {
3152     QFETCH(bool, a);
3153     // The scene's changed signal is connected to something that isn't a view.
3154     QGraphicsScene scene;
3155     ChangedListener cl;
3156     QGraphicsView *view = 0;
3157
3158     if (a) {
3159         view = new QGraphicsView(&scene);
3160         connect(&scene, SIGNAL(changed(QList<QRectF>)), &cl, SLOT(changed(QList<QRectF>)));
3161     } else {
3162         connect(&scene, SIGNAL(changed(QList<QRectF>)), &cl, SLOT(changed(QList<QRectF>)));
3163         view = new QGraphicsView(&scene);
3164     }
3165
3166     EventSpy spy(view->viewport(), QEvent::Paint);
3167     QCOMPARE(spy.count(), 0);
3168
3169     view->show();
3170     qApp->setActiveWindow(view);
3171     QVERIFY(QTest::qWaitForWindowActive(view));
3172
3173     QTRY_VERIFY(spy.count() >= 1);
3174     spy.reset();
3175     scene.update();
3176     QApplication::processEvents();
3177     QTRY_COMPARE(spy.count(), 1);
3178
3179     delete view;
3180 }
3181
3182 void tst_QGraphicsView::task239047_fitInViewSmallViewport()
3183 {
3184     // Ensure that with a small viewport, fitInView doesn't mirror the
3185     // scene.
3186     QWidget widget;
3187     QGraphicsScene scene;
3188     QGraphicsView *view = new QGraphicsView(&scene, &widget);
3189     view->resize(3, 3);
3190     QCOMPARE(view->size(), QSize(3, 3));
3191     widget.show();
3192     view->fitInView(0, 0, 100, 100);
3193     QPointF topLeft = view->mapToScene(0, 0);
3194     QPointF bottomRight = view->mapToScene(100, 100);
3195     QVERIFY(bottomRight.x() > topLeft.x());
3196     QVERIFY(bottomRight.y() > topLeft.y());
3197
3198     view->fitInView(0, 0, 0, 100);
3199
3200     // Don't crash
3201     view->scale(0, 0);
3202     view->fitInView(0, 0, 100, 100);
3203 }
3204
3205 void tst_QGraphicsView::task245469_itemsAtPointWithClip()
3206 {
3207     QGraphicsScene scene;
3208     QGraphicsItem *parent = scene.addRect(0, 0, 100, 100);
3209     QGraphicsItem *child = new QGraphicsRectItem(40, 40, 20, 20, parent);
3210     parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
3211
3212     QGraphicsView view(&scene);
3213     view.resize(150,150);
3214     view.rotate(90);
3215     view.show();
3216     QVERIFY(QTest::qWaitForWindowExposed(&view));
3217
3218     QList<QGraphicsItem *> itemsAtCenter = view.items(view.viewport()->rect().center());
3219     QCOMPARE(itemsAtCenter, (QList<QGraphicsItem *>() << child << parent));
3220
3221     QPolygonF p = view.mapToScene(QRect(view.viewport()->rect().center(), QSize(1, 1)));
3222     QList<QGraphicsItem *> itemsAtCenter2 = scene.items(p);
3223     QCOMPARE(itemsAtCenter2, itemsAtCenter);
3224 }
3225
3226 static QGraphicsView *createSimpleViewAndScene()
3227 {
3228     QGraphicsView *view = new QGraphicsView;
3229     QGraphicsScene *scene = new QGraphicsScene;
3230     view->setScene(scene);
3231
3232     view->setBackgroundBrush(Qt::blue);
3233
3234     QGraphicsRectItem *rect = scene->addRect(0, 0, 10, 10);
3235     rect->setBrush(Qt::red);
3236     rect->setPen(Qt::NoPen);
3237     return view;
3238 }
3239
3240 class SpyItem : public QGraphicsRectItem
3241 {
3242 public:
3243     SpyItem()
3244         : QGraphicsRectItem(QRectF(0, 0, 100, 100))
3245     {
3246     }
3247
3248     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
3249     {
3250         transform = painter->transform();
3251     }
3252
3253     QTransform transform;
3254 };
3255
3256 void tst_QGraphicsView::embeddedViews()
3257 {
3258     QGraphicsView *v1 = createSimpleViewAndScene();
3259     QGraphicsView *v2 = createSimpleViewAndScene();
3260
3261     QGraphicsProxyWidget *proxy = v1->scene()->addWidget(v2);
3262
3263     SpyItem *item = new SpyItem;
3264     v2->scene()->addItem(item);
3265
3266     proxy->translate(5, 5);
3267
3268     QImage actual(64, 64, QImage::Format_ARGB32_Premultiplied);
3269     actual.fill(0);
3270     v1->QWidget::render(&actual);
3271     QTransform a = item->transform;
3272
3273     v2->QWidget::render(&actual);
3274     QTransform b = item->transform;
3275
3276     QVERIFY(a == b);
3277     delete v1;
3278 }
3279
3280 void tst_QGraphicsView::scrollAfterResize_data()
3281 {
3282     QTest::addColumn<bool>("reverse");
3283     QTest::addColumn<QTransform>("x1");
3284     QTest::addColumn<QTransform>("x2");
3285     QTest::addColumn<QTransform>("x3");
3286
3287 #if !defined(QT_NO_STYLE_PLASTIQUE)
3288     QPlastiqueStyle style;
3289 #elif !defined(QT_NO_STYLE_WINDOWS)
3290     QWindowsStyle style;
3291 #else
3292     QCommonStyle style;
3293 #endif
3294
3295     int frameWidth = style.pixelMetric(QStyle::PM_DefaultFrameWidth);
3296     int extent = style.pixelMetric(QStyle::PM_ScrollBarExtent);
3297     int inside = style.styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
3298     int viewportWidth = 300;
3299     int scrollBarIndent = viewportWidth - extent - (inside ? 4 : 2)*frameWidth;
3300
3301     QTest::newRow("normal") << false
3302                             << QTransform()
3303                             << QTransform()
3304                             << QTransform().translate(-10, 0);
3305     QTest::newRow("reverse") << true
3306                              << QTransform().translate(scrollBarIndent, 0)
3307                              << QTransform().translate(scrollBarIndent + 100, 0)
3308                              << QTransform().translate(scrollBarIndent + 110, 0);
3309 }
3310
3311 void tst_QGraphicsView::scrollAfterResize()
3312 {
3313     QFETCH(bool, reverse);
3314     QFETCH(QTransform, x1);
3315     QFETCH(QTransform, x2);
3316     QFETCH(QTransform, x3);
3317
3318 #if !defined(QT_NO_STYLE_PLASTIQUE)
3319     QPlastiqueStyle style;
3320 #elif !defined(QT_NO_STYLE_WINDOWS)
3321     QWindowsStyle style;
3322 #else
3323     QCommonStyle style;
3324 #endif
3325     QWidget toplevel;
3326
3327     QGraphicsView view(&toplevel);
3328     view.setStyle(&style);
3329     if (reverse)
3330         view.setLayoutDirection(Qt::RightToLeft);
3331
3332     view.setSceneRect(-1000, -1000, 2000, 2000);
3333     view.resize(300, 300);
3334     toplevel.show();
3335     QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
3336     view.horizontalScrollBar()->setValue(0);
3337     view.verticalScrollBar()->setValue(0);
3338     QCOMPARE(view.viewportTransform(), x1);
3339     view.resize(400, 300);
3340     QCOMPARE(view.viewportTransform(), x2);
3341     view.horizontalScrollBar()->setValue(10);
3342     QCOMPARE(view.viewportTransform(), x3);
3343 }
3344
3345 void tst_QGraphicsView::moveItemWhileScrolling_data()
3346 {
3347     QTest::addColumn<bool>("adjustForAntialiasing");
3348     QTest::addColumn<bool>("changedConnected");
3349
3350     QTest::newRow("no adjust") << false << false;
3351     QTest::newRow("adjust") << true << false;
3352     QTest::newRow("no adjust changedConnected") << false << true;
3353     QTest::newRow("adjust changedConnected") << true << true;
3354 }
3355
3356 void tst_QGraphicsView::moveItemWhileScrolling()
3357 {
3358     QFETCH(bool, adjustForAntialiasing);
3359     QFETCH(bool, changedConnected);
3360
3361     class MoveItemScrollView : public QGraphicsView
3362     {
3363     public:
3364         MoveItemScrollView()
3365         {
3366             setWindowFlags(Qt::X11BypassWindowManagerHint);
3367             setScene(new QGraphicsScene(0, 0, 1000, 1000));
3368             rect = scene()->addRect(0, 0, 10, 10);
3369             rect->setPos(50, 50);
3370             painted = false;
3371         }
3372         QRegion lastPaintedRegion;
3373         QGraphicsItem *rect;
3374         bool painted;
3375         void waitForPaintEvent()
3376         {
3377             QTimer::singleShot(2000, &eventLoop, SLOT(quit()));
3378             eventLoop.exec();
3379         }
3380     protected:
3381         QEventLoop eventLoop;
3382         void paintEvent(QPaintEvent *event)
3383         {
3384             painted = true;
3385             lastPaintedRegion = event->region();
3386             QGraphicsView::paintEvent(event);
3387             if (eventLoop.isRunning())
3388                 eventLoop.quit();
3389         }
3390     };
3391
3392     MoveItemScrollView view;
3393     view.setFrameStyle(0);
3394     view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
3395     view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
3396     view.setResizeAnchor(QGraphicsView::NoAnchor);
3397     view.setTransformationAnchor(QGraphicsView::NoAnchor);
3398     if (!adjustForAntialiasing)
3399         view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing);
3400     view.resize(200, 200);
3401     view.painted = false;
3402     view.show();
3403     if (changedConnected)
3404         QObject::connect(view.scene(), SIGNAL(changed(QList<QRectF>)), this, SLOT(dummySlot()));
3405     QVERIFY(QTest::qWaitForWindowExposed(&view));
3406     QApplication::processEvents();
3407     QTRY_VERIFY(view.painted);
3408     view.painted = false;
3409     view.lastPaintedRegion = QRegion();
3410     view.horizontalScrollBar()->setValue(view.horizontalScrollBar()->value() + 10);
3411     view.rect->moveBy(0, 10);
3412     view.waitForPaintEvent();
3413     QTRY_VERIFY(view.painted);
3414
3415     QRegion expectedRegion;
3416     expectedRegion += QRect(0, 0, 200, 200);
3417     expectedRegion -= QRect(0, 0, 190, 200);
3418     int a = adjustForAntialiasing ? 2 : 1;
3419     expectedRegion += QRect(40, 50, 10, 10).adjusted(-a, -a, a, a);
3420     expectedRegion += QRect(40, 60, 10, 10).adjusted(-a, -a, a, a);
3421     COMPARE_REGIONS(view.lastPaintedRegion, expectedRegion);
3422 }
3423
3424 void tst_QGraphicsView::centerOnDirtyItem()
3425 {
3426     QWidget toplevel;
3427
3428     QGraphicsView view(&toplevel);
3429     toplevel.setWindowFlags(view.windowFlags() | Qt::WindowStaysOnTopHint);
3430     view.resize(200, 200);
3431
3432     QGraphicsScene *scene = new QGraphicsScene;
3433     view.setScene(scene);
3434     view.setSceneRect(-1000, -1000, 2000, 2000);
3435
3436     QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 10, 10);
3437     item->setBrush(Qt::red);
3438     scene->addItem(item);
3439     view.centerOn(item);
3440
3441     toplevel.show();
3442     QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
3443     QTest::qWait(50);
3444
3445     QImage before(view.viewport()->size(), QImage::Format_ARGB32);
3446     view.viewport()->render(&before);
3447
3448     item->setPos(20, 0);
3449     view.centerOn(item);
3450
3451     QTest::qWait(50);
3452
3453     QImage after(view.viewport()->size(), QImage::Format_ARGB32);
3454     view.viewport()->render(&after);
3455
3456     QCOMPARE(before, after);
3457 }
3458
3459 void tst_QGraphicsView::mouseTracking()
3460 {
3461     // Mouse tracking should only be automatically enabled if items either accept hover events
3462     // or have a cursor set. We never disable mouse tracking if it is already enabled.
3463
3464     { // Make sure mouse tracking is disabled by default.
3465         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3466         QGraphicsView view(&scene);
3467         QVERIFY(!view.viewport()->hasMouseTracking());
3468     }
3469
3470     { // Make sure we don't disable mouse tracking in setupViewport/setScene.
3471         QGraphicsView view;
3472         QWidget *viewport = new QWidget;
3473         viewport->setMouseTracking(true);
3474         view.setViewport(viewport);
3475         QVERIFY(viewport->hasMouseTracking());
3476
3477         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3478         view.setScene(&scene);
3479         QVERIFY(viewport->hasMouseTracking());
3480     }
3481
3482     // Make sure we enable mouse tracking when having items that accept hover events.
3483     {
3484         // Adding an item to the scene after the scene is set on the view.
3485         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3486         QGraphicsView view(&scene);
3487
3488         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3489         item->setAcceptHoverEvents(true);
3490         scene.addItem(item);
3491         QVERIFY(view.viewport()->hasMouseTracking());
3492     }
3493     {
3494         // Adding an item to the scene before the scene is set on the view.
3495         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3496         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3497         item->setAcceptHoverEvents(true);
3498         scene.addItem(item);
3499
3500         QGraphicsView view(&scene);
3501         QVERIFY(view.viewport()->hasMouseTracking());
3502     }
3503     {
3504         // QGraphicsWidget implicitly accepts hover if it has window decoration.
3505         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3506         QGraphicsView view(&scene);
3507
3508         QGraphicsWidget *widget = new QGraphicsWidget;
3509         scene.addItem(widget);
3510         QVERIFY(!view.viewport()->hasMouseTracking());
3511         // Enable window decoraton.
3512         widget->setWindowFlags(Qt::Window | Qt::WindowTitleHint);
3513         QVERIFY(view.viewport()->hasMouseTracking());
3514     }
3515
3516     // Make sure we enable mouse tracking when having items with a cursor set.
3517     {
3518         // Adding an item to the scene after the scene is set on the view.
3519         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3520         QGraphicsView view(&scene);
3521
3522         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3523 #ifndef QTEST_NO_CURSOR
3524         item->setCursor(Qt::CrossCursor);
3525 #endif
3526         scene.addItem(item);
3527         QVERIFY(view.viewport()->hasMouseTracking());
3528     }
3529     {
3530         // Adding an item to the scene before the scene is set on the view.
3531         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3532         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3533 #ifndef QTEST_NO_CURSOR
3534         item->setCursor(Qt::CrossCursor);
3535 #endif
3536         scene.addItem(item);
3537
3538         QGraphicsView view(&scene);
3539         QVERIFY(view.viewport()->hasMouseTracking());
3540     }
3541
3542     // Make sure we propagate mouse tracking to all views.
3543     {
3544         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3545         QGraphicsView view1(&scene);
3546         QGraphicsView view2(&scene);
3547         QGraphicsView view3(&scene);
3548
3549         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3550 #ifndef QTEST_NO_CURSOR
3551         item->setCursor(Qt::CrossCursor);
3552 #endif
3553         scene.addItem(item);
3554
3555         QVERIFY(view1.viewport()->hasMouseTracking());
3556         QVERIFY(view2.viewport()->hasMouseTracking());
3557         QVERIFY(view3.viewport()->hasMouseTracking());
3558     }
3559 }
3560
3561 void tst_QGraphicsView::mouseTracking2()
3562 {
3563     // Make sure mouse move events propagates to the scene when
3564     // mouse tracking is explicitly enabled on the view,
3565     // even when all items ignore hover events / use default cursor.
3566
3567     QGraphicsScene scene;
3568     scene.addRect(0, 0, 100, 100);
3569
3570     QGraphicsView view(&scene);
3571     view.show();
3572     QVERIFY(QTest::qWaitForWindowExposed(&view));
3573
3574     QVERIFY(!view.viewport()->hasMouseTracking());
3575     view.viewport()->setMouseTracking(true); // Explicitly enable mouse tracking.
3576     QVERIFY(view.viewport()->hasMouseTracking());
3577
3578     EventSpy spy(&scene, QEvent::GraphicsSceneMouseMove);
3579     QCOMPARE(spy.count(), 0);
3580     QMouseEvent event(QEvent::MouseMove,view.viewport()->rect().center(), Qt::NoButton,
3581                       Qt::MouseButtons(Qt::NoButton), 0);
3582     QApplication::sendEvent(view.viewport(), &event);
3583     QCOMPARE(spy.count(), 1);
3584 }
3585
3586 void tst_QGraphicsView::mouseTracking3()
3587 {
3588     // Mouse tracking should be automatically enabled if AnchorUnderMouse is used for
3589     // view transform or resize. We never disable mouse tracking if it is already enabled.
3590
3591     { // Make sure we enable mouse tracking when using AnchorUnderMouse for view transformation.
3592         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3593         QGraphicsView view(&scene);
3594         QVERIFY(!view.viewport()->hasMouseTracking());
3595
3596         view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3597         QVERIFY(view.viewport()->hasMouseTracking());
3598     }
3599
3600     { // Make sure we enable mouse tracking when using AnchorUnderMouse for view resizing.
3601         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3602         QGraphicsView view(&scene);
3603         QVERIFY(!view.viewport()->hasMouseTracking());
3604
3605         view.setResizeAnchor(QGraphicsView::AnchorUnderMouse);
3606         QVERIFY(view.viewport()->hasMouseTracking());
3607     }
3608
3609     { // Make sure we don't disable mouse tracking in setViewport/setScene (transformation anchor).
3610         QGraphicsView view;
3611         view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3612         QVERIFY(view.viewport()->hasMouseTracking());
3613
3614         QWidget *viewport = new QWidget;
3615         view.setViewport(viewport);
3616         QVERIFY(viewport->hasMouseTracking());
3617
3618         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3619         view.setScene(&scene);
3620         QVERIFY(viewport->hasMouseTracking());
3621     }
3622
3623     { // Make sure we don't disable mouse tracking in setViewport/setScene (resize anchor).
3624         QGraphicsView view;
3625         view.setResizeAnchor(QGraphicsView::AnchorUnderMouse);
3626         QVERIFY(view.viewport()->hasMouseTracking());
3627
3628         QWidget *viewport = new QWidget;
3629         view.setViewport(viewport);
3630         QVERIFY(viewport->hasMouseTracking());
3631
3632         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3633         view.setScene(&scene);
3634         QVERIFY(viewport->hasMouseTracking());
3635     }
3636
3637     // Make sure we don't disable mouse tracking when adding an item (transformation anchor).
3638     { // Adding an item to the scene before the scene is set on the view.
3639         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3640         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3641         scene.addItem(item);
3642
3643         QGraphicsView view;
3644         view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3645         view.setScene(&scene);
3646         QVERIFY(view.viewport()->hasMouseTracking());
3647     }
3648
3649     { // Adding an item to the scene after the scene is set on the view.
3650         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3651         QGraphicsView view(&scene);
3652         view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3653
3654         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3655         scene.addItem(item);
3656         QVERIFY(view.viewport()->hasMouseTracking());
3657     }
3658
3659     // Make sure we don't disable mouse tracking when adding an item (resize anchor).
3660     { // Adding an item to the scene before the scene is set on the view.
3661         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3662         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3663         scene.addItem(item);
3664
3665         QGraphicsView view;
3666         view.setResizeAnchor(QGraphicsView::AnchorUnderMouse);
3667         view.setScene(&scene);
3668         QVERIFY(view.viewport()->hasMouseTracking());
3669     }
3670
3671     { // Adding an item to the scene after the scene is set on the view.
3672         QGraphicsScene scene(-10000, -10000, 20000, 20000);
3673         QGraphicsView view(&scene);
3674         view.setResizeAnchor(QGraphicsView::AnchorUnderMouse);
3675
3676         QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10);
3677         scene.addItem(item);
3678         QVERIFY(view.viewport()->hasMouseTracking());
3679     }
3680 }
3681
3682 class RenderTester : public QGraphicsRectItem
3683 {
3684 public:
3685     RenderTester(const QRectF &rect)
3686         : QGraphicsRectItem(rect), paints(0)
3687     { }
3688
3689     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
3690                QWidget *widget)
3691     {
3692         QGraphicsRectItem::paint(painter, option, widget);
3693         ++paints;
3694     }
3695
3696     int paints;
3697 };
3698
3699 void tst_QGraphicsView::render()
3700 {
3701     // ### This test can be much more thorough - see QGraphicsScene::render.
3702     QGraphicsScene scene;
3703     CustomView view(&scene);
3704     view.setFrameStyle(0);
3705     view.resize(200, 200);
3706     view.painted = false;
3707     view.show();
3708     QVERIFY(QTest::qWaitForWindowExposed(&view));
3709     QApplication::processEvents();
3710     QTRY_VERIFY(view.painted);
3711
3712     RenderTester *r1 = new RenderTester(QRectF(0, 0, 50, 50));
3713     RenderTester *r2 = new RenderTester(QRectF(50, 50, 50, 50));
3714     RenderTester *r3 = new RenderTester(QRectF(0, 50, 50, 50));
3715     RenderTester *r4 = new RenderTester(QRectF(50, 0, 50, 50));
3716     scene.addItem(r1);
3717     scene.addItem(r2);
3718     scene.addItem(r3);
3719     scene.addItem(r4);
3720
3721     qApp->processEvents();
3722
3723     QTRY_COMPARE(r1->paints, 1);
3724     QCOMPARE(r2->paints, 1);
3725     QCOMPARE(r3->paints, 1);
3726     QCOMPARE(r4->paints, 1);
3727
3728     QPixmap pix(200, 200);
3729     pix.fill(Qt::transparent);
3730     QPainter painter(&pix);
3731     view.render(&painter);
3732     painter.end();
3733
3734     QCOMPARE(r1->paints, 2);
3735     QCOMPARE(r2->paints, 2);
3736     QCOMPARE(r3->paints, 2);
3737     QCOMPARE(r4->paints, 2);
3738 }
3739
3740 void tst_QGraphicsView::exposeRegion()
3741 {
3742     RenderTester *item = new RenderTester(QRectF(0, 0, 20, 20));
3743     QGraphicsScene scene;
3744     scene.addItem(item);
3745
3746     item->paints = 0;
3747     CustomView view;
3748     view.setScene(&scene);
3749     view.show();
3750     qApp->setActiveWindow(&view);
3751     QVERIFY(QTest::qWaitForWindowActive(&view));
3752
3753     QTRY_VERIFY(item->paints > 0);
3754
3755     item->paints = 0;
3756     view.lastUpdateRegions.clear();
3757
3758     // Update a small area in the viewport's topLeft() and bottomRight().
3759     // (the boundingRect() of this area covers the entire viewport).
3760     QWidget *viewport = view.viewport();
3761     QRegion expectedExposeRegion = QRect(0, 0, 5, 5);
3762     expectedExposeRegion += QRect(viewport->rect().bottomRight() - QPoint(5, 5), QSize(5, 5));
3763     viewport->update(expectedExposeRegion);
3764     QApplication::processEvents();
3765
3766     // Make sure it triggers correct repaint on the view.
3767     QTRY_COMPARE(view.lastUpdateRegions.size(), 1);
3768     COMPARE_REGIONS(view.lastUpdateRegions.at(0), expectedExposeRegion);
3769
3770     // Make sure the item didn't get any repaints.
3771 #ifndef Q_OS_MAC
3772     QCOMPARE(item->paints, 0);
3773 #endif
3774 }
3775
3776 void tst_QGraphicsView::update_data()
3777 {
3778     // In view.viewport() coordinates. (viewport rect: QRect(0, 0, 200, 200))
3779     QTest::addColumn<QRect>("updateRect");
3780     QTest::newRow("empty") << QRect();
3781     QTest::newRow("outside left") << QRect(-200, 0, 100, 100);
3782     QTest::newRow("outside right") << QRect(400, 0 ,100, 100);
3783     QTest::newRow("outside top") << QRect(0, -200, 100, 100);
3784     QTest::newRow("outside bottom") << QRect(0, 400, 100, 100);
3785     QTest::newRow("partially inside left") << QRect(-50, 0, 100, 100);
3786     QTest::newRow("partially inside right") << QRect(-150, 0, 100, 100);
3787     QTest::newRow("partially inside top") << QRect(0, -150, 100, 100);
3788     QTest::newRow("partially inside bottom") << QRect(0, 150, 100, 100);
3789     QTest::newRow("on topLeft edge") << QRect(-100, -100, 100, 100);
3790     QTest::newRow("on topRight edge") << QRect(200, -100, 100, 100);
3791     QTest::newRow("on bottomRight edge") << QRect(200, 200, 100, 100);
3792     QTest::newRow("on bottomLeft edge") << QRect(-200, 200, 100, 100);
3793     QTest::newRow("inside topLeft") << QRect(-99, -99, 100, 100);
3794     QTest::newRow("inside topRight") << QRect(199, -99, 100, 100);
3795     QTest::newRow("inside bottomRight") << QRect(199, 199, 100, 100);
3796     QTest::newRow("inside bottomLeft") << QRect(-199, 199, 100, 100);
3797     QTest::newRow("large1") << QRect(50, -100, 100, 400);
3798     QTest::newRow("large2") << QRect(-100, 50, 400, 100);
3799     QTest::newRow("large3") << QRect(-100, -100, 400, 400);
3800     QTest::newRow("viewport rect") << QRect(0, 0, 200, 200);
3801 }
3802
3803 void tst_QGraphicsView::update()
3804 {
3805     QFETCH(QRect, updateRect);
3806
3807     // some window manager resize the toplevel to max screen size
3808     // so we must make our view a child (no layout!) of a dummy toplevel
3809     // to ensure that it's really 200x200 pixels
3810     QWidget toplevel;
3811
3812     // Create a view with viewport rect equal to QRect(0, 0, 200, 200).
3813     QGraphicsScene dummyScene;
3814     CustomView view(0, &toplevel);
3815     view.setScene(&dummyScene);
3816     view.ensurePolished(); // must ensure polished to get content margins right
3817     int left, top, right, bottom;
3818     view.getContentsMargins(&left, &top, &right, &bottom);
3819     view.resize(200 + left + right, 200 + top + bottom);
3820     toplevel.show();
3821     QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
3822
3823
3824     QApplication::setActiveWindow(&toplevel);
3825     QApplication::processEvents();
3826     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&toplevel));
3827
3828     const QRect viewportRect = view.viewport()->rect();
3829     QCOMPARE(viewportRect, QRect(0, 0, 200, 200));
3830
3831 #if defined QT_BUILD_INTERNAL
3832     const bool intersects = updateRect.intersects(viewportRect);
3833     QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
3834     QTRY_COMPARE(viewPrivate->updateRect(updateRect), intersects);
3835     QApplication::processEvents();
3836
3837     view.lastUpdateRegions.clear();
3838     viewPrivate->processPendingUpdates();
3839     QVERIFY(viewPrivate->dirtyRegion.isEmpty());
3840     QVERIFY(viewPrivate->dirtyBoundingRect.isEmpty());
3841     QApplication::processEvents();
3842     if (!intersects) {
3843         QTRY_VERIFY(view.lastUpdateRegions.isEmpty());
3844     } else {
3845         QTRY_COMPARE(view.lastUpdateRegions.size(), 1);
3846         QTRY_COMPARE(view.lastUpdateRegions.at(0), QRegion(updateRect) & viewportRect);
3847     }
3848     QTRY_VERIFY(!viewPrivate->fullUpdatePending);
3849 #endif
3850 }
3851
3852 void tst_QGraphicsView::update2_data()
3853 {
3854     QTest::addColumn<qreal>("penWidth");
3855     QTest::addColumn<bool>("antialiasing");
3856     QTest::addColumn<bool>("changedConnected");
3857
3858     // Anti-aliased.
3859     QTest::newRow("pen width: 0.0, antialiasing: true") << qreal(0.0) << true << false;
3860     QTest::newRow("pen width: 1.5, antialiasing: true") << qreal(1.5) << true << false;
3861     QTest::newRow("pen width: 2.0, antialiasing: true") << qreal(2.0) << true << false;
3862     QTest::newRow("pen width: 3.0, antialiasing: true") << qreal(3.0) << true << false;
3863
3864     // Aliased.
3865     QTest::newRow("pen width: 0.0, antialiasing: false") << qreal(0.0) << false << false;
3866     QTest::newRow("pen width: 1.5, antialiasing: false") << qreal(1.5) << false << false;
3867     QTest::newRow("pen width: 2.0, antialiasing: false") << qreal(2.0) << false << false;
3868     QTest::newRow("pen width: 3.0, antialiasing: false") << qreal(3.0) << false << false;
3869
3870     // changed() connected
3871     QTest::newRow("pen width: 0.0, antialiasing: false, changed") << qreal(0.0) << false << true;
3872     QTest::newRow("pen width: 1.5, antialiasing: true, changed") << qreal(1.5) << true << true;
3873     QTest::newRow("pen width: 2.0, antialiasing: false, changed") << qreal(2.0) << false << true;
3874     QTest::newRow("pen width: 3.0, antialiasing: true, changed") << qreal(3.0) << true << true;
3875 }
3876
3877 void tst_QGraphicsView::update2()
3878 {
3879     QFETCH(qreal, penWidth);
3880     QFETCH(bool, antialiasing);
3881     QFETCH(bool, changedConnected);
3882
3883     // Create a rect item.
3884     const QRectF rawItemRect(-50.4, -50.3, 100.2, 100.1);
3885     CountPaintItem *rect = new CountPaintItem(rawItemRect);
3886     QPen pen;
3887     pen.setWidthF(penWidth);
3888     rect->setPen(pen);
3889
3890     // Add item to a scene.
3891     QGraphicsScene scene(-100, -100, 200, 200);
3892     if (changedConnected)
3893         QObject::connect(&scene, SIGNAL(changed(QList<QRectF>)), this, SLOT(dummySlot()));
3894
3895     scene.addItem(rect);
3896
3897     // Create a view on the scene.
3898     CustomView view(&scene);
3899     view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, !antialiasing);
3900     view.setRenderHint(QPainter::Antialiasing, antialiasing);
3901     view.setFrameStyle(0);
3902     view.resize(200, 200);
3903     view.show();
3904     qApp->setActiveWindow(&view);
3905     QVERIFY(QTest::qWaitForWindowActive(&view));
3906     QTRY_VERIFY(rect->numPaints > 0);
3907
3908     // Calculate expected update region for the rect.
3909     QRectF expectedItemBoundingRect = rawItemRect;
3910     const qreal halfPenWidth = penWidth / qreal(2.0);
3911     expectedItemBoundingRect.adjust(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth);
3912     QCOMPARE(rect->boundingRect(), expectedItemBoundingRect);
3913
3914     QRect expectedItemDeviceBoundingRect = rect->deviceTransform(view.viewportTransform())
3915                                            .mapRect(expectedItemBoundingRect).toAlignedRect();
3916     if (antialiasing)
3917         expectedItemDeviceBoundingRect.adjust(-2, -2, 2, 2);
3918     else
3919         expectedItemDeviceBoundingRect.adjust(-1, -1, 1, 1);
3920     const QRegion expectedUpdateRegion(expectedItemDeviceBoundingRect);
3921
3922     // Reset.
3923     rect->numPaints = 0;
3924     view.lastUpdateRegions.clear();
3925     view.painted = false;
3926
3927     rect->update();
3928     QTRY_VERIFY(view.painted);
3929
3930 #ifndef Q_OS_MAC //cocoa doesn't support drawing regions
3931     QTRY_VERIFY(view.painted);
3932     QCOMPARE(view.lastUpdateRegions.size(), 1);
3933     QCOMPARE(view.lastUpdateRegions.at(0), expectedUpdateRegion);
3934 #endif
3935 }
3936
3937 void tst_QGraphicsView::update_ancestorClipsChildrenToShape()
3938 {
3939     QGraphicsScene scene(-150, -150, 300, 300);
3940
3941     /*
3942     Add three rects:
3943
3944     +------------------+
3945     | child            |
3946     | +--------------+ |
3947     | | parent       | |
3948     | |  +-----------+ |
3949     | |  |grandParent| |
3950     | |  +-----------+ |
3951     | +--------------+ |
3952     +------------------+
3953
3954     ... where both the parent and the grand parent clips children to shape.
3955     */
3956     QApplication::processEvents(); // Get rid of pending update.
3957
3958     QGraphicsRectItem *grandParent = static_cast<QGraphicsRectItem *>(scene.addRect(0, 0, 50, 50));
3959     grandParent->setBrush(Qt::black);
3960     grandParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
3961
3962     QGraphicsRectItem *parent = static_cast<QGraphicsRectItem *>(scene.addRect(-50, -50, 100, 100));
3963     parent->setBrush(QColor(0, 0, 255, 125));
3964     parent->setParentItem(grandParent);
3965     parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
3966
3967     QGraphicsRectItem *child = static_cast<QGraphicsRectItem *>(scene.addRect(-100, -100, 200, 200));
3968     child->setBrush(QColor(255, 0, 0, 125));
3969     child->setParentItem(parent);
3970
3971     CustomView view(&scene);
3972     view.show();
3973     qApp->setActiveWindow(&view);
3974     QVERIFY(QTest::qWaitForWindowActive(&view));
3975     QTRY_VERIFY(view.painted);
3976
3977     view.lastUpdateRegions.clear();
3978     view.painted = false;
3979
3980     // Call child->update() and make sure the updated area is within the ancestors' clip.
3981     QRectF expected = child->deviceTransform(view.viewportTransform()).mapRect(child->boundingRect());
3982     expected &= grandParent->deviceTransform(view.viewportTransform()).mapRect(grandParent->boundingRect());
3983
3984     child->update();
3985     QTRY_VERIFY(view.painted);
3986
3987 #ifndef Q_OS_MAC //cocoa doesn't support drawing regions
3988     QTRY_VERIFY(view.painted);
3989     QCOMPARE(view.lastUpdateRegions.size(), 1);
3990     QCOMPARE(view.lastUpdateRegions.at(0), QRegion(expected.toAlignedRect()));
3991 #endif
3992 }
3993
3994 void tst_QGraphicsView::update_ancestorClipsChildrenToShape2()
3995 {
3996     QGraphicsScene scene(-150, -150, 300, 300);
3997
3998     /*
3999     Add two rects:
4000
4001     +------------------+
4002     | child            |
4003     | +--------------+ |
4004     | | parent       | |
4005     | |              | |
4006     | |              | |
4007     | |              | |
4008     | +--------------+ |
4009     +------------------+
4010
4011     ... where the parent has no contents and clips the child to shape.
4012     */
4013     QApplication::processEvents(); // Get rid of pending update.
4014
4015     QGraphicsRectItem *parent = static_cast<QGraphicsRectItem *>(scene.addRect(-50, -50, 100, 100));
4016     parent->setBrush(QColor(0, 0, 255, 125));
4017     parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
4018     parent->setFlag(QGraphicsItem::ItemHasNoContents);
4019
4020     QGraphicsRectItem *child = static_cast<QGraphicsRectItem *>(scene.addRect(-100, -100, 200, 200));
4021     child->setBrush(QColor(255, 0, 0, 125));
4022     child->setParentItem(parent);
4023
4024     CustomView view(&scene);
4025     view.show();
4026     qApp->setActiveWindow(&view);
4027     QVERIFY(QTest::qWaitForWindowActive(&view));
4028     QTRY_VERIFY(view.painted);
4029
4030     view.lastUpdateRegions.clear();
4031     view.painted = false;
4032
4033     // Call child->update() and make sure the updated area is within its parent's clip.
4034     QRectF expected = child->deviceTransform(view.viewportTransform()).mapRect(child->boundingRect());
4035     expected &= parent->deviceTransform(view.viewportTransform()).mapRect(parent->boundingRect());
4036
4037     child->update();
4038     QTRY_VERIFY(view.painted);
4039
4040 #ifndef Q_OS_MAC //cocoa doesn't support drawing regions
4041     QTRY_VERIFY(view.painted);
4042     QCOMPARE(view.lastUpdateRegions.size(), 1);
4043     QCOMPARE(view.lastUpdateRegions.at(0), QRegion(expected.toAlignedRect()));
4044 #endif
4045
4046     QTest::qWait(50);
4047
4048     view.lastUpdateRegions.clear();
4049     view.painted = false;
4050
4051     // Invalidate the parent's geometry and trigger an update.
4052     // The update area should be clipped to the parent's bounding rect for 'normal' items,
4053     // but in this case the item has no contents (ItemHasNoContents) and its geometry
4054     // is invalidated, which means we cannot clip the child update. So, the expected
4055     // area is exactly the same as the child's bounding rect (adjusted for antialiasing).
4056     parent->setRect(parent->rect().adjusted(-10, -10, -10, -10));
4057     expected = child->deviceTransform(view.viewportTransform()).mapRect(child->boundingRect());
4058     expected.adjust(-2, -2, 2, 2); // Antialiasing
4059
4060 #ifndef Q_OS_MAC //cocoa doesn't support drawing regions
4061     QTRY_VERIFY(view.painted);
4062     QCOMPARE(view.lastUpdateRegions.size(), 1);
4063     QCOMPARE(view.lastUpdateRegions.at(0), QRegion(expected.toAlignedRect()));
4064 #endif
4065 }
4066
4067 class FocusItem : public QGraphicsRectItem
4068 {
4069 public:
4070     FocusItem() : QGraphicsRectItem(0, 0, 20, 20) {
4071         m_viewHasIMEnabledInFocusInEvent = false;
4072     }
4073
4074     void focusInEvent(QFocusEvent * /* event */)
4075     {
4076         QGraphicsView *view = scene()->views().first();
4077         m_viewHasIMEnabledInFocusInEvent = view->testAttribute(Qt::WA_InputMethodEnabled);
4078     }
4079
4080     bool m_viewHasIMEnabledInFocusInEvent;
4081 };
4082
4083 void tst_QGraphicsView::inputMethodSensitivity()
4084 {
4085     QGraphicsScene scene;
4086     QGraphicsView view(&scene);
4087     view.show();
4088     QApplication::setActiveWindow(&view);
4089     QVERIFY(QTest::qWaitForWindowActive(&view));
4090     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
4091
4092     FocusItem *item = new FocusItem;
4093
4094     view.setAttribute(Qt::WA_InputMethodEnabled, true);
4095
4096     scene.addItem(item);
4097     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4098
4099     scene.removeItem(item);
4100     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4101
4102     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
4103     scene.addItem(item);
4104     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4105
4106     scene.removeItem(item);
4107     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4108
4109     scene.addItem(item);
4110     scene.setFocusItem(item);
4111     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4112
4113     scene.removeItem(item);
4114     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4115
4116     item->setFlag(QGraphicsItem::ItemIsFocusable);
4117     scene.addItem(item);
4118     scene.setFocusItem(item);
4119     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
4120     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true);
4121     QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true);
4122
4123     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, false);
4124     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4125
4126     item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
4127     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true);
4128
4129     // introduce another item that is focusable but does not accept input methods
4130     FocusItem *item2 = new FocusItem;
4131     item2->setFlag(QGraphicsItem::ItemIsFocusable);
4132     scene.addItem(item2);
4133     scene.setFocusItem(item2);
4134     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4135     QCOMPARE(item2->m_viewHasIMEnabledInFocusInEvent, false);
4136     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item2));
4137
4138     scene.setFocusItem(item);
4139     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true);
4140     QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true);
4141     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
4142
4143     view.setScene(0);
4144     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4145     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
4146
4147     view.setScene(&scene);
4148     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true);
4149     QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true);
4150     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
4151
4152     scene.setFocusItem(item2);
4153     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4154     QCOMPARE(item2->m_viewHasIMEnabledInFocusInEvent, false);
4155     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item2));
4156
4157     view.setScene(0);
4158     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4159     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item2));
4160
4161     scene.setFocusItem(item);
4162     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false);
4163     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
4164
4165     view.setScene(&scene);
4166     QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true);
4167     QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true);
4168     QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item));
4169 }
4170
4171 void tst_QGraphicsView::inputContextReset()
4172 {
4173     PlatformInputContext inputContext;
4174     QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
4175     inputMethodPrivate->testContext = &inputContext;
4176
4177     QGraphicsScene scene;
4178     QGraphicsView view(&scene);
4179     QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
4180
4181     view.show();
4182     QApplication::setActiveWindow(&view);
4183     QVERIFY(QTest::qWaitForWindowActive(&view));
4184     QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
4185
4186     QGraphicsItem *item1 = new QGraphicsRectItem;
4187     item1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
4188
4189     inputContext.m_resetCallCount = 0;
4190     inputContext.m_commitCallCount = 0;
4191     scene.addItem(item1);
4192     QCOMPARE(inputContext.m_resetCallCount, 0);
4193     QCOMPARE(inputContext.m_commitCallCount, 0);
4194
4195     scene.setFocusItem(item1);
4196     QCOMPARE(scene.focusItem(), (QGraphicsItem *)item1);
4197     QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
4198     QCOMPARE(inputContext.m_resetCallCount, 0);
4199     QCOMPARE(inputContext.m_commitCallCount, 0);
4200
4201     scene.setFocusItem(0);
4202     // the input context is reset twice, once because an item has lost focus and again because
4203     // the Qt::WA_InputMethodEnabled flag is cleared because no item has focus.
4204     //    QEXPECT_FAIL("", "QTBUG-22454", Abort);
4205     QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 2);
4206
4207     // introduce another item that is focusable but does not accept input methods
4208     QGraphicsItem *item2 = new QGraphicsRectItem;
4209     item2->setFlags(QGraphicsItem::ItemIsFocusable);
4210     scene.addItem(item2);
4211
4212     inputContext.m_resetCallCount = 0;
4213     inputContext.m_commitCallCount = 0;
4214     scene.setFocusItem(item2);
4215     QCOMPARE(inputContext.m_resetCallCount, 0);
4216     QCOMPARE(inputContext.m_commitCallCount, 0);
4217
4218     scene.setFocusItem(item1);
4219     QCOMPARE(inputContext.m_resetCallCount, 0);
4220     QCOMPARE(inputContext.m_commitCallCount, 0);
4221
4222     // test changing between between items that accept input methods.
4223     item2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
4224     scene.setFocusItem(item2);
4225     QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 1);
4226 }
4227
4228 void tst_QGraphicsView::indirectPainting()
4229 {
4230     class MyScene : public QGraphicsScene
4231     { public:
4232         MyScene() : QGraphicsScene(), drawCount(0) {}
4233         void drawItems(QPainter *, int, QGraphicsItem **, const QStyleOptionGraphicsItem *, QWidget *)
4234         { ++drawCount; }
4235         int drawCount;
4236     };
4237
4238     MyScene scene;
4239     QGraphicsItem *item = scene.addRect(0, 0, 50, 50);
4240
4241     QGraphicsView view(&scene);
4242     view.setOptimizationFlag(QGraphicsView::IndirectPainting);
4243     view.show();
4244     QVERIFY(QTest::qWaitForWindowExposed(&view));
4245     QTest::qWait(100);
4246
4247     scene.drawCount = 0;
4248     item->setPos(20, 20);
4249     QApplication::processEvents();
4250     QTRY_VERIFY(scene.drawCount > 0);
4251 }
4252
4253 void tst_QGraphicsView::compositionModeInDrawBackground()
4254 {
4255     class MyView : public QGraphicsView
4256     { public:
4257         MyView(QGraphicsScene *scene) : QGraphicsView(scene),
4258         painted(false), compositionMode(QPainter::CompositionMode_SourceOver) {}
4259         bool painted;
4260         QPainter::CompositionMode compositionMode;
4261         void drawBackground(QPainter *painter, const QRectF &)
4262         {
4263             compositionMode = painter->compositionMode();
4264             painted = true;
4265         }
4266     };
4267
4268     QGraphicsScene dummy;
4269     MyView view(&dummy);
4270     view.show();
4271     QVERIFY(QTest::qWaitForWindowExposed(&view));
4272
4273     // Make sure the painter's composition mode is SourceOver in drawBackground.
4274     QTRY_VERIFY(view.painted);
4275     QCOMPARE(view.compositionMode, QPainter::CompositionMode_SourceOver);
4276
4277     view.painted = false;
4278     view.setCacheMode(QGraphicsView::CacheBackground);
4279     view.viewport()->update();
4280
4281     // Make sure the painter's composition mode is SourceOver in drawBackground
4282     // with background cache enabled.
4283     QTRY_VERIFY(view.painted);
4284     QCOMPARE(view.compositionMode, QPainter::CompositionMode_SourceOver);
4285 }
4286 void tst_QGraphicsView::task253415_reconnectUpdateSceneOnSceneChanged()
4287 {
4288     QGraphicsView view;
4289     QGraphicsView dummyView;
4290     view.setWindowFlags(view.windowFlags() | Qt::WindowStaysOnTopHint);
4291     view.resize(200, 200);
4292
4293     QGraphicsScene scene1;
4294     QObject::connect(&scene1, SIGNAL(changed(QList<QRectF>)), &dummyView, SLOT(updateScene(QList<QRectF>)));
4295     view.setScene(&scene1);
4296
4297     QTest::qWait(12);
4298
4299     QGraphicsScene scene2;
4300     QObject::connect(&scene2, SIGNAL(changed(QList<QRectF>)), &dummyView, SLOT(updateScene(QList<QRectF>)));
4301     view.setScene(&scene2);
4302
4303     QTest::qWait(12);
4304
4305     bool wasConnected2 = QObject::disconnect(&scene2, SIGNAL(changed(QList<QRectF>)), &view, 0);
4306     QVERIFY(wasConnected2);
4307 }
4308
4309 void tst_QGraphicsView::task255529_transformationAnchorMouseAndViewportMargins()
4310 {
4311 #if defined(Q_OS_WINCE)
4312     QSKIP("Qt/CE does not implement mouse tracking at this point");
4313 #endif
4314     QGraphicsScene scene(-100, -100, 200, 200);
4315     scene.addRect(QRectF(-50, -50, 100, 100), QPen(Qt::black), QBrush(Qt::blue));
4316
4317     class VpGraphicsView: public QGraphicsView
4318     {
4319     public:
4320         VpGraphicsView(QGraphicsScene *scene, QWidget *parent=0)
4321             : QGraphicsView(scene, parent)
4322         {
4323             setViewportMargins(8, 16, 12, 20);
4324             setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
4325             setMouseTracking(true);
4326         }
4327     };
4328
4329     VpGraphicsView view(&scene);
4330     view.setWindowFlags(Qt::X11BypassWindowManagerHint);
4331     view.show();
4332     qApp->setActiveWindow(&view);
4333     QVERIFY(QTest::qWaitForWindowActive(&view));
4334     QPoint mouseViewPos(20, 20);
4335     sendMouseMove(view.viewport(), mouseViewPos);
4336
4337     QPointF mouseScenePos = view.mapToScene(mouseViewPos);
4338     view.setTransform(QTransform().scale(5, 5).rotate(5, Qt::ZAxis), true);
4339
4340     QPointF newMouseScenePos = view.mapToScene(mouseViewPos);
4341
4342     qreal slack = 1;
4343
4344     const qreal dx = qAbs(newMouseScenePos.x() - mouseScenePos.x());
4345     const qreal dy = qAbs(newMouseScenePos.y() - mouseScenePos.y());
4346     const QByteArray message = QString::fromLatin1("QTBUG-22455, distance: dx=%1, dy=%2 slack=%3 (%4).").
4347                      arg(dx).arg(dy).arg(slack).arg(qApp->style()->metaObject()->className()).toLocal8Bit();
4348     // This is highly unstable (observed to pass on Windows and some Linux configurations).
4349 #ifdef Q_OS_MAC
4350     QEXPECT_FAIL("", message.constData(), Abort);
4351 #endif
4352     QVERIFY2(dx < slack && dy < slack, message.constData());
4353 }
4354
4355 void tst_QGraphicsView::task259503_scrollingArtifacts()
4356 {
4357     QGraphicsScene scene(0, 0, 800, 600);
4358
4359     QGraphicsRectItem card;
4360     card.setRect(0, 0, 50, 50);
4361     card.setPen(QPen(Qt::darkRed));
4362     card.setBrush(QBrush(Qt::cyan));
4363     card.setZValue(2.0);
4364     card.setPos(300, 300);
4365     scene.addItem(&card);
4366
4367     class SAGraphicsView: public QGraphicsView
4368     {
4369     public:
4370         SAGraphicsView(QGraphicsScene *scene)
4371             : QGraphicsView(scene)
4372             , itSTimeToTest(false)
4373         {
4374             setViewportUpdateMode( QGraphicsView::MinimalViewportUpdate );
4375             resize(QSize(640, 480));
4376         }
4377
4378         QRegion updateRegion;
4379         bool itSTimeToTest;
4380
4381         void paintEvent(QPaintEvent *event)
4382         {
4383             QGraphicsView::paintEvent(event);
4384
4385             if (itSTimeToTest)
4386             {
4387                 QEXPECT_FAIL("", "QTBUG-24296", Continue);
4388                 QCOMPARE(event->region(), updateRegion);
4389             }
4390         }
4391     };
4392
4393     SAGraphicsView view(&scene);
4394     view.show();
4395     QVERIFY(QTest::qWaitForWindowExposed(&view));
4396
4397     int hsbValue = view.horizontalScrollBar()->value();
4398     view.horizontalScrollBar()->setValue(hsbValue / 2);
4399     QTest::qWait(10);
4400     view.horizontalScrollBar()->setValue(0);
4401     QTest::qWait(10);
4402
4403     QRect itemDeviceBoundingRect = card.deviceTransform(view.viewportTransform()).mapRect(card.boundingRect()).toRect();
4404     itemDeviceBoundingRect.adjust(-2, -2, 2, 2);
4405     view.updateRegion = itemDeviceBoundingRect;
4406     view.updateRegion += itemDeviceBoundingRect.translated(-100, 0);
4407     view.itSTimeToTest = true;
4408     card.setPos(200, 300);
4409     QTest::qWait(10);
4410 }
4411
4412 void tst_QGraphicsView::QTBUG_4151_clipAndIgnore_data()
4413 {
4414     QTest::addColumn<bool>("clip");
4415     QTest::addColumn<bool>("ignoreTransformations");
4416     QTest::addColumn<int>("numItems");
4417
4418     QTest::newRow("none") << false << false << 3;
4419     QTest::newRow("clip") << true << false << 3;
4420     QTest::newRow("ignore") << false << true << 3;
4421     QTest::newRow("clip+ignore") << true << true << 3;
4422 }
4423
4424 void tst_QGraphicsView::QTBUG_4151_clipAndIgnore()
4425 {
4426     QFETCH(bool, clip);
4427     QFETCH(bool, ignoreTransformations);
4428     QFETCH(int, numItems);
4429
4430     QGraphicsScene scene;
4431
4432     QGraphicsRectItem *parent = new QGraphicsRectItem(QRectF(0, 0, 50, 50), 0);
4433     QGraphicsRectItem *child = new QGraphicsRectItem(QRectF(-10, -10, 40, 40), parent);
4434     QGraphicsRectItem *ignore = new QGraphicsRectItem(QRectF(60, 60, 50, 50), 0);
4435
4436     if (clip)
4437         parent->setFlags(QGraphicsItem::ItemClipsChildrenToShape);
4438     if (ignoreTransformations)
4439         ignore->setFlag(QGraphicsItem::ItemIgnoresTransformations);
4440
4441     parent->setBrush(Qt::red);
4442     child->setBrush(QColor(0, 0, 255, 128));
4443     ignore->setBrush(Qt::green);
4444
4445     scene.addItem(parent);
4446     scene.addItem(ignore);
4447
4448     QGraphicsView view(&scene);
4449     view.setFrameStyle(0);
4450     view.resize(75, 75);
4451     view.show();
4452     view.activateWindow();
4453     QVERIFY(QTest::qWaitForWindowActive(&view));
4454     QCOMPARE(QApplication::activeWindow(), (QWidget *)&view);
4455
4456     QCOMPARE(view.items(view.rect()).size(), numItems);
4457 }
4458
4459 void tst_QGraphicsView::QTBUG_5859_exposedRect()
4460 {
4461     class CustomScene : public QGraphicsScene
4462     {
4463     public:
4464         CustomScene(const QRectF &rect) : QGraphicsScene(rect) { }
4465         void drawBackground(QPainter * /* painter */, const QRectF &rect)
4466         { lastBackgroundExposedRect = rect; }
4467         QRectF lastBackgroundExposedRect;
4468     };
4469
4470     class CustomRectItem : public QGraphicsRectItem
4471     {
4472     public:
4473         CustomRectItem(const QRectF &rect) : QGraphicsRectItem(rect)
4474         { setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); }
4475         void paint(QPainter * /* painter */, const QStyleOptionGraphicsItem *option, QWidget * /* widget */ = 0)
4476         { lastExposedRect = option->exposedRect; }
4477         QRectF lastExposedRect;
4478     };
4479
4480     CustomScene scene(QRectF(0,0,50,50));
4481
4482     CustomRectItem item(scene.sceneRect());
4483
4484     scene.addItem(&item);
4485
4486     QGraphicsView view(&scene);
4487     view.scale(4.15, 4.15);
4488     view.show();
4489     qApp->setActiveWindow(&view);
4490     QVERIFY(QTest::qWaitForWindowActive(&view));
4491
4492     view.viewport()->repaint(10,10,20,20);
4493     QApplication::processEvents();
4494
4495     QCOMPARE(item.lastExposedRect, scene.lastBackgroundExposedRect);
4496 }
4497
4498 #ifndef QTEST_NO_CURSOR
4499 void tst_QGraphicsView::QTBUG_7438_cursor()
4500 {
4501     QGraphicsScene scene;
4502     QGraphicsItem *item = scene.addRect(QRectF(-10, -10, 20, 20));
4503     item->setFlag(QGraphicsItem::ItemIsMovable);
4504
4505     QGraphicsView view(&scene);
4506     view.setFixedSize(400, 400);
4507     view.show();
4508     QVERIFY(QTest::qWaitForWindowExposed(&view));
4509
4510     QCOMPARE(view.viewport()->cursor().shape(), QCursor().shape());
4511     view.viewport()->setCursor(Qt::PointingHandCursor);
4512     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
4513     sendMouseMove(view.viewport(), view.mapFromScene(0, 0));
4514     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
4515     sendMousePress(view.viewport(), view.mapFromScene(0, 0));
4516     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
4517     sendMouseRelease(view.viewport(), view.mapFromScene(0, 0));
4518     QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor);
4519 }
4520 #endif
4521
4522 class GraphicsItemWithHover : public QGraphicsRectItem
4523 {
4524 public:
4525     GraphicsItemWithHover()
4526         : receivedEnterEvent(false), receivedLeaveEvent(false),
4527           enterWidget(0), leaveWidget(0)
4528     {
4529         setRect(0, 0, 100, 100);
4530         setAcceptHoverEvents(true);
4531     }
4532
4533     bool sceneEvent(QEvent *event)
4534     {
4535         if (event->type() == QEvent::GraphicsSceneHoverEnter) {
4536             receivedEnterEvent = true;
4537             enterWidget = static_cast<QGraphicsSceneHoverEvent *>(event)->widget();
4538         } else if (event->type() == QEvent::GraphicsSceneHoverLeave) {
4539             receivedLeaveEvent = true;
4540             leaveWidget = static_cast<QGraphicsSceneHoverEvent *>(event)->widget();
4541         }
4542         return QGraphicsRectItem::sceneEvent(event);
4543     }
4544
4545     bool receivedEnterEvent;
4546     bool receivedLeaveEvent;
4547     QWidget *enterWidget;
4548     QWidget *leaveWidget;
4549 };
4550
4551 void tst_QGraphicsView::hoverLeave()
4552 {
4553     QGraphicsScene scene;
4554     QGraphicsView view(&scene);
4555     GraphicsItemWithHover *item = new GraphicsItemWithHover;
4556     scene.addItem(item);
4557
4558     // move the cursor out of the way
4559     QCursor::setPos(1,1);
4560
4561     view.show();
4562     qApp->setActiveWindow(&view);
4563     QVERIFY(QTest::qWaitForWindowActive(&view));
4564
4565     QPoint pos = view.viewport()->mapToGlobal(view.mapFromScene(item->mapToScene(10, 10)));
4566     QCursor::setPos(pos);
4567     QTest::qWait(200);
4568     QVERIFY(item->receivedEnterEvent);
4569     QCOMPARE(item->enterWidget, view.viewport());
4570
4571     QCursor::setPos(1,1);
4572     QTest::qWait(200);
4573 #ifdef Q_OS_MAC
4574     QEXPECT_FAIL("", "QTBUG-26274 - behaviour regression", Abort);
4575 #endif
4576     QVERIFY(item->receivedLeaveEvent);
4577     QCOMPARE(item->leaveWidget, view.viewport());
4578 }
4579
4580 class IMItem : public QGraphicsRectItem
4581 {
4582 public:
4583     IMItem(QGraphicsItem *parent = 0):
4584         QGraphicsRectItem(QRectF(0, 0, 20, 20), parent)
4585     {
4586         setFlag(QGraphicsItem::ItemIsFocusable, true);
4587         setFlag(QGraphicsItem::ItemAcceptsInputMethod, true);
4588     }
4589
4590     QVariant inputMethodQuery(Qt::InputMethodQuery) const
4591     {
4592         return mf;
4593     }
4594
4595     static QRectF mf;
4596 };
4597
4598 QRectF IMItem::mf(1.5, 1.6, 10, 10);
4599
4600 void tst_QGraphicsView::QTBUG_16063_microFocusRect()
4601 {
4602     QGraphicsScene scene;
4603     IMItem *item = new IMItem();
4604     scene.addItem(item);
4605
4606     QGraphicsView view(&scene);
4607
4608     view.setFixedSize(40, 40);
4609     view.show();
4610     QVERIFY(QTest::qWaitForWindowActive(&view));
4611
4612     scene.setFocusItem(item);
4613     view.setFocus();
4614     QRectF mfv = view.inputMethodQuery(Qt::ImMicroFocus).toRectF();
4615     QCOMPARE(mfv, IMItem::mf.translated(-view.mapToScene(view.sceneRect().toRect()).boundingRect().topLeft()));
4616 }
4617
4618 QTEST_MAIN(tst_QGraphicsView)
4619 #include "tst_qgraphicsview.moc"