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

source code of qtbase/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp