/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../shared/util.h" //TESTED_CLASS= //TESTED_FILES= Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QPainterPath) Q_DECLARE_METATYPE(QPointF) Q_DECLARE_METATYPE(QRectF) #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) #include #define Q_CHECK_PAINTEVENTS \ if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \ QSKIP("The Graphics View doesn't get the paint events", SkipSingle); #else #define Q_CHECK_PAINTEVENTS #endif #if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) // On mac (cocoa) we always get full update. // So check that the expected region is contained inside the actual #define COMPARE_REGIONS(ACTUAL, EXPECTED) QVERIFY((EXPECTED).subtracted(ACTUAL).isEmpty()) #else #define COMPARE_REGIONS QTRY_COMPARE #endif #include "../platformquirks.h" static QGraphicsRectItem staticItem; //QTBUG-7629, we should not crash at exit. static void sendMousePress(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton) { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(point); event.setButton(button); event.setButtons(button); QApplication::sendEvent(scene, &event); } static void sendMouseMove(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons buttons = 0) { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove); event.setScenePos(point); event.setButton(button); event.setButtons(button); QApplication::sendEvent(scene, &event); } static void sendMouseRelease(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton) { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(point); event.setButton(button); QApplication::sendEvent(scene, &event); } static void sendMouseClick(QGraphicsScene *scene, const QPointF &point, Qt::MouseButton button = Qt::LeftButton) { sendMousePress(scene, point, button); sendMouseRelease(scene, point, button); } static void sendKeyPress(QGraphicsScene *scene, Qt::Key key) { QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier); QApplication::sendEvent(scene, &keyEvent); } static void sendKeyRelease(QGraphicsScene *scene, Qt::Key key) { QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier); QApplication::sendEvent(scene, &keyEvent); } static void sendKeyClick(QGraphicsScene *scene, Qt::Key key) { sendKeyPress(scene, key); sendKeyRelease(scene, key); } class EventSpy : public QGraphicsWidget { Q_OBJECT public: EventSpy(QObject *watched, QEvent::Type type) : _count(0), spied(type) { watched->installEventFilter(this); } EventSpy(QGraphicsScene *scene, QGraphicsItem *watched, QEvent::Type type) : _count(0), spied(type) { scene->addItem(this); watched->installSceneEventFilter(this); } int count() const { return _count; } protected: bool eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched); if (event->type() == spied) ++_count; return false; } bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) { Q_UNUSED(watched); if (event->type() == spied) ++_count; return false; } int _count; QEvent::Type spied; }; class EventSpy2 : public QGraphicsWidget { Q_OBJECT public: EventSpy2(QObject *watched) { watched->installEventFilter(this); } EventSpy2(QGraphicsScene *scene, QGraphicsItem *watched) { scene->addItem(this); watched->installSceneEventFilter(this); } QMap counts; protected: bool eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched); ++counts[event->type()]; return false; } bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) { Q_UNUSED(watched); ++counts[event->type()]; return false; } }; class EventTester : public QGraphicsItem { public: EventTester(QGraphicsItem *parent = 0) : QGraphicsItem(parent), repaints(0) { br = QRectF(-10, -10, 20, 20); } void setGeometry(const QRectF &rect) { prepareGeometryChange(); br = rect; update(); } QRectF boundingRect() const { return br; } void paint(QPainter *painter, const QStyleOptionGraphicsItem *o, QWidget *) { hints = painter->renderHints(); painter->setBrush(brush); painter->drawRect(boundingRect()); lastExposedRect = o->exposedRect; ++repaints; } bool sceneEvent(QEvent *event) { events << event->type(); return QGraphicsItem::sceneEvent(event); } void reset() { events.clear(); hints = QPainter::RenderHints(0); repaints = 0; lastExposedRect = QRectF(); } QList events; QPainter::RenderHints hints; int repaints; QRectF br; QRectF lastExposedRect; QBrush brush; }; class MyGraphicsView : public QGraphicsView { public: int repaints; QRegion paintedRegion; MyGraphicsView(QGraphicsScene *scene, QWidget *parent=0) : QGraphicsView(scene,parent), repaints(0) {} void paintEvent(QPaintEvent *e) { paintedRegion += e->region(); ++repaints; QGraphicsView::paintEvent(e); } void reset() { repaints = 0; paintedRegion = QRegion(); } }; class tst_QGraphicsItem : public QObject { Q_OBJECT public slots: void init(); private slots: void construction(); void constructionWithParent(); void destruction(); void deleteChildItem(); void scene(); void parentItem(); void setParentItem(); void children(); void flags(); void inputMethodHints(); void toolTip(); void visible(); void explicitlyVisible(); void enabled(); void explicitlyEnabled(); void selected(); void selected2(); void selected_group(); void selected_textItem(); void selected_multi(); void acceptedMouseButtons(); void acceptsHoverEvents(); void childAcceptsHoverEvents(); void hasFocus(); void pos(); void scenePos(); void matrix(); void sceneMatrix(); void setMatrix(); void zValue(); void shape(); void contains(); void collidesWith_item(); void collidesWith_path_data(); void collidesWith_path(); void collidesWithItemWithClip(); void isObscuredBy(); void isObscured(); void mapFromToParent(); void mapFromToScene(); void mapFromToItem(); void mapRectFromToParent_data(); void mapRectFromToParent(); void isAncestorOf(); void commonAncestorItem(); void data(); void type(); void graphicsitem_cast(); void hoverEventsGenerateRepaints(); void boundingRects_data(); void boundingRects(); void boundingRects2(); void sceneBoundingRect(); void childrenBoundingRect(); void childrenBoundingRectTransformed(); void childrenBoundingRect2(); void childrenBoundingRect3(); void childrenBoundingRect4(); void childrenBoundingRect5(); void group(); void setGroup(); void setGroup2(); void nestedGroups(); void warpChildrenIntoGroup(); void removeFromGroup(); void handlesChildEvents(); void handlesChildEvents2(); void handlesChildEvents3(); void filtersChildEvents(); void filtersChildEvents2(); void ensureVisible(); void cursor(); //void textControlGetterSetter(); void defaultItemTest_QGraphicsLineItem(); void defaultItemTest_QGraphicsPixmapItem(); void defaultItemTest_QGraphicsTextItem(); void defaultItemTest_QGraphicsEllipseItem(); void itemChange(); void sceneEventFilter(); void prepareGeometryChange(); void paint(); void deleteItemInEventHandlers(); void itemClipsToShape(); void itemClipsChildrenToShape(); void itemClipsChildrenToShape2(); void itemClipsChildrenToShape3(); void itemClipsChildrenToShape4(); void itemClipsChildrenToShape5(); void itemClipsTextChildToShape(); void itemClippingDiscovery(); void ancestorFlags(); void untransformable(); void contextMenuEventPropagation(); void itemIsMovable(); void boundingRegion_data(); void boundingRegion(); void itemTransform_parentChild(); void itemTransform_siblings(); void itemTransform_unrelated(); void opacity_data(); void opacity(); void opacity2(); void opacityZeroUpdates(); void itemStacksBehindParent(); void nestedClipping(); void nestedClippingTransforms(); void sceneTransformCache(); void tabChangesFocus(); void tabChangesFocus_data(); void cacheMode(); void cacheMode2(); void updateCachedItemAfterMove(); void deviceTransform_data(); void deviceTransform(); void update(); void setTransformProperties_data(); void setTransformProperties(); void itemUsesExtendedStyleOption(); void itemSendsGeometryChanges(); void moveItem(); void moveLineItem(); void sorting_data(); void sorting(); void itemHasNoContents(); void hitTestUntransformableItem(); void hitTestGraphicsEffectItem(); void focusProxy(); void subFocus(); void focusProxyDeletion(); void negativeZStacksBehindParent(); void setGraphicsEffect(); void panel(); void addPanelToActiveScene(); void panelWithFocusItem(); void activate(); void setActivePanelOnInactiveScene(); void activationOnShowHide(); void moveWhileDeleting(); void ensureDirtySceneTransform(); void focusScope(); void focusScope2(); void stackBefore(); void sceneModality(); void panelModality(); void mixedModality(); void modality_hover(); void modality_mouseGrabber(); void modality_clickFocus(); void modality_keyEvents(); void itemIsInFront(); void scenePosChange(); void updateMicroFocus(); void textItem_shortcuts(); void scroll(); void stopClickFocusPropagation(); void deviceCoordinateCache_simpleRotations(); // task specific tests below me void task141694_textItemEnsureVisible(); void task128696_textItemEnsureMovable(); void ensureUpdateOnTextItem(); void task177918_lineItemUndetected(); void task240400_clickOnTextItem_data(); void task240400_clickOnTextItem(); void task243707_addChildBeforeParent(); void task197802_childrenVisibility(); void QTBUG_4233_updateCachedWithSceneRect(); void QTBUG_5418_textItemSetDefaultColor(); void QTBUG_6738_missingUpdateWithSetParent(); void QTBUG_7714_fullUpdateDiscardingOpacityUpdate2(); void QT_2653_fullUpdateDiscardingOpacityUpdate(); void QT_2649_focusScope(); void sortItemsWhileAdding(); void doNotMarkFullUpdateIfNotInScene(); void itemDiesDuringDraggingOperation(); void QTBUG_12112_focusItem(); void QTBUG_13473_sceneposchange(); private: QList paintedItems; }; void tst_QGraphicsItem::init() { #ifdef Q_OS_WINCE //disable magic for WindowsCE qApp->setAutoMaximizeThreshold(-1); #endif } void tst_QGraphicsItem::construction() { for (int i = 0; i < 7; ++i) { QGraphicsItem *item; switch (i) { case 0: item = new QGraphicsEllipseItem; QCOMPARE(int(item->type()), int(QGraphicsEllipseItem::Type)); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsEllipseItem *)item); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsRectItem *)0); QCOMPARE(item->flags(), 0); break; case 1: item = new QGraphicsLineItem; QCOMPARE(int(item->type()), int(QGraphicsLineItem::Type)); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsLineItem *)item); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsRectItem *)0); QCOMPARE(item->flags(), 0); break; case 2: item = new QGraphicsPathItem; QCOMPARE(int(item->type()), int(QGraphicsPathItem::Type)); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsPathItem *)item); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsRectItem *)0); QCOMPARE(item->flags(), 0); break; case 3: item = new QGraphicsPixmapItem; QCOMPARE(int(item->type()), int(QGraphicsPixmapItem::Type)); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsPixmapItem *)item); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsRectItem *)0); QCOMPARE(item->flags(), 0); break; case 4: item = new QGraphicsPolygonItem; QCOMPARE(int(item->type()), int(QGraphicsPolygonItem::Type)); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsPolygonItem *)item); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsRectItem *)0); QCOMPARE(item->flags(), 0); break; case 5: item = new QGraphicsRectItem; QCOMPARE(int(item->type()), int(QGraphicsRectItem::Type)); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsRectItem *)item); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsLineItem *)0); QCOMPARE(item->flags(), 0); break; case 6: item = new QGraphicsTextItem; QCOMPARE(int(item->type()), int(QGraphicsTextItem::Type)); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsTextItem *)item); QCOMPARE(qgraphicsitem_cast(item), (QGraphicsRectItem *)0); // This is the only item that uses an extended style option. QCOMPARE(item->flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption)); break; default: qFatal("You broke the logic, please fix!"); break; } QCOMPARE(item->scene(), (QGraphicsScene *)0); QCOMPARE(item->parentItem(), (QGraphicsItem *)0); QVERIFY(item->children().isEmpty()); QVERIFY(item->isVisible()); QVERIFY(item->isEnabled()); QVERIFY(!item->isSelected()); QCOMPARE(item->acceptedMouseButtons(), Qt::MouseButtons(0x1f)); if (item->type() == QGraphicsTextItem::Type) QVERIFY(item->acceptsHoverEvents()); else QVERIFY(!item->acceptsHoverEvents()); QVERIFY(!item->hasFocus()); QCOMPARE(item->pos(), QPointF()); QCOMPARE(item->matrix(), QMatrix()); QCOMPARE(item->sceneMatrix(), QMatrix()); QCOMPARE(item->zValue(), qreal(0)); QCOMPARE(item->sceneBoundingRect(), QRectF()); QCOMPARE(item->shape(), QPainterPath()); QVERIFY(!item->contains(QPointF(0, 0))); QVERIFY(!item->collidesWithItem(0)); QVERIFY(item->collidesWithItem(item)); QVERIFY(!item->collidesWithPath(QPainterPath())); QVERIFY(!item->isAncestorOf(0)); QVERIFY(!item->isAncestorOf(item)); QCOMPARE(item->data(0), QVariant()); delete item; } } class BoundingRectItem : public QGraphicsRectItem { public: BoundingRectItem(QGraphicsItem *parent = 0) : QGraphicsRectItem(0, 0, parent ? 200 : 100, parent ? 200 : 100, parent) {} QRectF boundingRect() const { QRectF tmp = QGraphicsRectItem::boundingRect(); foreach (QGraphicsItem *child, children()) tmp |= child->boundingRect(); // <- might be pure virtual return tmp; } }; void tst_QGraphicsItem::constructionWithParent() { // This test causes a crash if item1 calls item2's pure virtuals before the // object has been constructed. QGraphicsItem *item0 = new BoundingRectItem; QGraphicsItem *item1 = new BoundingRectItem; QGraphicsScene scene; scene.addItem(item0); scene.addItem(item1); QGraphicsItem *item2 = new BoundingRectItem(item1); QCOMPARE(item1->children(), QList() << item2); QCOMPARE(item1->boundingRect(), QRectF(0, 0, 200, 200)); item2->setParentItem(item0); QCOMPARE(item0->children(), QList() << item2); QCOMPARE(item0->boundingRect(), QRectF(0, 0, 200, 200)); } static int itemDeleted = 0; class Item : public QGraphicsRectItem { public: ~Item() { ++itemDeleted; } }; void tst_QGraphicsItem::destruction() { QCOMPARE(itemDeleted, 0); { QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); QCOMPARE(child->parentItem(), parent); delete parent; QCOMPARE(itemDeleted, 1); } { QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); QCOMPARE(parent->children().size(), 1); delete child; QCOMPARE(parent->children().size(), 0); delete parent; QCOMPARE(itemDeleted, 2); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; QCOMPARE(child->parentItem(), (QGraphicsItem *)0); child->setParentItem(parent); QCOMPARE(child->parentItem(), parent); scene.addItem(parent); QCOMPARE(child->parentItem(), parent); delete parent; QCOMPARE(itemDeleted, 3); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); scene.addItem(parent); QCOMPARE(child->scene(), &scene); QCOMPARE(parent->children().size(), 1); delete child; QCOMPARE(parent->children().size(), 0); delete parent; QCOMPARE(itemDeleted, 4); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); scene.addItem(parent); QCOMPARE(child->scene(), &scene); scene.removeItem(parent); QCOMPARE(child->scene(), (QGraphicsScene *)0); delete parent; QCOMPARE(itemDeleted, 5); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); QCOMPARE(child->scene(), (QGraphicsScene *)0); QCOMPARE(parent->scene(), (QGraphicsScene *)0); scene.addItem(parent); QCOMPARE(child->scene(), &scene); scene.removeItem(child); QCOMPARE(child->scene(), (QGraphicsScene *)0); QCOMPARE(parent->scene(), &scene); QCOMPARE(child->parentItem(), (QGraphicsItem *)0); QVERIFY(parent->children().isEmpty()); delete parent; QCOMPARE(itemDeleted, 5); delete child; QCOMPARE(itemDeleted, 6); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); scene.addItem(parent); scene.removeItem(child); scene.removeItem(parent); delete child; delete parent; QCOMPARE(itemDeleted, 7); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); scene.addItem(parent); QGraphicsScene scene2; scene2.addItem(parent); delete parent; QCOMPARE(itemDeleted, 8); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); scene.addItem(parent); QCOMPARE(child->scene(), &scene); QGraphicsScene scene2; scene2.addItem(parent); QCOMPARE(child->scene(), &scene2); scene.addItem(parent); QCOMPARE(child->scene(), &scene); scene2.addItem(parent); QCOMPARE(child->scene(), &scene2); delete parent; QCOMPARE(itemDeleted, 9); } { QGraphicsScene scene; QGraphicsItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); scene.addItem(parent); QCOMPARE(child->scene(), &scene); QGraphicsScene scene2; scene2.addItem(child); QCOMPARE(child->scene(), &scene2); delete parent; QCOMPARE(itemDeleted, 9); delete child; QCOMPARE(itemDeleted, 10); } { QGraphicsScene scene; QGraphicsItem *root = new QGraphicsRectItem; QGraphicsItem *parent = root; QGraphicsItem *middleItem = 0; for (int i = 0; i < 99; ++i) { Item *child = new Item; child->setParentItem(parent); parent = child; if (i == 50) middleItem = parent; } scene.addItem(root); QCOMPARE(scene.items().size(), 100); QGraphicsScene scene2; scene2.addItem(middleItem); delete middleItem; QCOMPARE(itemDeleted, 59); } QCOMPARE(itemDeleted, 109); { QGraphicsScene *scene = new QGraphicsScene; QGraphicsRectItem *parent = new QGraphicsRectItem; Item *child = new Item; child->setParentItem(parent); parent->setVisible(false); scene->addItem(parent); QCOMPARE(child->parentItem(), static_cast(parent)); delete scene; QCOMPARE(itemDeleted, 110); } } void tst_QGraphicsItem::deleteChildItem() { QGraphicsScene scene; QGraphicsItem *rect = scene.addRect(QRectF()); QGraphicsItem *child1 = new QGraphicsRectItem(rect); QGraphicsItem *child2 = new QGraphicsRectItem(rect); QGraphicsItem *child3 = new QGraphicsRectItem(rect); delete child1; child2->setParentItem(0); delete child2; } void tst_QGraphicsItem::scene() { QGraphicsRectItem *item = new QGraphicsRectItem; QCOMPARE(item->scene(), (QGraphicsScene *)0); QGraphicsScene scene; scene.addItem(item); QCOMPARE(item->scene(), (QGraphicsScene *)&scene); QGraphicsScene scene2; scene2.addItem(item); QCOMPARE(item->scene(), (QGraphicsScene *)&scene2); scene2.removeItem(item); QCOMPARE(item->scene(), (QGraphicsScene *)0); delete item; } void tst_QGraphicsItem::parentItem() { QGraphicsRectItem item; QCOMPARE(item.parentItem(), (QGraphicsItem *)0); QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item); QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item); item2->setParentItem(&item); QCOMPARE(item2->parentItem(), (QGraphicsItem *)&item); item2->setParentItem(0); QCOMPARE(item2->parentItem(), (QGraphicsItem *)0); delete item2; } void tst_QGraphicsItem::setParentItem() { QGraphicsScene scene; QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10)); QCOMPARE(item->scene(), &scene); QGraphicsRectItem *child = new QGraphicsRectItem; QCOMPARE(child->scene(), (QGraphicsScene *)0); // This implicitly adds the item to the parent's scene child->setParentItem(item); QCOMPARE(child->scene(), &scene); // This just makes it a toplevel child->setParentItem(0); QCOMPARE(child->scene(), &scene); // Add the child back to the parent, then remove the parent from the scene child->setParentItem(item); scene.removeItem(item); QCOMPARE(child->scene(), (QGraphicsScene *)0); } void tst_QGraphicsItem::children() { QGraphicsRectItem item; QVERIFY(item.children().isEmpty()); QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(), &item); QCOMPARE(item.children().size(), 1); QCOMPARE(item.children().first(), (QGraphicsItem *)item2); QVERIFY(item2->children().isEmpty()); delete item2; QVERIFY(item.children().isEmpty()); } void tst_QGraphicsItem::flags() { QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20)); QCOMPARE(item->flags(), 0); QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); scene.addItem(item); { // Focus item->setFlag(QGraphicsItem::ItemIsFocusable, false); QVERIFY(!item->hasFocus()); item->setFocus(); QVERIFY(!item->hasFocus()); item->setFlag(QGraphicsItem::ItemIsFocusable, true); QVERIFY(!item->hasFocus()); item->setFocus(); QVERIFY(item->hasFocus()); QVERIFY(scene.hasFocus()); item->setFlag(QGraphicsItem::ItemIsFocusable, false); QVERIFY(!item->hasFocus()); QVERIFY(scene.hasFocus()); } { // Selectable item->setFlag(QGraphicsItem::ItemIsSelectable, false); QVERIFY(!item->isSelected()); item->setSelected(true); QVERIFY(!item->isSelected()); item->setFlag(QGraphicsItem::ItemIsSelectable, true); QVERIFY(!item->isSelected()); item->setSelected(true); QVERIFY(item->isSelected()); item->setFlag(QGraphicsItem::ItemIsSelectable, false); QVERIFY(!item->isSelected()); } { // Movable item->setFlag(QGraphicsItem::ItemIsMovable, false); QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(0, 0)); event.setButton(Qt::LeftButton); event.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); // mouse grabber is reset QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove); event2.setScenePos(QPointF(10, 10)); event2.setButton(Qt::LeftButton); event2.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event2); QCOMPARE(item->pos(), QPointF()); QGraphicsSceneMouseEvent event3(QEvent::GraphicsSceneMouseRelease); event3.setScenePos(QPointF(10, 10)); event3.setButtons(0); QApplication::sendEvent(&scene, &event3); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); item->setFlag(QGraphicsItem::ItemIsMovable, true); QGraphicsSceneMouseEvent event4(QEvent::GraphicsSceneMousePress); event4.setScenePos(QPointF(0, 0)); event4.setButton(Qt::LeftButton); event4.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event4); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item); QGraphicsSceneMouseEvent event5(QEvent::GraphicsSceneMouseMove); event5.setScenePos(QPointF(10, 10)); event5.setButton(Qt::LeftButton); event5.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event5); QCOMPARE(item->pos(), QPointF(10, 10)); } { QGraphicsItem* clippingParent = new QGraphicsRectItem; clippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); QGraphicsItem* nonClippingParent = new QGraphicsRectItem; nonClippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false); QGraphicsItem* child = new QGraphicsRectItem(nonClippingParent); QVERIFY(!child->isClipped()); child->setParentItem(clippingParent); QVERIFY(child->isClipped()); child->setParentItem(nonClippingParent); QVERIFY(!child->isClipped()); } } class ImhTester : public QGraphicsItem { QRectF boundingRect() const { return QRectF(); } void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {} }; void tst_QGraphicsItem::inputMethodHints() { ImhTester *item = new ImhTester; item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true); item->setFlag(QGraphicsItem::ItemIsFocusable, true); QCOMPARE(item->inputMethodHints(), Qt::ImhNone); ImhTester *item2 = new ImhTester; item2->setFlag(QGraphicsItem::ItemAcceptsInputMethod, true); item2->setFlag(QGraphicsItem::ItemIsFocusable, true); Qt::InputMethodHints imHints = item2->inputMethodHints(); imHints |= Qt::ImhHiddenText; item2->setInputMethodHints(imHints); QGraphicsScene scene; scene.addItem(item); scene.addItem(item2); QGraphicsView view(&scene); QApplication::setActiveWindow(&view); view.show(); QTest::qWaitForWindowShown(&view); item->setFocus(); QTRY_VERIFY(item->hasFocus()); QCOMPARE(view.inputMethodHints(), item->inputMethodHints()); item2->setFocus(); QTRY_VERIFY(item2->hasFocus()); QCOMPARE(view.inputMethodHints(), item2->inputMethodHints()); item->setFlag(QGraphicsItem::ItemAcceptsInputMethod, false); item->setFocus(); QTRY_VERIFY(item->hasFocus()); //Focus has changed but the new item doesn't accept input method, no hints. QCOMPARE(view.inputMethodHints(), 0); item2->setFocus(); QTRY_VERIFY(item2->hasFocus()); QCOMPARE(view.inputMethodHints(), item2->inputMethodHints()); imHints = item2->inputMethodHints(); imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); item2->setInputMethodHints(imHints); QCOMPARE(view.inputMethodHints(), item2->inputMethodHints()); QGraphicsProxyWidget *widget = new QGraphicsProxyWidget; QLineEdit *edit = new QLineEdit; edit->setEchoMode(QLineEdit::Password); scene.addItem(widget); widget->setFocus(); QTRY_VERIFY(widget->hasFocus()); //No widget on the proxy, so no hints QCOMPARE(view.inputMethodHints(), 0); widget->setWidget(edit); //View should match with the line edit QCOMPARE(view.inputMethodHints(), edit->inputMethodHints()); } void tst_QGraphicsItem::toolTip() { QString toolTip = "Qt rocks!"; QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100)); item->setPen(QPen(Qt::red, 1)); item->setBrush(QBrush(Qt::blue)); QVERIFY(item->toolTip().isEmpty()); item->setToolTip(toolTip); QCOMPARE(item->toolTip(), toolTip); QGraphicsScene scene; scene.addItem(item); QGraphicsView view(&scene); view.setFixedSize(200, 200); view.show(); QTest::qWait(250); { QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(), view.viewport()->mapToGlobal(view.viewport()->rect().topLeft())); QApplication::sendEvent(view.viewport(), &helpEvent); QTest::qWait(250); bool foundView = false; bool foundTipLabel = false; foreach (QWidget *widget, QApplication::topLevelWidgets()) { if (widget == &view) foundView = true; if (widget->inherits("QTipLabel")) foundTipLabel = true; } QVERIFY(foundView); QVERIFY(!foundTipLabel); } { QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().center(), view.viewport()->mapToGlobal(view.viewport()->rect().center())); QApplication::sendEvent(view.viewport(), &helpEvent); QTest::qWait(250); bool foundView = false; bool foundTipLabel = false; foreach (QWidget *widget, QApplication::topLevelWidgets()) { if (widget == &view) foundView = true; if (widget->inherits("QTipLabel")) foundTipLabel = true; } QVERIFY(foundView); QVERIFY(foundTipLabel); } { QHelpEvent helpEvent(QEvent::ToolTip, view.viewport()->rect().topLeft(), view.viewport()->mapToGlobal(view.viewport()->rect().topLeft())); QApplication::sendEvent(view.viewport(), &helpEvent); QTest::qWait(1000); bool foundView = false; bool foundTipLabel = false; foreach (QWidget *widget, QApplication::topLevelWidgets()) { if (widget == &view) foundView = true; if (widget->inherits("QTipLabel") && widget->isVisible()) foundTipLabel = true; } QVERIFY(foundView); QVERIFY(!foundTipLabel); } } void tst_QGraphicsItem::visible() { QGraphicsItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20)); item->setFlag(QGraphicsItem::ItemIsMovable); QVERIFY(item->isVisible()); item->setVisible(false); QVERIFY(!item->isVisible()); item->setVisible(true); QVERIFY(item->isVisible()); QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); scene.addItem(item); QVERIFY(item->isVisible()); QCOMPARE(scene.itemAt(0, 0), item); item->setVisible(false); QCOMPARE(scene.itemAt(0, 0), (QGraphicsItem *)0); item->setVisible(true); QCOMPARE(scene.itemAt(0, 0), item); QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setButton(Qt::LeftButton); event.setScenePos(QPointF(0, 0)); QApplication::sendEvent(&scene, &event); QCOMPARE(scene.mouseGrabberItem(), item); item->setVisible(false); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); item->setVisible(true); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); item->setFlag(QGraphicsItem::ItemIsFocusable); item->setFocus(); QVERIFY(item->hasFocus()); item->setVisible(false); QVERIFY(!item->hasFocus()); item->setVisible(true); QVERIFY(!item->hasFocus()); } void tst_QGraphicsItem::explicitlyVisible() { QGraphicsScene scene; QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50)); child->setParentItem(parent); QVERIFY(parent->isVisible()); QVERIFY(child->isVisible()); parent->hide(); QVERIFY(!parent->isVisible()); QVERIFY(!child->isVisible()); parent->show(); child->hide(); QVERIFY(parent->isVisible()); QVERIFY(!child->isVisible()); parent->hide(); QVERIFY(!parent->isVisible()); QVERIFY(!child->isVisible()); parent->show(); QVERIFY(parent->isVisible()); QVERIFY(!child->isVisible()); // <- explicitly hidden child->show(); QVERIFY(child->isVisible()); parent->hide(); QVERIFY(!parent->isVisible()); QVERIFY(!child->isVisible()); // <- explicit show doesn't work parent->show(); QVERIFY(parent->isVisible()); QVERIFY(child->isVisible()); // <- no longer explicitly hidden // ------------------- Reparenting ------------------------------ QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200); QVERIFY(parent2->isVisible()); // Reparent implicitly hidden item to a visible parent. parent->hide(); QVERIFY(!parent->isVisible()); QVERIFY(!child->isVisible()); child->setParentItem(parent2); QVERIFY(parent2->isVisible()); QVERIFY(child->isVisible()); // Reparent implicitly hidden item to a hidden parent. child->setParentItem(parent); parent2->hide(); child->setParentItem(parent2); QVERIFY(!parent2->isVisible()); QVERIFY(!child->isVisible()); // Reparent explicitly hidden item to a visible parent. child->hide(); parent->show(); child->setParentItem(parent); QVERIFY(parent->isVisible()); QVERIFY(!child->isVisible()); // Reparent explicitly hidden item to a hidden parent. child->setParentItem(parent2); QVERIFY(!parent2->isVisible()); QVERIFY(!child->isVisible()); // Reparent explicitly hidden item to a visible parent. parent->show(); child->setParentItem(parent); QVERIFY(parent->isVisible()); QVERIFY(!child->isVisible()); // Reparent visible item to a hidden parent. child->show(); parent2->hide(); child->setParentItem(parent2); QVERIFY(!parent2->isVisible()); QVERIFY(!child->isVisible()); parent2->show(); QVERIFY(parent2->isVisible()); QVERIFY(child->isVisible()); // Reparent implicitly hidden child to root. parent2->hide(); QVERIFY(!child->isVisible()); child->setParentItem(0); QVERIFY(child->isVisible()); // Reparent an explicitly hidden child to root. child->hide(); child->setParentItem(parent2); parent2->show(); QVERIFY(!child->isVisible()); child->setParentItem(0); QVERIFY(!child->isVisible()); } void tst_QGraphicsItem::enabled() { QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(-10, -10, 20, 20)); item->setFlag(QGraphicsItem::ItemIsMovable); QVERIFY(item->isEnabled()); item->setEnabled(false); QVERIFY(!item->isEnabled()); item->setEnabled(true); QVERIFY(item->isEnabled()); item->setEnabled(false); item->setFlag(QGraphicsItem::ItemIsFocusable); QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); scene.addItem(item); item->setFocus(); QVERIFY(!item->hasFocus()); item->setEnabled(true); item->setFocus(); QVERIFY(item->hasFocus()); item->setEnabled(false); QVERIFY(!item->hasFocus()); QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setButton(Qt::LeftButton); event.setScenePos(QPointF(0, 0)); QApplication::sendEvent(&scene, &event); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); item->setEnabled(true); QApplication::sendEvent(&scene, &event); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item); item->setEnabled(false); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); } void tst_QGraphicsItem::explicitlyEnabled() { QGraphicsScene scene; QGraphicsItem *parent = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsItem *child = scene.addRect(QRectF(25, 25, 50, 50)); child->setParentItem(parent); QVERIFY(parent->isEnabled()); QVERIFY(child->isEnabled()); parent->setEnabled(false); QVERIFY(!parent->isEnabled()); QVERIFY(!child->isEnabled()); parent->setEnabled(true); child->setEnabled(false); QVERIFY(parent->isEnabled()); QVERIFY(!child->isEnabled()); parent->setEnabled(false); QVERIFY(!parent->isEnabled()); QVERIFY(!child->isEnabled()); parent->setEnabled(true); QVERIFY(parent->isEnabled()); QVERIFY(!child->isEnabled()); // <- explicitly disabled child->setEnabled(true); QVERIFY(child->isEnabled()); parent->setEnabled(false); QVERIFY(!parent->isEnabled()); QVERIFY(!child->isEnabled()); // <- explicit enabled doesn't work parent->setEnabled(true); QVERIFY(parent->isEnabled()); QVERIFY(child->isEnabled()); // <- no longer explicitly disabled // ------------------- Reparenting ------------------------------ QGraphicsItem *parent2 = scene.addRect(-50, -50, 200, 200); QVERIFY(parent2->isEnabled()); // Reparent implicitly hidden item to a enabled parent. parent->setEnabled(false); QVERIFY(!parent->isEnabled()); QVERIFY(!child->isEnabled()); child->setParentItem(parent2); QVERIFY(parent2->isEnabled()); QVERIFY(child->isEnabled()); // Reparent implicitly hidden item to a hidden parent. child->setParentItem(parent); parent2->setEnabled(false); child->setParentItem(parent2); QVERIFY(!parent2->isEnabled()); QVERIFY(!child->isEnabled()); // Reparent explicitly hidden item to a enabled parent. child->setEnabled(false); parent->setEnabled(true); child->setParentItem(parent); QVERIFY(parent->isEnabled()); QVERIFY(!child->isEnabled()); // Reparent explicitly hidden item to a hidden parent. child->setParentItem(parent2); QVERIFY(!parent2->isEnabled()); QVERIFY(!child->isEnabled()); // Reparent explicitly hidden item to a enabled parent. parent->setEnabled(true); child->setParentItem(parent); QVERIFY(parent->isEnabled()); QVERIFY(!child->isEnabled()); // Reparent enabled item to a hidden parent. child->setEnabled(true); parent2->setEnabled(false); child->setParentItem(parent2); QVERIFY(!parent2->isEnabled()); QVERIFY(!child->isEnabled()); parent2->setEnabled(true); QVERIFY(parent2->isEnabled()); QVERIFY(child->isEnabled()); // Reparent implicitly hidden child to root. parent2->setEnabled(false); QVERIFY(!child->isEnabled()); child->setParentItem(0); QVERIFY(child->isEnabled()); // Reparent an explicitly hidden child to root. child->setEnabled(false); child->setParentItem(parent2); parent2->setEnabled(true); QVERIFY(!child->isEnabled()); child->setParentItem(0); QVERIFY(!child->isEnabled()); } class SelectChangeItem : public QGraphicsRectItem { public: SelectChangeItem() : QGraphicsRectItem(-50, -50, 100, 100) { setBrush(Qt::blue); } QList values; protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value) { if (change == ItemSelectedChange) values << value.toBool(); return QGraphicsRectItem::itemChange(change, value); } }; void tst_QGraphicsItem::selected() { SelectChangeItem *item = new SelectChangeItem; item->setFlag(QGraphicsItem::ItemIsSelectable); QVERIFY(!item->isSelected()); QVERIFY(item->values.isEmpty()); item->setSelected(true); QCOMPARE(item->values.size(), 1); QCOMPARE(item->values.last(), true); QVERIFY(item->isSelected()); item->setSelected(false); QCOMPARE(item->values.size(), 2); QCOMPARE(item->values.last(), false); QVERIFY(!item->isSelected()); item->setSelected(true); QCOMPARE(item->values.size(), 3); item->setEnabled(false); QCOMPARE(item->values.size(), 4); QCOMPARE(item->values.last(), false); QVERIFY(!item->isSelected()); item->setEnabled(true); QCOMPARE(item->values.size(), 4); item->setSelected(true); QCOMPARE(item->values.size(), 5); QCOMPARE(item->values.last(), true); QVERIFY(item->isSelected()); item->setVisible(false); QCOMPARE(item->values.size(), 6); QCOMPARE(item->values.last(), false); QVERIFY(!item->isSelected()); item->setVisible(true); QCOMPARE(item->values.size(), 6); item->setSelected(true); QCOMPARE(item->values.size(), 7); QCOMPARE(item->values.last(), true); QVERIFY(item->isSelected()); QGraphicsScene scene(-100, -100, 200, 200); scene.addItem(item); QCOMPARE(scene.selectedItems(), QList() << item); item->setSelected(false); QVERIFY(scene.selectedItems().isEmpty()); item->setSelected(true); QCOMPARE(scene.selectedItems(), QList() << item); item->setSelected(false); QVERIFY(scene.selectedItems().isEmpty()); // Interactive selection QGraphicsView view(&scene); view.setFixedSize(250, 250); view.show(); QTest::qWaitForWindowShown(&view); qApp->processEvents(); qApp->processEvents(); scene.clearSelection(); QCOMPARE(item->values.size(), 10); QCOMPARE(item->values.last(), false); QVERIFY(!item->isSelected()); // Click inside and check that it's selected QTest::mouseMove(view.viewport()); QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos())); QCOMPARE(item->values.size(), 11); QCOMPARE(item->values.last(), true); QVERIFY(item->isSelected()); // Click outside and check that it's not selected QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos() + QPointF(item->boundingRect().width(), item->boundingRect().height()))); QCOMPARE(item->values.size(), 12); QCOMPARE(item->values.last(), false); QVERIFY(!item->isSelected()); SelectChangeItem *item2 = new SelectChangeItem; item2->setFlag(QGraphicsItem::ItemIsSelectable); item2->setPos(100, 0); scene.addItem(item2); // Click inside and check that it's selected QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos())); QCOMPARE(item->values.size(), 13); QCOMPARE(item->values.last(), true); QVERIFY(item->isSelected()); // Click inside item2 and check that it's selected, and item is not QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos())); QCOMPARE(item->values.size(), 14); QCOMPARE(item->values.last(), false); QVERIFY(!item->isSelected()); QCOMPARE(item2->values.size(), 1); QCOMPARE(item2->values.last(), true); QVERIFY(item2->isSelected()); } void tst_QGraphicsItem::selected2() { // Selecting an item, then moving another previously caused a crash. QGraphicsScene scene; QGraphicsItem *line1 = scene.addRect(QRectF(0, 0, 100, 100)); line1->setPos(-105, 0); line1->setFlag(QGraphicsItem::ItemIsSelectable); QGraphicsItem *line2 = scene.addRect(QRectF(0, 0, 100, 100)); line2->setFlag(QGraphicsItem::ItemIsMovable); line1->setSelected(true); { QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress); mousePress.setScenePos(QPointF(50, 50)); mousePress.setButton(Qt::LeftButton); QApplication::sendEvent(&scene, &mousePress); QVERIFY(mousePress.isAccepted()); } { QGraphicsSceneMouseEvent mouseMove(QEvent::GraphicsSceneMouseMove); mouseMove.setScenePos(QPointF(60, 60)); mouseMove.setButton(Qt::LeftButton); mouseMove.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &mouseMove); QVERIFY(mouseMove.isAccepted()); } } void tst_QGraphicsItem::selected_group() { QGraphicsScene scene; QGraphicsItem *item1 = scene.addRect(QRectF()); QGraphicsItem *item2 = scene.addRect(QRectF()); item1->setFlag(QGraphicsItem::ItemIsSelectable); item2->setFlag(QGraphicsItem::ItemIsSelectable); scene.addRect(QRectF())->setParentItem(item1); QGraphicsItem *leaf = scene.addRect(QRectF()); leaf->setFlag(QGraphicsItem::ItemIsSelectable); leaf->setParentItem(item2); QGraphicsItemGroup *group = scene.createItemGroup(QList() << item1 << item2); QCOMPARE(group->scene(), &scene); group->setFlag(QGraphicsItem::ItemIsSelectable); foreach (QGraphicsItem *item, scene.items()) { if (item == group) QVERIFY(!item->group()); else QCOMPARE(item->group(), group); } QVERIFY(group->handlesChildEvents()); QVERIFY(!group->isSelected()); group->setSelected(false); QVERIFY(!group->isSelected()); group->setSelected(true); QVERIFY(group->isSelected()); foreach (QGraphicsItem *item, scene.items()) QVERIFY(item->isSelected()); group->setSelected(false); QVERIFY(!group->isSelected()); foreach (QGraphicsItem *item, scene.items()) QVERIFY(!item->isSelected()); leaf->setSelected(true); foreach (QGraphicsItem *item, scene.items()) QVERIFY(item->isSelected()); leaf->setSelected(false); foreach (QGraphicsItem *item, scene.items()) QVERIFY(!item->isSelected()); leaf->setSelected(true); QGraphicsScene scene2; scene2.addItem(item1); QVERIFY(!item1->isSelected()); QVERIFY(item2->isSelected()); } void tst_QGraphicsItem::selected_textItem() { QGraphicsScene scene; QGraphicsTextItem *text = scene.addText(QLatin1String("Text")); text->setFlag(QGraphicsItem::ItemIsSelectable); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(20); QTRY_VERIFY(!text->isSelected()); QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(text->mapToScene(0, 0))); QTRY_VERIFY(text->isSelected()); text->setSelected(false); text->setTextInteractionFlags(Qt::TextEditorInteraction); QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(text->mapToScene(0, 0))); QTRY_VERIFY(text->isSelected()); } void tst_QGraphicsItem::selected_multi() { // Test multiselection behavior QGraphicsScene scene; // Create two disjoint items QGraphicsItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20)); QGraphicsItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20)); item1->setPos(-15, 0); item2->setPos(15, 20); // Make both items selectable item1->setFlag(QGraphicsItem::ItemIsSelectable); item2->setFlag(QGraphicsItem::ItemIsSelectable); // Create and show a view QGraphicsView view(&scene); view.show(); view.fitInView(scene.sceneRect()); qApp->processEvents(); QVERIFY(!item1->isSelected()); QVERIFY(!item2->isSelected()); // Start clicking QTest::qWait(200); // Click on item1 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); // Click on item2 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos())); QTest::qWait(20); QVERIFY(item2->isSelected()); QVERIFY(!item1->isSelected()); // Ctrl-click on item1 QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item2->isSelected()); QVERIFY(item1->isSelected()); // Ctrl-click on item1 again QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item2->isSelected()); QVERIFY(!item1->isSelected()); // Ctrl-click on item2 QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item2->scenePos())); QTest::qWait(20); QVERIFY(!item2->isSelected()); QVERIFY(!item1->isSelected()); // Click on item1 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); // Click on scene QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(0, 0)); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(!item2->isSelected()); // Click on item1 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); // Ctrl-click on scene QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(0, 0)); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(!item2->isSelected()); // Click on item1 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); // Press on item2 QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos())); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(item2->isSelected()); // Release on item2 QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item2->scenePos())); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(item2->isSelected()); // Click on item1 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); // Ctrl-click on item1 QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(!item2->isSelected()); // Ctrl-press on item1 QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(!item2->isSelected()); { // Ctrl-move on item1 QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier); QApplication::sendEvent(view.viewport(), &event); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(!item2->isSelected()); } // Release on item1 QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); item1->setFlag(QGraphicsItem::ItemIsMovable); item1->setSelected(false); // Ctrl-press on item1 QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(!item1->isSelected()); QVERIFY(!item2->isSelected()); { // Ctrl-move on item1 QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->scenePos()) + QPoint(1, 0), Qt::LeftButton, Qt::LeftButton, Qt::ControlModifier); QApplication::sendEvent(view.viewport(), &event); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); } // Release on item1 QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.mapFromScene(item1->scenePos())); QTest::qWait(20); QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); } void tst_QGraphicsItem::acceptedMouseButtons() { QGraphicsScene scene; QGraphicsRectItem *item1 = scene.addRect(QRectF(-10, -10, 20, 20)); QGraphicsRectItem *item2 = scene.addRect(QRectF(-10, -10, 20, 20)); item2->setZValue(1); item1->setFlag(QGraphicsItem::ItemIsMovable); item2->setFlag(QGraphicsItem::ItemIsMovable); QCOMPARE(item1->acceptedMouseButtons(), Qt::MouseButtons(0x1f)); QCOMPARE(item2->acceptedMouseButtons(), Qt::MouseButtons(0x1f)); QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setButton(Qt::LeftButton); event.setScenePos(QPointF(0, 0)); QApplication::sendEvent(&scene, &event); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item2); item2->setAcceptedMouseButtons(0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); QApplication::sendEvent(&scene, &event); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item1); } class HoverItem : public QGraphicsRectItem { public: HoverItem(const QRectF &rect) : QGraphicsRectItem(rect), hoverInCount(0), hoverMoveCount(0), hoverOutCount(0) { } int hoverInCount; int hoverMoveCount; int hoverOutCount; protected: void hoverEnterEvent(QGraphicsSceneHoverEvent *) { ++hoverInCount; } void hoverMoveEvent(QGraphicsSceneHoverEvent *) { ++hoverMoveCount; } void hoverLeaveEvent(QGraphicsSceneHoverEvent *) { ++hoverOutCount; } }; void tst_QGraphicsItem::acceptsHoverEvents() { QGraphicsScene scene; HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20)); HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10)); scene.addItem(item1); scene.addItem(item2); item2->setZValue(1); QVERIFY(!item1->acceptsHoverEvents()); QVERIFY(!item2->acceptsHoverEvents()); item1->setAcceptsHoverEvents(true); item2->setAcceptsHoverEvents(true); QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove); event.setScenePos(QPointF(-100, -100)); QApplication::sendEvent(&scene, &event); event.setScenePos(QPointF(-2.5, -2.5)); QApplication::sendEvent(&scene, &event); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item2->hoverInCount, 1); item1->setAcceptsHoverEvents(false); item2->setAcceptsHoverEvents(false); event.setScenePos(QPointF(-100, -100)); QApplication::sendEvent(&scene, &event); event.setScenePos(QPointF(-2.5, -2.5)); QApplication::sendEvent(&scene, &event); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item2->hoverInCount, 1); item1->setAcceptsHoverEvents(true); item2->setAcceptsHoverEvents(false); event.setScenePos(QPointF(-100, -100)); QApplication::sendEvent(&scene, &event); event.setScenePos(QPointF(-2.5, -2.5)); QApplication::sendEvent(&scene, &event); QCOMPARE(item1->hoverInCount, 1); QCOMPARE(item2->hoverInCount, 1); } void tst_QGraphicsItem::childAcceptsHoverEvents() { QGraphicsScene scene; HoverItem *item1 = new HoverItem(QRectF(-10, -10, 20, 20)); HoverItem *item2 = new HoverItem(QRectF(-5, -5, 10, 10)); scene.addItem(item1); scene.addItem(item2); item2->setParentItem(item1); item2->setAcceptHoverEvents(true); QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove); event.setScenePos(QPointF(-100, -100)); QApplication::sendEvent(&scene, &event); QCOMPARE(item2->hoverInCount, 0); QCOMPARE(item2->hoverMoveCount, 0); QCOMPARE(item2->hoverOutCount, 0); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item1->hoverMoveCount, 0); QCOMPARE(item1->hoverOutCount, 0); event.setScenePos(QPointF(-2.5, -2.5)); QApplication::sendEvent(&scene, &event); QCOMPARE(item2->hoverInCount, 1); QCOMPARE(item2->hoverMoveCount, 1); QCOMPARE(item2->hoverOutCount, 0); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item1->hoverMoveCount, 0); QCOMPARE(item1->hoverOutCount, 0); event.setScenePos(QPointF(0, 0)); QApplication::sendEvent(&scene, &event); QCOMPARE(item2->hoverInCount, 1); QCOMPARE(item2->hoverMoveCount, 2); QCOMPARE(item2->hoverOutCount, 0); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item1->hoverMoveCount, 0); QCOMPARE(item1->hoverOutCount, 0); event.setScenePos(QPointF(-7, -7)); QApplication::sendEvent(&scene, &event); QCOMPARE(item2->hoverInCount, 1); QCOMPARE(item2->hoverMoveCount, 2); QCOMPARE(item2->hoverOutCount, 1); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item1->hoverMoveCount, 0); QCOMPARE(item1->hoverOutCount, 0); event.setScenePos(QPointF(0, 0)); QApplication::sendEvent(&scene, &event); QCOMPARE(item2->hoverInCount, 2); QCOMPARE(item2->hoverMoveCount, 3); QCOMPARE(item2->hoverOutCount, 1); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item1->hoverMoveCount, 0); QCOMPARE(item1->hoverOutCount, 0); HoverItem *item0 = new HoverItem(QRectF(-20, -20, 20, 20)); scene.addItem(item0); item1->setParentItem(item0); item0->setAcceptHoverEvents(true); event.setScenePos(QPointF(-100, -100)); QApplication::sendEvent(&scene, &event); event.setScenePos(QPointF(-15, -15)); QApplication::sendEvent(&scene, &event); QCOMPARE(item2->hoverInCount, 2); QCOMPARE(item2->hoverMoveCount, 3); QCOMPARE(item2->hoverOutCount, 2); QCOMPARE(item1->hoverInCount, 0); QCOMPARE(item1->hoverMoveCount, 0); QCOMPARE(item1->hoverOutCount, 0); QCOMPARE(item0->hoverInCount, 1); QCOMPARE(item0->hoverMoveCount, 1); QCOMPARE(item0->hoverOutCount, 0); } void tst_QGraphicsItem::hasFocus() { QGraphicsLineItem *line = new QGraphicsLineItem; QVERIFY(!line->hasFocus()); line->setFocus(); QVERIFY(!line->hasFocus()); QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); scene.addItem(line); line->setFocus(); QVERIFY(!line->hasFocus()); line->setFlag(QGraphicsItem::ItemIsFocusable); line->setFocus(); QVERIFY(line->hasFocus()); QGraphicsScene scene2; QApplication::sendEvent(&scene2, &activate); scene2.addItem(line); QVERIFY(!line->hasFocus()); QCOMPARE(scene.focusItem(), (QGraphicsItem *)0); QCOMPARE(scene2.focusItem(), (QGraphicsItem *)0); line->setFocus(); QVERIFY(line->hasFocus()); line->clearFocus(); QVERIFY(!line->hasFocus()); QGraphicsLineItem *line2 = new QGraphicsLineItem; line2->setFlag(QGraphicsItem::ItemIsFocusable); scene2.addItem(line2); line2->setFocus(); QVERIFY(!line->hasFocus()); QVERIFY(line2->hasFocus()); line->setFocus(); QVERIFY(line->hasFocus()); QVERIFY(!line2->hasFocus()); } void tst_QGraphicsItem::pos() { QGraphicsItem *child = new QGraphicsLineItem; QGraphicsItem *parent = new QGraphicsLineItem; QCOMPARE(child->pos(), QPointF()); QCOMPARE(parent->pos(), QPointF()); child->setParentItem(parent); child->setPos(10, 10); QCOMPARE(child->pos(), QPointF(10, 10)); parent->setPos(10, 10); QCOMPARE(parent->pos(), QPointF(10, 10)); QCOMPARE(child->pos(), QPointF(10, 10)); delete child; delete parent; } void tst_QGraphicsItem::scenePos() { QGraphicsItem *child = new QGraphicsLineItem; QGraphicsItem *parent = new QGraphicsLineItem; QCOMPARE(child->scenePos(), QPointF()); QCOMPARE(parent->scenePos(), QPointF()); child->setParentItem(parent); child->setPos(10, 10); QCOMPARE(child->scenePos(), QPointF(10, 10)); parent->setPos(10, 10); QCOMPARE(parent->scenePos(), QPointF(10, 10)); QCOMPARE(child->scenePos(), QPointF(20, 20)); parent->setPos(20, 20); QCOMPARE(parent->scenePos(), QPointF(20, 20)); QCOMPARE(child->scenePos(), QPointF(30, 30)); delete child; delete parent; } void tst_QGraphicsItem::matrix() { QGraphicsLineItem line; QCOMPARE(line.matrix(), QMatrix()); line.setMatrix(QMatrix().rotate(90)); QCOMPARE(line.matrix(), QMatrix().rotate(90)); line.setMatrix(QMatrix().rotate(90)); QCOMPARE(line.matrix(), QMatrix().rotate(90)); line.setMatrix(QMatrix().rotate(90), true); QCOMPARE(line.matrix(), QMatrix().rotate(180)); line.setMatrix(QMatrix().rotate(-90), true); QCOMPARE(line.matrix(), QMatrix().rotate(90)); line.resetMatrix(); QCOMPARE(line.matrix(), QMatrix()); line.rotate(90); QCOMPARE(line.matrix(), QMatrix().rotate(90)); line.rotate(90); QCOMPARE(line.matrix(), QMatrix().rotate(90).rotate(90)); line.resetMatrix(); line.scale(2, 4); QCOMPARE(line.matrix(), QMatrix().scale(2, 4)); line.scale(2, 4); QCOMPARE(line.matrix(), QMatrix().scale(2, 4).scale(2, 4)); line.resetMatrix(); line.shear(2, 4); QCOMPARE(line.matrix(), QMatrix().shear(2, 4)); line.shear(2, 4); QCOMPARE(line.matrix(), QMatrix().shear(2, 4).shear(2, 4)); line.resetMatrix(); line.translate(10, 10); QCOMPARE(line.matrix(), QMatrix().translate(10, 10)); line.translate(10, 10); QCOMPARE(line.matrix(), QMatrix().translate(10, 10).translate(10, 10)); line.resetMatrix(); } void tst_QGraphicsItem::sceneMatrix() { QGraphicsLineItem *parent = new QGraphicsLineItem; QGraphicsLineItem *child = new QGraphicsLineItem(QLineF(), parent); QCOMPARE(parent->sceneMatrix(), QMatrix()); QCOMPARE(child->sceneMatrix(), QMatrix()); parent->translate(10, 10); QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10)); QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10)); child->translate(10, 10); QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10)); QCOMPARE(child->sceneMatrix(), QMatrix().translate(20, 20)); parent->rotate(90); QCOMPARE(parent->sceneMatrix(), QMatrix().translate(10, 10).rotate(90)); QCOMPARE(child->sceneMatrix(), QMatrix().translate(10, 10).rotate(90).translate(10, 10)); delete child; delete parent; } void tst_QGraphicsItem::setMatrix() { QGraphicsScene scene; qRegisterMetaType >("QList"); QSignalSpy spy(&scene, SIGNAL(changed(QList))); QRectF unrotatedRect(-12, -34, 56, 78); QGraphicsRectItem item(unrotatedRect, 0, &scene); scene.update(scene.sceneRect()); QApplication::instance()->processEvents(); QCOMPARE(spy.count(), 1); item.setMatrix(QMatrix().rotate(qreal(12.34))); QRectF rotatedRect = scene.sceneRect(); QVERIFY(unrotatedRect != rotatedRect); scene.update(scene.sceneRect()); QApplication::instance()->processEvents(); QCOMPARE(spy.count(), 2); item.setMatrix(QMatrix()); scene.update(scene.sceneRect()); QApplication::instance()->processEvents(); QCOMPARE(spy.count(), 3); QList rlist = qVariantValue >(spy.last().at(0)); QCOMPARE(rlist.size(), 3); QCOMPARE(rlist.at(0), rotatedRect); // From item.setMatrix() (clearing rotated rect) QCOMPARE(rlist.at(1), rotatedRect); // From scene.update() (updating scene rect) QCOMPARE(rlist.at(2), unrotatedRect); // From post-update (update current state) } static QList _paintedItems; class PainterItem : public QGraphicsItem { protected: QRectF boundingRect() const { return QRectF(-10, -10, 20, 20); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { _paintedItems << this; painter->fillRect(boundingRect(), Qt::red); } }; void tst_QGraphicsItem::zValue() { Q_CHECK_PAINTEVENTS QGraphicsScene scene; QGraphicsItem *item1 = new PainterItem; QGraphicsItem *item2 = new PainterItem; QGraphicsItem *item3 = new PainterItem; QGraphicsItem *item4 = new PainterItem; scene.addItem(item1); scene.addItem(item2); scene.addItem(item3); scene.addItem(item4); item2->setZValue(-3); item4->setZValue(-2); item1->setZValue(-1); item3->setZValue(0); QGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif QApplication::processEvents(); #ifdef Q_WS_QWS QApplication::sendPostedEvents(); //glib workaround #endif QTRY_VERIFY(!_paintedItems.isEmpty()); QVERIFY((_paintedItems.size() % 4) == 0); for (int i = 0; i < 3; ++i) QVERIFY(_paintedItems.at(i)->zValue() < _paintedItems.at(i + 1)->zValue()); } void tst_QGraphicsItem::shape() { QGraphicsLineItem line(QLineF(-10, -10, 20, 20)); // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0 // if we pass a value of 0.0 to QPainterPathStroker::setWidth() const qreal penWidthZero = qreal(0.00000001); QPainterPathStroker ps; ps.setWidth(penWidthZero); QPainterPath path(line.line().p1()); path.lineTo(line.line().p2()); QPainterPath p = ps.createStroke(path); p.addPath(path); QCOMPARE(line.shape(), p); QPen linePen; linePen.setWidthF(5.0); linePen.setCapStyle(Qt::RoundCap); line.setPen(linePen); ps.setCapStyle(line.pen().capStyle()); ps.setWidth(line.pen().widthF()); p = ps.createStroke(path); p.addPath(path); QCOMPARE(line.shape(), p); linePen.setCapStyle(Qt::FlatCap); line.setPen(linePen); ps.setCapStyle(line.pen().capStyle()); p = ps.createStroke(path); p.addPath(path); QCOMPARE(line.shape(), p); linePen.setCapStyle(Qt::SquareCap); line.setPen(linePen); ps.setCapStyle(line.pen().capStyle()); p = ps.createStroke(path); p.addPath(path); QCOMPARE(line.shape(), p); QGraphicsRectItem rect(QRectF(-10, -10, 20, 20)); QPainterPathStroker ps1; ps1.setWidth(penWidthZero); path = QPainterPath(); path.addRect(rect.rect()); p = ps1.createStroke(path); p.addPath(path); QCOMPARE(rect.shape(), p); QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20)); QPainterPathStroker ps2; ps2.setWidth(ellipse.pen().widthF() <= 0.0 ? penWidthZero : ellipse.pen().widthF()); path = QPainterPath(); path.addEllipse(ellipse.rect()); p = ps2.createStroke(path); p.addPath(path); QCOMPARE(ellipse.shape(), p); QPainterPathStroker ps3; ps3.setWidth(penWidthZero); p = ps3.createStroke(path); p.addPath(path); QGraphicsPathItem pathItem(path); QCOMPARE(pathItem.shape(), p); QRegion region(QRect(0, 0, 300, 200)); region = region.subtracted(QRect(50, 50, 200, 100)); QImage image(300, 200, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter painter(&image); painter.setClipRegion(region); painter.fillRect(0, 0, 300, 200, Qt::green); painter.end(); QPixmap pixmap = QPixmap::fromImage(image); QGraphicsPixmapItem pixmapItem(pixmap); path = QPainterPath(); path.addRegion(region); { QBitmap bitmap(300, 200); bitmap.clear(); QPainter painter(&bitmap); painter.setClipRegion(region); painter.fillRect(0, 0, 300, 200, Qt::color1); painter.end(); QBitmap bitmap2(300, 200); bitmap2.clear(); painter.begin(&bitmap2); painter.setClipPath(pixmapItem.shape()); painter.fillRect(0, 0, 300, 200, Qt::color1); painter.end(); QCOMPARE(bitmap.toImage(), bitmap2.toImage()); } QPolygonF poly; poly << QPointF(0, 0) << QPointF(10, 0) << QPointF(0, 10); QGraphicsPolygonItem polygon(poly); path = QPainterPath(); path.addPolygon(poly); QPainterPathStroker ps4; ps4.setWidth(penWidthZero); p = ps4.createStroke(path); p.addPath(path); QCOMPARE(polygon.shape(), p); } void tst_QGraphicsItem::contains() { if (sizeof(qreal) != sizeof(double)) { QSKIP("Skipped due to rounding errors", SkipAll); } // Rect QGraphicsRectItem rect(QRectF(-10, -10, 20, 20)); QVERIFY(!rect.contains(QPointF(-11, -10))); QVERIFY(rect.contains(QPointF(-10, -10))); QVERIFY(!rect.contains(QPointF(-11, 0))); QVERIFY(rect.contains(QPointF(-10, 0))); QVERIFY(rect.contains(QPointF(0, -10))); QVERIFY(rect.contains(QPointF(0, 0))); QVERIFY(rect.contains(QPointF(9, 9))); // Ellipse QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20)); QVERIFY(!ellipse.contains(QPointF(-10, -10))); QVERIFY(ellipse.contains(QPointF(-9, 0))); QVERIFY(ellipse.contains(QPointF(0, -9))); QVERIFY(ellipse.contains(QPointF(0, 0))); QVERIFY(!ellipse.contains(QPointF(9, 9))); // Line QGraphicsLineItem line(QLineF(-10, -10, 20, 20)); QVERIFY(!line.contains(QPointF(-10, 0))); QVERIFY(!line.contains(QPointF(0, -10))); QVERIFY(!line.contains(QPointF(10, 0))); QVERIFY(!line.contains(QPointF(0, 10))); QVERIFY(line.contains(QPointF(0, 0))); QVERIFY(line.contains(QPointF(-9, -9))); QVERIFY(line.contains(QPointF(9, 9))); // Polygon QGraphicsPolygonItem polygon(QPolygonF() << QPointF(0, 0) << QPointF(10, 0) << QPointF(0, 10)); QVERIFY(polygon.contains(QPointF(1, 1))); QVERIFY(polygon.contains(QPointF(4, 4))); QVERIFY(polygon.contains(QPointF(1, 4))); QVERIFY(polygon.contains(QPointF(4, 1))); QVERIFY(!polygon.contains(QPointF(8, 8))); QVERIFY(polygon.contains(QPointF(1, 8))); QVERIFY(polygon.contains(QPointF(8, 1))); } void tst_QGraphicsItem::collidesWith_item() { // Rectangle QGraphicsRectItem rect(QRectF(-10, -10, 20, 20)); QGraphicsRectItem rect2(QRectF(-10, -10, 20, 20)); QVERIFY(rect.collidesWithItem(&rect2)); QVERIFY(rect2.collidesWithItem(&rect)); rect2.setPos(21, 21); QVERIFY(!rect.collidesWithItem(&rect2)); QVERIFY(!rect2.collidesWithItem(&rect)); rect2.setPos(-21, -21); QVERIFY(!rect.collidesWithItem(&rect2)); QVERIFY(!rect2.collidesWithItem(&rect)); rect2.setPos(-17, -17); QVERIFY(rect.collidesWithItem(&rect2)); QVERIFY(rect2.collidesWithItem(&rect)); QGraphicsEllipseItem ellipse(QRectF(-10, -10, 20, 20)); QGraphicsEllipseItem ellipse2(QRectF(-10, -10, 20, 20)); QVERIFY(ellipse.collidesWithItem(&ellipse2)); QVERIFY(ellipse2.collidesWithItem(&ellipse)); ellipse2.setPos(21, 21); QVERIFY(!ellipse.collidesWithItem(&ellipse2)); QVERIFY(!ellipse2.collidesWithItem(&ellipse)); ellipse2.setPos(-21, -21); QVERIFY(!ellipse.collidesWithItem(&ellipse2)); QVERIFY(!ellipse2.collidesWithItem(&ellipse)); ellipse2.setPos(-17, -17); QVERIFY(!ellipse.collidesWithItem(&ellipse2)); QVERIFY(!ellipse2.collidesWithItem(&ellipse)); { QGraphicsScene scene; QGraphicsRectItem rect(20, 20, 100, 100, 0, &scene); QGraphicsRectItem rect2(40, 40, 50, 50, 0, &scene); rect2.setZValue(1); QGraphicsLineItem line(0, 0, 200, 200, 0, &scene); line.setZValue(2); QCOMPARE(scene.items().size(), 3); QList col1 = rect.collidingItems(); QCOMPARE(col1.size(), 2); QCOMPARE(col1.first(), static_cast(&line)); QCOMPARE(col1.last(), static_cast(&rect2)); QList col2 = rect2.collidingItems(); QCOMPARE(col2.size(), 2); QCOMPARE(col2.first(), static_cast(&line)); QCOMPARE(col2.last(), static_cast(&rect)); QList col3 = line.collidingItems(); QCOMPARE(col3.size(), 2); QCOMPARE(col3.first(), static_cast(&rect2)); QCOMPARE(col3.last(), static_cast(&rect)); } } void tst_QGraphicsItem::collidesWith_path_data() { QTest::addColumn("pos"); QTest::addColumn("matrix"); QTest::addColumn("shape"); QTest::addColumn("rectCollides"); QTest::addColumn("ellipseCollides"); QTest::newRow("nothing") << QPointF(0, 0) << QMatrix() << QPainterPath() << false << false; QPainterPath rect; rect.addRect(0, 0, 20, 20); QTest::newRow("rect1") << QPointF(0, 0) << QMatrix() << rect << true << true; QTest::newRow("rect2") << QPointF(0, 0) << QMatrix().translate(21, 21) << rect << false << false; QTest::newRow("rect3") << QPointF(21, 21) << QMatrix() << rect << false << false; } void tst_QGraphicsItem::collidesWith_path() { QFETCH(QPointF, pos); QFETCH(QMatrix, matrix); QFETCH(QPainterPath, shape); QFETCH(bool, rectCollides); QFETCH(bool, ellipseCollides); QGraphicsRectItem rect(QRectF(0, 0, 20, 20)); QGraphicsEllipseItem ellipse(QRectF(0, 0, 20, 20)); rect.setPos(pos); rect.setMatrix(matrix); ellipse.setPos(pos); ellipse.setMatrix(matrix); QPainterPath mappedShape = rect.sceneMatrix().inverted().map(shape); if (rectCollides) QVERIFY(rect.collidesWithPath(mappedShape)); else QVERIFY(!rect.collidesWithPath(mappedShape)); if (ellipseCollides) QVERIFY(ellipse.collidesWithPath(mappedShape)); else QVERIFY(!ellipse.collidesWithPath(mappedShape)); } void tst_QGraphicsItem::collidesWithItemWithClip() { QGraphicsScene scene; QGraphicsEllipseItem *ellipse = scene.addEllipse(0, 0, 100, 100); ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape); QGraphicsEllipseItem *ellipse2 = scene.addEllipse(0, 0, 10, 10); ellipse2->setParentItem(ellipse); QGraphicsEllipseItem *ellipse3 = scene.addEllipse(0, 0, 10, 10); ellipse3->setParentItem(ellipse); QGraphicsEllipseItem *ellipse5 = scene.addEllipse(50, 50, 10, 10); ellipse5->setParentItem(ellipse); QGraphicsEllipseItem *ellipse4 = scene.addEllipse(0, 0, 10, 10); QVERIFY(ellipse2->collidesWithItem(ellipse3)); QVERIFY(ellipse3->collidesWithItem(ellipse2)); QVERIFY(!ellipse2->collidesWithItem(ellipse)); QVERIFY(!ellipse->collidesWithItem(ellipse2)); QVERIFY(!ellipse4->collidesWithItem(ellipse)); QVERIFY(!ellipse4->collidesWithItem(ellipse2)); QVERIFY(!ellipse4->collidesWithItem(ellipse3)); QVERIFY(!ellipse->collidesWithItem(ellipse4)); QVERIFY(!ellipse2->collidesWithItem(ellipse4)); QVERIFY(!ellipse3->collidesWithItem(ellipse4)); QVERIFY(ellipse->collidesWithItem(ellipse5)); QVERIFY(ellipse5->collidesWithItem(ellipse)); } class MyItem : public QGraphicsEllipseItem { public: bool isObscuredBy(const QGraphicsItem *item) const { const MyItem *myItem = qgraphicsitem_cast(item); if (myItem) { if (item->zValue() > zValue()) { QRectF r = rect(); QPointF topMid = (r.topRight()+r.topLeft())/2; QPointF botMid = (r.bottomRight()+r.bottomLeft())/2; QPointF leftMid = (r.topLeft()+r.bottomLeft())/2; QPointF rightMid = (r.topRight()+r.bottomRight())/2; QPainterPath mappedShape = item->mapToItem(this, item->opaqueArea()); if (mappedShape.contains(topMid) && mappedShape.contains(botMid) && mappedShape.contains(leftMid) && mappedShape.contains(rightMid)) return true; else return false; } else return false; } else return QGraphicsItem::isObscuredBy(item); } QPainterPath opaqueArea() const { return shape(); } enum { Type = UserType+1 }; int type() const { return Type; } }; void tst_QGraphicsItem::isObscuredBy() { QGraphicsScene scene; MyItem myitem1, myitem2; myitem1.setRect(QRectF(50, 50, 40, 200)); myitem1.rotate(67); myitem2.setRect(QRectF(25, 25, 20, 20)); myitem2.setZValue(-1.0); scene.addItem(&myitem1); scene.addItem(&myitem2); QVERIFY(!myitem2.isObscuredBy(&myitem1)); QVERIFY(!myitem1.isObscuredBy(&myitem2)); myitem2.setRect(QRectF(-50, 85, 20, 20)); QVERIFY(myitem2.isObscuredBy(&myitem1)); QVERIFY(!myitem1.isObscuredBy(&myitem2)); myitem2.setRect(QRectF(-30, 70, 20, 20)); QVERIFY(!myitem2.isObscuredBy(&myitem1)); QVERIFY(!myitem1.isObscuredBy(&myitem2)); QGraphicsRectItem rect1, rect2; rect1.setRect(QRectF(-40, -40, 50, 50)); rect1.setBrush(QBrush(Qt::red)); rect2.setRect(QRectF(-30, -20, 20, 20)); rect2.setZValue(-1.0); rect2.setBrush(QBrush(Qt::blue)); QVERIFY(rect2.isObscuredBy(&rect1)); QVERIFY(!rect1.isObscuredBy(&rect2)); rect2.setPos(QPointF(-20, -25)); QVERIFY(!rect2.isObscuredBy(&rect1)); QVERIFY(!rect1.isObscuredBy(&rect2)); rect2.setPos(QPointF(-100, -100)); QVERIFY(!rect2.isObscuredBy(&rect1)); QVERIFY(!rect1.isObscuredBy(&rect2)); } class OpaqueItem : public QGraphicsRectItem { protected: QPainterPath opaqueArea() const { return shape(); } }; void tst_QGraphicsItem::isObscured() { if (sizeof(qreal) != sizeof(double)) { QSKIP("Skipped due to rounding errors", SkipAll); } OpaqueItem *item1 = new OpaqueItem; item1->setRect(0, 0, 100, 100); item1->setZValue(0); OpaqueItem *item2 = new OpaqueItem; item2->setZValue(1); item2->setRect(0, 0, 100, 100); QGraphicsScene scene; scene.addItem(item1); scene.addItem(item2); QVERIFY(item1->isObscured()); QVERIFY(item1->isObscuredBy(item2)); QVERIFY(item1->isObscured(QRectF(0, 0, 50, 50))); QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50))); QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50))); QVERIFY(item1->isObscured(QRectF(0, 50, 50, 50))); QVERIFY(item1->isObscured(0, 0, 50, 50)); QVERIFY(item1->isObscured(50, 0, 50, 50)); QVERIFY(item1->isObscured(50, 50, 50, 50)); QVERIFY(item1->isObscured(0, 50, 50, 50)); QVERIFY(!item2->isObscured()); QVERIFY(!item2->isObscuredBy(item1)); QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50))); QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50))); QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50))); QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50))); QVERIFY(!item2->isObscured(0, 0, 50, 50)); QVERIFY(!item2->isObscured(50, 0, 50, 50)); QVERIFY(!item2->isObscured(50, 50, 50, 50)); QVERIFY(!item2->isObscured(0, 50, 50, 50)); item2->moveBy(50, 0); QVERIFY(!item1->isObscured()); QVERIFY(!item1->isObscuredBy(item2)); QVERIFY(!item1->isObscured(QRectF(0, 0, 50, 50))); QVERIFY(item1->isObscured(QRectF(50, 0, 50, 50))); QVERIFY(item1->isObscured(QRectF(50, 50, 50, 50))); QVERIFY(!item1->isObscured(QRectF(0, 50, 50, 50))); QVERIFY(!item1->isObscured(0, 0, 50, 50)); QVERIFY(item1->isObscured(50, 0, 50, 50)); QVERIFY(item1->isObscured(50, 50, 50, 50)); QVERIFY(!item1->isObscured(0, 50, 50, 50)); QVERIFY(!item2->isObscured()); QVERIFY(!item2->isObscuredBy(item1)); QVERIFY(!item2->isObscured(QRectF(0, 0, 50, 50))); QVERIFY(!item2->isObscured(QRectF(50, 0, 50, 50))); QVERIFY(!item2->isObscured(QRectF(50, 50, 50, 50))); QVERIFY(!item2->isObscured(QRectF(0, 50, 50, 50))); QVERIFY(!item2->isObscured(0, 0, 50, 50)); QVERIFY(!item2->isObscured(50, 0, 50, 50)); QVERIFY(!item2->isObscured(50, 50, 50, 50)); QVERIFY(!item2->isObscured(0, 50, 50, 50)); } void tst_QGraphicsItem::mapFromToParent() { QPainterPath path1; path1.addRect(0, 0, 200, 200); QPainterPath path2; path2.addRect(0, 0, 100, 100); QPainterPath path3; path3.addRect(0, 0, 50, 50); QPainterPath path4; path4.addRect(0, 0, 25, 25); QGraphicsItem *item1 = new QGraphicsPathItem(path1); QGraphicsItem *item2 = new QGraphicsPathItem(path2, item1); QGraphicsItem *item3 = new QGraphicsPathItem(path3, item2); QGraphicsItem *item4 = new QGraphicsPathItem(path4, item3); item1->setPos(10, 10); item2->setPos(10, 10); item3->setPos(10, 10); item4->setPos(10, 10); for (int i = 0; i < 4; ++i) { QMatrix matrix; matrix.rotate(i * 90); matrix.translate(i * 100, -i * 100); matrix.scale(2, 4); item1->setMatrix(matrix); QCOMPARE(item1->mapToParent(QPointF(0, 0)), item1->pos() + matrix.map(QPointF(0, 0))); QCOMPARE(item2->mapToParent(QPointF(0, 0)), item2->pos()); QCOMPARE(item3->mapToParent(QPointF(0, 0)), item3->pos()); QCOMPARE(item4->mapToParent(QPointF(0, 0)), item4->pos()); QCOMPARE(item1->mapToParent(QPointF(10, -10)), item1->pos() + matrix.map(QPointF(10, -10))); QCOMPARE(item2->mapToParent(QPointF(10, -10)), item2->pos() + QPointF(10, -10)); QCOMPARE(item3->mapToParent(QPointF(10, -10)), item3->pos() + QPointF(10, -10)); QCOMPARE(item4->mapToParent(QPointF(10, -10)), item4->pos() + QPointF(10, -10)); QCOMPARE(item1->mapToParent(QPointF(-10, 10)), item1->pos() + matrix.map(QPointF(-10, 10))); QCOMPARE(item2->mapToParent(QPointF(-10, 10)), item2->pos() + QPointF(-10, 10)); QCOMPARE(item3->mapToParent(QPointF(-10, 10)), item3->pos() + QPointF(-10, 10)); QCOMPARE(item4->mapToParent(QPointF(-10, 10)), item4->pos() + QPointF(-10, 10)); QCOMPARE(item1->mapFromParent(item1->pos()), matrix.inverted().map(QPointF(0, 0))); QCOMPARE(item2->mapFromParent(item2->pos()), QPointF(0, 0)); QCOMPARE(item3->mapFromParent(item3->pos()), QPointF(0, 0)); QCOMPARE(item4->mapFromParent(item4->pos()), QPointF(0, 0)); QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(10, -10)), matrix.inverted().map(QPointF(10, -10))); QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(10, -10)), QPointF(10, -10)); QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(10, -10)), QPointF(10, -10)); QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(10, -10)), QPointF(10, -10)); QCOMPARE(item1->mapFromParent(item1->pos() + QPointF(-10, 10)), matrix.inverted().map(QPointF(-10, 10))); QCOMPARE(item2->mapFromParent(item2->pos() + QPointF(-10, 10)), QPointF(-10, 10)); QCOMPARE(item3->mapFromParent(item3->pos() + QPointF(-10, 10)), QPointF(-10, 10)); QCOMPARE(item4->mapFromParent(item4->pos() + QPointF(-10, 10)), QPointF(-10, 10)); } delete item1; } void tst_QGraphicsItem::mapFromToScene() { QGraphicsItem *item1 = new QGraphicsPathItem(QPainterPath()); QGraphicsItem *item2 = new QGraphicsPathItem(QPainterPath(), item1); QGraphicsItem *item3 = new QGraphicsPathItem(QPainterPath(), item2); QGraphicsItem *item4 = new QGraphicsPathItem(QPainterPath(), item3); item1->setPos(100, 100); item2->setPos(100, 100); item3->setPos(100, 100); item4->setPos(100, 100); QCOMPARE(item1->pos(), QPointF(100, 100)); QCOMPARE(item2->pos(), QPointF(100, 100)); QCOMPARE(item3->pos(), QPointF(100, 100)); QCOMPARE(item4->pos(), QPointF(100, 100)); QCOMPARE(item1->pos(), item1->mapToParent(0, 0)); QCOMPARE(item2->pos(), item2->mapToParent(0, 0)); QCOMPARE(item3->pos(), item3->mapToParent(0, 0)); QCOMPARE(item4->pos(), item4->mapToParent(0, 0)); QCOMPARE(item1->mapToParent(10, 10), QPointF(110, 110)); QCOMPARE(item2->mapToParent(10, 10), QPointF(110, 110)); QCOMPARE(item3->mapToParent(10, 10), QPointF(110, 110)); QCOMPARE(item4->mapToParent(10, 10), QPointF(110, 110)); QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100)); QCOMPARE(item2->mapToScene(0, 0), QPointF(200, 200)); QCOMPARE(item3->mapToScene(0, 0), QPointF(300, 300)); QCOMPARE(item4->mapToScene(0, 0), QPointF(400, 400)); QCOMPARE(item1->mapToScene(10, 0), QPointF(110, 100)); QCOMPARE(item2->mapToScene(10, 0), QPointF(210, 200)); QCOMPARE(item3->mapToScene(10, 0), QPointF(310, 300)); QCOMPARE(item4->mapToScene(10, 0), QPointF(410, 400)); QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0)); QCOMPARE(item2->mapFromScene(200, 200), QPointF(0, 0)); QCOMPARE(item3->mapFromScene(300, 300), QPointF(0, 0)); QCOMPARE(item4->mapFromScene(400, 400), QPointF(0, 0)); QCOMPARE(item1->mapFromScene(110, 100), QPointF(10, 0)); QCOMPARE(item2->mapFromScene(210, 200), QPointF(10, 0)); QCOMPARE(item3->mapFromScene(310, 300), QPointF(10, 0)); QCOMPARE(item4->mapFromScene(410, 400), QPointF(10, 0)); // Rotate item1 90 degrees clockwise QMatrix matrix; matrix.rotate(90); item1->setMatrix(matrix); QCOMPARE(item1->pos(), item1->mapToParent(0, 0)); QCOMPARE(item2->pos(), item2->mapToParent(0, 0)); QCOMPARE(item3->pos(), item3->mapToParent(0, 0)); QCOMPARE(item4->pos(), item4->mapToParent(0, 0)); QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110)); QCOMPARE(item2->mapToParent(10, 0), QPointF(110, 100)); QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100)); QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100)); QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100)); QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200)); QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 300)); QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 400)); QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110)); QCOMPARE(item2->mapToScene(10, 0), QPointF(0, 210)); QCOMPARE(item3->mapToScene(10, 0), QPointF(-100, 310)); QCOMPARE(item4->mapToScene(10, 0), QPointF(-200, 410)); QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0)); QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0)); QCOMPARE(item3->mapFromScene(-100, 300), QPointF(0, 0)); QCOMPARE(item4->mapFromScene(-200, 400), QPointF(0, 0)); QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0)); QCOMPARE(item2->mapFromScene(0, 210), QPointF(10, 0)); QCOMPARE(item3->mapFromScene(-100, 310), QPointF(10, 0)); QCOMPARE(item4->mapFromScene(-200, 410), QPointF(10, 0)); // Rotate item2 90 degrees clockwise item2->setMatrix(matrix); QCOMPARE(item1->pos(), item1->mapToParent(0, 0)); QCOMPARE(item2->pos(), item2->mapToParent(0, 0)); QCOMPARE(item3->pos(), item3->mapToParent(0, 0)); QCOMPARE(item4->pos(), item4->mapToParent(0, 0)); QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110)); QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110)); QCOMPARE(item3->mapToParent(10, 0), QPointF(110, 100)); QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100)); QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100)); QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200)); QCOMPARE(item3->mapToScene(0, 0), QPointF(-100, 100)); QCOMPARE(item4->mapToScene(0, 0), QPointF(-200, 0)); QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110)); QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200)); QCOMPARE(item3->mapToScene(10, 0), QPointF(-110, 100)); QCOMPARE(item4->mapToScene(10, 0), QPointF(-210, 0)); QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0)); QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0)); QCOMPARE(item3->mapFromScene(-100, 100), QPointF(0, 0)); QCOMPARE(item4->mapFromScene(-200, 0), QPointF(0, 0)); QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0)); QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0)); QCOMPARE(item3->mapFromScene(-110, 100), QPointF(10, 0)); QCOMPARE(item4->mapFromScene(-210, 0), QPointF(10, 0)); // Translate item3 50 points, then rotate 90 degrees counterclockwise QMatrix matrix2; matrix2.translate(50, 0); matrix2.rotate(-90); item3->setMatrix(matrix2); QCOMPARE(item1->pos(), item1->mapToParent(0, 0)); QCOMPARE(item2->pos(), item2->mapToParent(0, 0)); QCOMPARE(item3->pos(), item3->mapToParent(0, 0) - QPointF(50, 0)); QCOMPARE(item4->pos(), item4->mapToParent(0, 0)); QCOMPARE(item1->mapToParent(10, 0), QPointF(100, 110)); QCOMPARE(item2->mapToParent(10, 0), QPointF(100, 110)); QCOMPARE(item3->mapToParent(10, 0), QPointF(150, 90)); QCOMPARE(item4->mapToParent(10, 0), QPointF(110, 100)); QCOMPARE(item1->mapToScene(0, 0), QPointF(100, 100)); QCOMPARE(item2->mapToScene(0, 0), QPointF(0, 200)); QCOMPARE(item3->mapToScene(0, 0), QPointF(-150, 100)); QCOMPARE(item4->mapToScene(0, 0), QPointF(-250, 200)); QCOMPARE(item1->mapToScene(10, 0), QPointF(100, 110)); QCOMPARE(item2->mapToScene(10, 0), QPointF(-10, 200)); QCOMPARE(item3->mapToScene(10, 0), QPointF(-150, 110)); QCOMPARE(item4->mapToScene(10, 0), QPointF(-250, 210)); QCOMPARE(item1->mapFromScene(100, 100), QPointF(0, 0)); QCOMPARE(item2->mapFromScene(0, 200), QPointF(0, 0)); QCOMPARE(item3->mapFromScene(-150, 100), QPointF(0, 0)); QCOMPARE(item4->mapFromScene(-250, 200), QPointF(0, 0)); QCOMPARE(item1->mapFromScene(100, 110), QPointF(10, 0)); QCOMPARE(item2->mapFromScene(-10, 200), QPointF(10, 0)); QCOMPARE(item3->mapFromScene(-150, 110), QPointF(10, 0)); QCOMPARE(item4->mapFromScene(-250, 210), QPointF(10, 0)); delete item1; } void tst_QGraphicsItem::mapFromToItem() { QGraphicsItem *item1 = new QGraphicsPathItem; QGraphicsItem *item2 = new QGraphicsPathItem; QGraphicsItem *item3 = new QGraphicsPathItem; QGraphicsItem *item4 = new QGraphicsPathItem; item1->setPos(-100, -100); item2->setPos(100, -100); item3->setPos(100, 100); item4->setPos(-100, 100); QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(200, 0)); QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200)); QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0)); QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(0, -200)); QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(0, 200)); QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-200, 0)); QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200)); QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0)); QMatrix matrix; matrix.translate(100, 100); item1->setMatrix(matrix); QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(100, -100)); QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(0, 200)); QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(-200, 0)); QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(100, -100)); QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(-100, 100)); QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(-100, 100)); QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(0, -200)); QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(200, 0)); matrix.rotate(90); item1->setMatrix(matrix); item2->setMatrix(matrix); item3->setMatrix(matrix); item4->setMatrix(matrix); QCOMPARE(item1->mapFromItem(item2, 0, 0), QPointF(0, -200)); QCOMPARE(item2->mapFromItem(item3, 0, 0), QPointF(200, 0)); QCOMPARE(item3->mapFromItem(item4, 0, 0), QPointF(0, 200)); QCOMPARE(item4->mapFromItem(item1, 0, 0), QPointF(-200, 0)); QCOMPARE(item1->mapFromItem(item4, 0, 0), QPointF(200, 0)); QCOMPARE(item2->mapFromItem(item1, 0, 0), QPointF(0, 200)); QCOMPARE(item3->mapFromItem(item2, 0, 0), QPointF(-200, 0)); QCOMPARE(item4->mapFromItem(item3, 0, 0), QPointF(0, -200)); QCOMPARE(item1->mapFromItem(item2, 10, -5), QPointF(10, -205)); QCOMPARE(item2->mapFromItem(item3, 10, -5), QPointF(210, -5)); QCOMPARE(item3->mapFromItem(item4, 10, -5), QPointF(10, 195)); QCOMPARE(item4->mapFromItem(item1, 10, -5), QPointF(-190, -5)); QCOMPARE(item1->mapFromItem(item4, 10, -5), QPointF(210, -5)); QCOMPARE(item2->mapFromItem(item1, 10, -5), QPointF(10, 195)); QCOMPARE(item3->mapFromItem(item2, 10, -5), QPointF(-190, -5)); QCOMPARE(item4->mapFromItem(item3, 10, -5), QPointF(10, -205)); QCOMPARE(item1->mapFromItem(0, 10, -5), item1->mapFromScene(10, -5)); QCOMPARE(item2->mapFromItem(0, 10, -5), item2->mapFromScene(10, -5)); QCOMPARE(item3->mapFromItem(0, 10, -5), item3->mapFromScene(10, -5)); QCOMPARE(item4->mapFromItem(0, 10, -5), item4->mapFromScene(10, -5)); QCOMPARE(item1->mapToItem(0, 10, -5), item1->mapToScene(10, -5)); QCOMPARE(item2->mapToItem(0, 10, -5), item2->mapToScene(10, -5)); QCOMPARE(item3->mapToItem(0, 10, -5), item3->mapToScene(10, -5)); QCOMPARE(item4->mapToItem(0, 10, -5), item4->mapToScene(10, -5)); delete item1; delete item2; delete item3; delete item4; } void tst_QGraphicsItem::mapRectFromToParent_data() { QTest::addColumn("parent"); QTest::addColumn("parentPos"); QTest::addColumn("parentTransform"); QTest::addColumn("pos"); QTest::addColumn("transform"); QTest::addColumn("inputRect"); QTest::addColumn("outputRect"); QTest::newRow("nil") << false << QPointF() << QTransform() << QPointF() << QTransform() << QRectF() << QRectF(); QTest::newRow("simple") << false << QPointF() << QTransform() << QPointF() << QTransform() << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10); QTest::newRow("simple w/parent") << true << QPointF() << QTransform() << QPointF() << QTransform() << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10); QTest::newRow("simple w/parent parentPos") << true << QPointF(50, 50) << QTransform() << QPointF() << QTransform() << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10); QTest::newRow("simple w/parent parentPos parentRotation") << true << QPointF(50, 50) << QTransform().rotate(45) << QPointF() << QTransform() << QRectF(0, 0, 10, 10) << QRectF(0, 0, 10, 10); QTest::newRow("pos w/parent") << true << QPointF() << QTransform() << QPointF(50, 50) << QTransform() << QRectF(0, 0, 10, 10) << QRectF(50, 50, 10, 10); QTest::newRow("rotation w/parent") << true << QPointF() << QTransform() << QPointF() << QTransform().rotate(90) << QRectF(0, 0, 10, 10) << QRectF(-10, 0, 10, 10); QTest::newRow("pos rotation w/parent") << true << QPointF() << QTransform() << QPointF(50, 50) << QTransform().rotate(90) << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10); QTest::newRow("pos rotation w/parent parentPos parentRotation") << true << QPointF(-170, -190) << QTransform().rotate(90) << QPointF(50, 50) << QTransform().rotate(90) << QRectF(0, 0, 10, 10) << QRectF(40, 50, 10, 10); } void tst_QGraphicsItem::mapRectFromToParent() { QFETCH(bool, parent); QFETCH(QPointF, parentPos); QFETCH(QTransform, parentTransform); QFETCH(QPointF, pos); QFETCH(QTransform, transform); QFETCH(QRectF, inputRect); QFETCH(QRectF, outputRect); QGraphicsRectItem *rect = new QGraphicsRectItem; rect->setPos(pos); rect->setTransform(transform); if (parent) { QGraphicsRectItem *rectParent = new QGraphicsRectItem; rect->setParentItem(rectParent); rectParent->setPos(parentPos); rectParent->setTransform(parentTransform); } // Make sure we use non-destructive transform operations (e.g., 90 degree // rotations). QCOMPARE(rect->mapRectToParent(inputRect), outputRect); QCOMPARE(rect->mapRectFromParent(outputRect), inputRect); QCOMPARE(rect->itemTransform(rect->parentItem()).mapRect(inputRect), outputRect); QCOMPARE(rect->mapToParent(inputRect).boundingRect(), outputRect); QCOMPARE(rect->mapToParent(QPolygonF(inputRect)).boundingRect(), outputRect); QCOMPARE(rect->mapFromParent(outputRect).boundingRect(), inputRect); QCOMPARE(rect->mapFromParent(QPolygonF(outputRect)).boundingRect(), inputRect); QPainterPath inputPath; inputPath.addRect(inputRect); QPainterPath outputPath; outputPath.addRect(outputRect); QCOMPARE(rect->mapToParent(inputPath).boundingRect(), outputPath.boundingRect()); QCOMPARE(rect->mapFromParent(outputPath).boundingRect(), inputPath.boundingRect()); } void tst_QGraphicsItem::isAncestorOf() { QGraphicsItem *grandPa = new QGraphicsRectItem; QGraphicsItem *parent = new QGraphicsRectItem; QGraphicsItem *child = new QGraphicsRectItem; QVERIFY(!parent->isAncestorOf(0)); QVERIFY(!child->isAncestorOf(0)); QVERIFY(!parent->isAncestorOf(child)); QVERIFY(!child->isAncestorOf(parent)); QVERIFY(!parent->isAncestorOf(parent)); child->setParentItem(parent); parent->setParentItem(grandPa); QVERIFY(parent->isAncestorOf(child)); QVERIFY(grandPa->isAncestorOf(parent)); QVERIFY(grandPa->isAncestorOf(child)); QVERIFY(!child->isAncestorOf(parent)); QVERIFY(!parent->isAncestorOf(grandPa)); QVERIFY(!child->isAncestorOf(grandPa)); QVERIFY(!child->isAncestorOf(child)); QVERIFY(!parent->isAncestorOf(parent)); QVERIFY(!grandPa->isAncestorOf(grandPa)); parent->setParentItem(0); delete child; delete parent; delete grandPa; } void tst_QGraphicsItem::commonAncestorItem() { QGraphicsItem *ancestor = new QGraphicsRectItem; QGraphicsItem *grandMa = new QGraphicsRectItem; QGraphicsItem *grandPa = new QGraphicsRectItem; QGraphicsItem *brotherInLaw = new QGraphicsRectItem; QGraphicsItem *cousin = new QGraphicsRectItem; QGraphicsItem *husband = new QGraphicsRectItem; QGraphicsItem *child = new QGraphicsRectItem; QGraphicsItem *wife = new QGraphicsRectItem; child->setParentItem(husband); husband->setParentItem(grandPa); brotherInLaw->setParentItem(grandPa); cousin->setParentItem(brotherInLaw); wife->setParentItem(grandMa); grandMa->setParentItem(ancestor); grandPa->setParentItem(ancestor); QCOMPARE(grandMa->commonAncestorItem(grandMa), grandMa); QCOMPARE(grandMa->commonAncestorItem(0), (QGraphicsItem *)0); QCOMPARE(grandMa->commonAncestorItem(grandPa), ancestor); QCOMPARE(grandPa->commonAncestorItem(grandMa), ancestor); QCOMPARE(grandPa->commonAncestorItem(husband), grandPa); QCOMPARE(grandPa->commonAncestorItem(wife), ancestor); QCOMPARE(grandMa->commonAncestorItem(husband), ancestor); QCOMPARE(grandMa->commonAncestorItem(wife), grandMa); QCOMPARE(wife->commonAncestorItem(grandMa), grandMa); QCOMPARE(child->commonAncestorItem(cousin), grandPa); QCOMPARE(cousin->commonAncestorItem(child), grandPa); QCOMPARE(wife->commonAncestorItem(child), ancestor); QCOMPARE(child->commonAncestorItem(wife), ancestor); } void tst_QGraphicsItem::data() { QGraphicsTextItem text; QCOMPARE(text.data(0), QVariant()); text.setData(0, "TextItem"); QCOMPARE(text.data(0), QVariant(QString("TextItem"))); text.setData(0, QVariant()); QCOMPARE(text.data(0), QVariant()); } void tst_QGraphicsItem::type() { QCOMPARE(int(QGraphicsItem::Type), 1); QCOMPARE(int(QGraphicsPathItem::Type), 2); QCOMPARE(int(QGraphicsRectItem::Type), 3); QCOMPARE(int(QGraphicsEllipseItem::Type), 4); QCOMPARE(int(QGraphicsPolygonItem::Type), 5); QCOMPARE(int(QGraphicsLineItem::Type), 6); QCOMPARE(int(QGraphicsPixmapItem::Type), 7); QCOMPARE(int(QGraphicsTextItem::Type), 8); QCOMPARE(QGraphicsPathItem().type(), 2); QCOMPARE(QGraphicsRectItem().type(), 3); QCOMPARE(QGraphicsEllipseItem().type(), 4); QCOMPARE(QGraphicsPolygonItem().type(), 5); QCOMPARE(QGraphicsLineItem().type(), 6); QCOMPARE(QGraphicsPixmapItem().type(), 7); QCOMPARE(QGraphicsTextItem().type(), 8); } void tst_QGraphicsItem::graphicsitem_cast() { QGraphicsPathItem pathItem; const QGraphicsPathItem *pPathItem = &pathItem; QGraphicsRectItem rectItem; const QGraphicsRectItem *pRectItem = &rectItem; QGraphicsEllipseItem ellipseItem; const QGraphicsEllipseItem *pEllipseItem = &ellipseItem; QGraphicsPolygonItem polygonItem; const QGraphicsPolygonItem *pPolygonItem = &polygonItem; QGraphicsLineItem lineItem; const QGraphicsLineItem *pLineItem = &lineItem; QGraphicsPixmapItem pixmapItem; const QGraphicsPixmapItem *pPixmapItem = &pixmapItem; QGraphicsTextItem textItem; const QGraphicsTextItem *pTextItem = &textItem; QVERIFY(qgraphicsitem_cast(&pathItem)); //QVERIFY(qgraphicsitem_cast(&pathItem)); QVERIFY(qgraphicsitem_cast(&pathItem)); QVERIFY(qgraphicsitem_cast(pPathItem)); QVERIFY(qgraphicsitem_cast(pPathItem)); QVERIFY(qgraphicsitem_cast(&rectItem)); QVERIFY(qgraphicsitem_cast(&rectItem)); QVERIFY(qgraphicsitem_cast(pRectItem)); QVERIFY(qgraphicsitem_cast(pRectItem)); QVERIFY(qgraphicsitem_cast(&ellipseItem)); QVERIFY(qgraphicsitem_cast(&ellipseItem)); QVERIFY(qgraphicsitem_cast(pEllipseItem)); QVERIFY(qgraphicsitem_cast(pEllipseItem)); QVERIFY(qgraphicsitem_cast(&polygonItem)); //QVERIFY(qgraphicsitem_cast(&polygonItem)); QVERIFY(qgraphicsitem_cast(&polygonItem)); QVERIFY(qgraphicsitem_cast(pPolygonItem)); QVERIFY(qgraphicsitem_cast(pPolygonItem)); QVERIFY(qgraphicsitem_cast(&lineItem)); QVERIFY(qgraphicsitem_cast(&lineItem)); QVERIFY(qgraphicsitem_cast(pLineItem)); QVERIFY(qgraphicsitem_cast(pLineItem)); QVERIFY(qgraphicsitem_cast(&pixmapItem)); QVERIFY(qgraphicsitem_cast(&pixmapItem)); QVERIFY(qgraphicsitem_cast(pPixmapItem)); QVERIFY(qgraphicsitem_cast(pPixmapItem)); QVERIFY(qgraphicsitem_cast(&textItem)); QVERIFY(qgraphicsitem_cast(&textItem)); QVERIFY(qgraphicsitem_cast(pTextItem)); QVERIFY(qgraphicsitem_cast(pTextItem)); // and some casts that _should_ fail: QVERIFY(!qgraphicsitem_cast(&pathItem)); QVERIFY(!qgraphicsitem_cast(pPolygonItem)); // and this shouldn't crash QGraphicsItem *ptr = 0; QVERIFY(!qgraphicsitem_cast(ptr)); QVERIFY(!qgraphicsitem_cast(ptr)); } void tst_QGraphicsItem::hoverEventsGenerateRepaints() { Q_CHECK_PAINTEVENTS QGraphicsScene scene; QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(150); EventTester *tester = new EventTester; scene.addItem(tester); tester->setAcceptsHoverEvents(true); QTRY_COMPARE(tester->repaints, 1); // Send a hover enter event QGraphicsSceneHoverEvent hoverEnterEvent(QEvent::GraphicsSceneHoverEnter); hoverEnterEvent.setScenePos(QPointF(0, 0)); hoverEnterEvent.setPos(QPointF(0, 0)); QApplication::sendEvent(&scene, &hoverEnterEvent); // Check that we get a repaint int npaints = tester->repaints; qApp->processEvents(); qApp->processEvents(); QCOMPARE(tester->events.size(), 2); // enter + move QCOMPARE(tester->repaints, npaints + 1); QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove); // Send a hover move event QGraphicsSceneHoverEvent hoverMoveEvent(QEvent::GraphicsSceneHoverMove); hoverMoveEvent.setScenePos(QPointF(0, 0)); hoverMoveEvent.setPos(QPointF(0, 0)); QApplication::sendEvent(&scene, &hoverMoveEvent); // Check that we don't get a repaint qApp->processEvents(); qApp->processEvents(); QCOMPARE(tester->events.size(), 3); QCOMPARE(tester->repaints, npaints + 1); QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverMove); // Send a hover leave event QGraphicsSceneHoverEvent hoverLeaveEvent(QEvent::GraphicsSceneHoverLeave); hoverLeaveEvent.setScenePos(QPointF(-100, -100)); hoverLeaveEvent.setPos(QPointF(0, 0)); QApplication::sendEvent(&scene, &hoverLeaveEvent); // Check that we get a repaint qApp->processEvents(); qApp->processEvents(); QCOMPARE(tester->events.size(), 4); QCOMPARE(tester->repaints, npaints + 2); QCOMPARE(tester->events.last(), QEvent::GraphicsSceneHoverLeave); } void tst_QGraphicsItem::boundingRects_data() { QTest::addColumn("item"); QTest::addColumn("boundingRect"); QRectF rect(0, 0, 100, 100); QPainterPath path; path.addRect(rect); QRectF adjustedRect(-0.5, -0.5, 101, 101); QTest::newRow("path") << (QGraphicsItem *)new QGraphicsPathItem(path) << adjustedRect; QTest::newRow("rect") << (QGraphicsItem *)new QGraphicsRectItem(rect) << adjustedRect; QTest::newRow("ellipse") << (QGraphicsItem *)new QGraphicsEllipseItem(rect) << adjustedRect; QTest::newRow("polygon") << (QGraphicsItem *)new QGraphicsPolygonItem(rect) << adjustedRect; } void tst_QGraphicsItem::boundingRects() { QFETCH(QGraphicsItem *, item); QFETCH(QRectF, boundingRect); ((QAbstractGraphicsShapeItem *)item)->setPen(QPen(Qt::black, 1)); QCOMPARE(item->boundingRect(), boundingRect); } void tst_QGraphicsItem::boundingRects2() { QGraphicsPixmapItem pixmap(QPixmap::fromImage(QImage(100, 100, QImage::Format_ARGB32_Premultiplied))); QCOMPARE(pixmap.boundingRect(), QRectF(0, 0, 100, 100)); QGraphicsLineItem line(0, 0, 100, 0); line.setPen(QPen(Qt::black, 1)); QCOMPARE(line.boundingRect(), QRectF(-0.5, -0.5, 101, 1)); } void tst_QGraphicsItem::sceneBoundingRect() { QGraphicsScene scene; QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0)); item->setPos(100, 100); QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100)); QCOMPARE(item->sceneBoundingRect(), QRectF(100, 100, 100, 100)); item->rotate(90); QCOMPARE(item->boundingRect(), QRectF(0, 0, 100, 100)); QCOMPARE(item->sceneBoundingRect(), QRectF(0, 100, 100, 100)); } void tst_QGraphicsItem::childrenBoundingRect() { QGraphicsScene scene; QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0)); QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0)); child->setParentItem(parent); parent->setPos(100, 100); child->setPos(100, 100); QCOMPARE(parent->boundingRect(), QRectF(0, 0, 100, 100)); QCOMPARE(child->boundingRect(), QRectF(0, 0, 100, 100)); QCOMPARE(child->childrenBoundingRect(), QRectF()); QCOMPARE(parent->childrenBoundingRect(), QRectF(100, 100, 100, 100)); QGraphicsRectItem *child2 = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0)); child2->setParentItem(parent); child2->setPos(-100, -100); QCOMPARE(parent->childrenBoundingRect(), QRectF(-100, -100, 300, 300)); QGraphicsRectItem *childChild = scene.addRect(QRectF(0, 0, 100, 100), QPen(Qt::black, 0)); childChild->setParentItem(child); childChild->setPos(500, 500); child->rotate(90); scene.addPolygon(parent->mapToScene(parent->boundingRect() | parent->childrenBoundingRect()))->setPen(QPen(Qt::red));; QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(30); QCOMPARE(parent->childrenBoundingRect(), QRectF(-500, -100, 600, 800)); } void tst_QGraphicsItem::childrenBoundingRectTransformed() { QGraphicsScene scene; QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100)); rect2->setParentItem(rect); rect3->setParentItem(rect2); rect4->setParentItem(rect3); rect5->setParentItem(rect4); rect2->setTransform(QTransform().translate(50, 50).rotate(45)); rect2->setPos(25, 25); rect3->setTransform(QTransform().translate(50, 50).rotate(45)); rect3->setPos(25, 25); rect4->setTransform(QTransform().translate(50, 50).rotate(45)); rect4->setPos(25, 25); rect5->setTransform(QTransform().translate(50, 50).rotate(45)); rect5->setPos(25, 25); QRectF subTreeRect = rect->childrenBoundingRect(); QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821)); QCOMPARE(subTreeRect.top(), qreal(75.0)); QCOMPARE(subTreeRect.width(), qreal(351.7766952966369)); QCOMPARE(subTreeRect.height(), qreal(251.7766952966369)); rect->rotate(45); rect2->rotate(-45); rect3->rotate(45); rect4->rotate(-45); rect5->rotate(45); subTreeRect = rect->childrenBoundingRect(); QCOMPARE(rect->childrenBoundingRect(), QRectF(-100, 75, 275, 250)); } void tst_QGraphicsItem::childrenBoundingRect2() { QGraphicsItemGroup box; QGraphicsLineItem l1(0, 0, 100, 0, &box); QGraphicsLineItem l2(100, 0, 100, 100, &box); QGraphicsLineItem l3(0, 0, 0, 100, &box); // Make sure lines (zero with/height) are included in the childrenBoundingRect. QCOMPARE(box.childrenBoundingRect(), QRectF(0, 0, 100, 100)); } void tst_QGraphicsItem::childrenBoundingRect3() { QGraphicsScene scene; QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect4 = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *rect5 = scene.addRect(QRectF(0, 0, 100, 100)); rect2->setParentItem(rect); rect3->setParentItem(rect2); rect4->setParentItem(rect3); rect5->setParentItem(rect4); rect2->setTransform(QTransform().translate(50, 50).rotate(45)); rect2->setPos(25, 25); rect3->setTransform(QTransform().translate(50, 50).rotate(45)); rect3->setPos(25, 25); rect4->setTransform(QTransform().translate(50, 50).rotate(45)); rect4->setPos(25, 25); rect5->setTransform(QTransform().translate(50, 50).rotate(45)); rect5->setPos(25, 25); // Try to mess up the cached bounding rect. (void)rect2->childrenBoundingRect(); QRectF subTreeRect = rect->childrenBoundingRect(); QCOMPARE(subTreeRect.left(), qreal(-206.0660171779821)); QCOMPARE(subTreeRect.top(), qreal(75.0)); QCOMPARE(subTreeRect.width(), qreal(351.7766952966369)); QCOMPARE(subTreeRect.height(), qreal(251.7766952966369)); } void tst_QGraphicsItem::childrenBoundingRect4() { QGraphicsScene scene; QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 10, 10)); QGraphicsRectItem *rect2 = scene.addRect(QRectF(0, 0, 20, 20)); QGraphicsRectItem *rect3 = scene.addRect(QRectF(0, 0, 30, 30)); rect2->setParentItem(rect); rect3->setParentItem(rect); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); // Try to mess up the cached bounding rect. rect->childrenBoundingRect(); rect2->childrenBoundingRect(); rect3->setOpacity(0.0); rect3->setParentItem(rect2); QCOMPARE(rect->childrenBoundingRect(), rect3->boundingRect()); QCOMPARE(rect2->childrenBoundingRect(), rect3->boundingRect()); } void tst_QGraphicsItem::childrenBoundingRect5() { QGraphicsScene scene; QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 100, 100)); child->setParentItem(parent); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); // Try to mess up the cached bounding rect. QRectF expectedChildrenBoundingRect = parent->boundingRect(); QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect); // Apply some effects. QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect; dropShadow->setOffset(25, 25); child->setGraphicsEffect(dropShadow); parent->setGraphicsEffect(new QGraphicsOpacityEffect); QVERIFY(parent->childrenBoundingRect() != expectedChildrenBoundingRect); expectedChildrenBoundingRect |= dropShadow->boundingRect(); QCOMPARE(parent->childrenBoundingRect(), expectedChildrenBoundingRect); } void tst_QGraphicsItem::group() { QGraphicsScene scene; QGraphicsRectItem *parent = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::green)); QGraphicsRectItem *child = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::blue)); QGraphicsRectItem *parent2 = scene.addRect(QRectF(0, 0, 50, 50), QPen(Qt::black, 0), QBrush(Qt::red)); parent2->setPos(-50, 50); child->rotate(45); child->setParentItem(parent); parent->setPos(25, 25); child->setPos(25, 25); QCOMPARE(parent->group(), (QGraphicsItemGroup *)0); QCOMPARE(parent2->group(), (QGraphicsItemGroup *)0); QCOMPARE(child->group(), (QGraphicsItemGroup *)0); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QApplication::processEvents(); QGraphicsItemGroup *group = new QGraphicsItemGroup; group->setSelected(true); scene.addItem(group); QRectF parentSceneBoundingRect = parent->sceneBoundingRect(); group->addToGroup(parent); QCOMPARE(parent->group(), group); QCOMPARE(parent->sceneBoundingRect(), parentSceneBoundingRect); QCOMPARE(parent->parentItem(), (QGraphicsItem *)group); QCOMPARE(group->children().size(), 1); QCOMPARE(scene.items().size(), 4); QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 3); QTest::qWait(25); QRectF parent2SceneBoundingRect = parent2->sceneBoundingRect(); group->addToGroup(parent2); QCOMPARE(parent2->group(), group); QCOMPARE(parent2->sceneBoundingRect(), parent2SceneBoundingRect); QCOMPARE(parent2->parentItem(), (QGraphicsItem *)group); QCOMPARE(group->children().size(), 2); QCOMPARE(scene.items().size(), 4); QCOMPARE(scene.items(group->sceneBoundingRect()).size(), 4); QTest::qWait(25); QList newItems; for (int i = 0; i < 100; ++i) { QGraphicsItem *item = scene.addRect(QRectF(-25, -25, 50, 50), QPen(Qt::black, 0), QBrush(QColor(rand() % 255, rand() % 255, rand() % 255, rand() % 255))); newItems << item; item->setPos(-1000 + rand() % 2000, -1000 + rand() % 2000); item->rotate(rand() % 90); } view.fitInView(scene.itemsBoundingRect()); int n = 0; foreach (QGraphicsItem *item, newItems) { group->addToGroup(item); QCOMPARE(item->group(), group); if ((n++ % 100) == 0) QTest::qWait(10); } } void tst_QGraphicsItem::setGroup() { QGraphicsItemGroup group1; QGraphicsItemGroup group2; QGraphicsRectItem *rect = new QGraphicsRectItem; QCOMPARE(rect->group(), (QGraphicsItemGroup *)0); QCOMPARE(rect->parentItem(), (QGraphicsItem *)0); rect->setGroup(&group1); QCOMPARE(rect->group(), &group1); QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group1); rect->setGroup(&group2); QCOMPARE(rect->group(), &group2); QCOMPARE(rect->parentItem(), (QGraphicsItem *)&group2); rect->setGroup(0); QCOMPARE(rect->group(), (QGraphicsItemGroup *)0); QCOMPARE(rect->parentItem(), (QGraphicsItem *)0); } void tst_QGraphicsItem::setGroup2() { QGraphicsScene scene; QGraphicsItemGroup group; scene.addItem(&group); QGraphicsRectItem *rect = scene.addRect(50,50,50,50,Qt::NoPen,Qt::black); rect->setTransformOriginPoint(50,50); rect->setRotation(45); rect->setScale(1.5); rect->translate(20,20); group.translate(-30,-40); group.setRotation(180); group.setScale(0.5); QTransform oldSceneTransform = rect->sceneTransform(); rect->setGroup(&group); QCOMPARE(rect->sceneTransform(), oldSceneTransform); group.setRotation(20); group.setScale(2); rect->setRotation(90); rect->setScale(0.8); oldSceneTransform = rect->sceneTransform(); rect->setGroup(0); QCOMPARE(rect->sceneTransform(), oldSceneTransform); } void tst_QGraphicsItem::nestedGroups() { QGraphicsItemGroup *group1 = new QGraphicsItemGroup; QGraphicsItemGroup *group2 = new QGraphicsItemGroup; QGraphicsRectItem *rect = new QGraphicsRectItem; QGraphicsRectItem *rect2 = new QGraphicsRectItem; rect2->setParentItem(rect); group1->addToGroup(rect); QCOMPARE(rect->group(), group1); QCOMPARE(rect2->group(), group1); group2->addToGroup(group1); QCOMPARE(rect->group(), group1); QCOMPARE(rect2->group(), group1); QCOMPARE(group1->group(), group2); QCOMPARE(group2->group(), (QGraphicsItemGroup *)0); QGraphicsScene scene; scene.addItem(group1); QCOMPARE(rect->group(), group1); QCOMPARE(rect2->group(), group1); QCOMPARE(group1->group(), (QGraphicsItemGroup *)0); QVERIFY(group2->children().isEmpty()); delete group2; } void tst_QGraphicsItem::warpChildrenIntoGroup() { QGraphicsScene scene; QGraphicsRectItem *parentRectItem = scene.addRect(QRectF(0, 0, 100, 100)); QGraphicsRectItem *childRectItem = scene.addRect(QRectF(0, 0, 100, 100)); parentRectItem->rotate(90); childRectItem->setPos(-50, -25); childRectItem->setParentItem(parentRectItem); QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0)); QCOMPARE(childRectItem->scenePos(), QPointF(25, -50)); QGraphicsRectItem *parentOfGroup = scene.addRect(QRectF(0, 0, 100, 100)); parentOfGroup->setPos(-200, -200); parentOfGroup->scale(2, 2); QGraphicsItemGroup *group = new QGraphicsItemGroup; group->setPos(50, 50); group->setParentItem(parentOfGroup); QCOMPARE(group->scenePos(), QPointF(-100, -100)); group->addToGroup(childRectItem); QCOMPARE(childRectItem->mapToScene(50, 0), QPointF(25, 0)); QCOMPARE(childRectItem->scenePos(), QPointF(25, -50)); } void tst_QGraphicsItem::removeFromGroup() { QGraphicsScene scene; QGraphicsRectItem *rect1 = scene.addRect(QRectF(-100, -100, 200, 200)); QGraphicsRectItem *rect2 = scene.addRect(QRectF(100, 100, 200, 200)); rect1->setFlag(QGraphicsItem::ItemIsSelectable); rect2->setFlag(QGraphicsItem::ItemIsSelectable); rect1->setSelected(true); rect2->setSelected(true); QGraphicsView view(&scene); view.show(); qApp->processEvents(); // index items qApp->processEvents(); // emit changed QGraphicsItemGroup *group = scene.createItemGroup(scene.selectedItems()); QVERIFY(group); QCOMPARE(group->children().size(), 2); qApp->processEvents(); // index items qApp->processEvents(); // emit changed scene.destroyItemGroup(group); // calls removeFromGroup. qApp->processEvents(); // index items qApp->processEvents(); // emit changed QCOMPARE(scene.items().size(), 2); QVERIFY(!rect1->group()); QVERIFY(!rect2->group()); } class ChildEventTester : public QGraphicsRectItem { public: ChildEventTester(const QRectF &rect, QGraphicsItem *parent = 0) : QGraphicsRectItem(rect, parent), counter(0) { } int counter; protected: void focusInEvent(QFocusEvent *event) { ++counter; QGraphicsRectItem::focusInEvent(event); } void mousePressEvent(QGraphicsSceneMouseEvent *) { ++counter; } void mouseMoveEvent(QGraphicsSceneMouseEvent *) { ++counter; } void mouseReleaseEvent(QGraphicsSceneMouseEvent *) { ++counter; } }; void tst_QGraphicsItem::handlesChildEvents() { ChildEventTester *blue = new ChildEventTester(QRectF(0, 0, 100, 100)); ChildEventTester *red = new ChildEventTester(QRectF(0, 0, 50, 50)); ChildEventTester *green = new ChildEventTester(QRectF(0, 0, 25, 25)); ChildEventTester *gray = new ChildEventTester(QRectF(0, 0, 25, 25)); ChildEventTester *yellow = new ChildEventTester(QRectF(0, 0, 50, 50)); blue->setBrush(QBrush(Qt::blue)); red->setBrush(QBrush(Qt::red)); yellow->setBrush(QBrush(Qt::yellow)); green->setBrush(QBrush(Qt::green)); gray->setBrush(QBrush(Qt::gray)); red->setPos(50, 0); yellow->setPos(50, 50); green->setPos(25, 0); gray->setPos(25, 25); red->setParentItem(blue); yellow->setParentItem(blue); green->setParentItem(red); gray->setParentItem(red); QGraphicsScene scene; scene.addItem(blue); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(20); // Pull out the items, closest item first QList items = scene.items(scene.itemsBoundingRect()); QCOMPARE(items.at(0), (QGraphicsItem *)yellow); QCOMPARE(items.at(1), (QGraphicsItem *)gray); QCOMPARE(items.at(2), (QGraphicsItem *)green); QCOMPARE(items.at(3), (QGraphicsItem *)red); QCOMPARE(items.at(4), (QGraphicsItem *)blue); QCOMPARE(blue->counter, 0); // Send events to the toplevel item QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress); QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease); pressEvent.setButton(Qt::LeftButton); pressEvent.setScenePos(blue->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setButton(Qt::LeftButton); releaseEvent.setScenePos(blue->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(blue->counter, 2); // Send events to a level1 item pressEvent.setScenePos(red->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setScenePos(red->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(blue->counter, 2); QCOMPARE(red->counter, 2); // Send events to a level2 item pressEvent.setScenePos(green->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setScenePos(green->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(blue->counter, 2); QCOMPARE(red->counter, 2); QCOMPARE(green->counter, 2); blue->setHandlesChildEvents(true); // Send events to a level1 item pressEvent.setScenePos(red->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setScenePos(red->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(blue->counter, 4); QCOMPARE(red->counter, 2); // Send events to a level2 item pressEvent.setScenePos(green->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setScenePos(green->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(blue->counter, 6); QCOMPARE(red->counter, 2); QCOMPARE(green->counter, 2); blue->setHandlesChildEvents(false); // Send events to a level1 item pressEvent.setScenePos(red->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setScenePos(red->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(blue->counter, 6); QCOMPARE(red->counter, 4); // Send events to a level2 item pressEvent.setScenePos(green->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setScenePos(green->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(blue->counter, 6); QCOMPARE(red->counter, 4); QCOMPARE(green->counter, 4); } void tst_QGraphicsItem::handlesChildEvents2() { ChildEventTester *root = new ChildEventTester(QRectF(0, 0, 10, 10)); root->setHandlesChildEvents(true); QVERIFY(root->handlesChildEvents()); ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root); QVERIFY(!child->handlesChildEvents()); ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10)); ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2); ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3); child2->setParentItem(root); QVERIFY(!child2->handlesChildEvents()); QVERIFY(!child3->handlesChildEvents()); QVERIFY(!child4->handlesChildEvents()); QGraphicsScene scene; scene.addItem(root); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QApplication::processEvents(); QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5), view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0); QApplication::sendEvent(view.viewport(), &event); QTRY_COMPARE(root->counter, 1); } void tst_QGraphicsItem::handlesChildEvents3() { QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); ChildEventTester *group2 = new ChildEventTester(QRectF(), 0); ChildEventTester *group1 = new ChildEventTester(QRectF(), group2); ChildEventTester *leaf = new ChildEventTester(QRectF(), group1); scene.addItem(group2); leaf->setFlag(QGraphicsItem::ItemIsFocusable); group1->setFlag(QGraphicsItem::ItemIsFocusable); group1->setHandlesChildEvents(true); group2->setFlag(QGraphicsItem::ItemIsFocusable); group2->setHandlesChildEvents(true); leaf->setFocus(); QVERIFY(leaf->hasFocus()); // group2 stole the event, but leaf still got focus QVERIFY(!group1->hasFocus()); QVERIFY(!group2->hasFocus()); QCOMPARE(leaf->counter, 0); QCOMPARE(group1->counter, 0); QCOMPARE(group2->counter, 1); group1->setFocus(); QVERIFY(group1->hasFocus()); // group2 stole the event, but group1 still got focus QVERIFY(!leaf->hasFocus()); QVERIFY(!group2->hasFocus()); QCOMPARE(leaf->counter, 0); QCOMPARE(group1->counter, 0); QCOMPARE(group2->counter, 2); group2->setFocus(); QVERIFY(group2->hasFocus()); // group2 stole the event, and now group2 also has focus QVERIFY(!leaf->hasFocus()); QVERIFY(!group1->hasFocus()); QCOMPARE(leaf->counter, 0); QCOMPARE(group1->counter, 0); QCOMPARE(group2->counter, 3); } class ChildEventFilterTester : public ChildEventTester { public: ChildEventFilterTester(const QRectF &rect, QGraphicsItem *parent = 0) : ChildEventTester(rect, parent), filter(QEvent::None) { } QEvent::Type filter; protected: bool sceneEventFilter(QGraphicsItem *item, QEvent *event) { Q_UNUSED(item); if (event->type() == filter) { ++counter; return true; } return false; } }; void tst_QGraphicsItem::filtersChildEvents() { QGraphicsScene scene; ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10)); ChildEventFilterTester *filter = new ChildEventFilterTester(QRectF(10, 10, 10, 10), root); ChildEventTester *child = new ChildEventTester(QRectF(20, 20, 10, 10), filter); // setup filter filter->setFiltersChildEvents(true); filter->filter = QEvent::GraphicsSceneMousePress; scene.addItem(root); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(20); QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress); QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease); // send event to child pressEvent.setButton(Qt::LeftButton); pressEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setButton(Qt::LeftButton); releaseEvent.setScenePos(QPointF(25, 25));//child->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QTRY_COMPARE(child->counter, 1); // mouse release is not filtered QCOMPARE(filter->counter, 1); // mouse press is filtered QCOMPARE(root->counter, 0); // add another filter root->setFiltersChildEvents(true); root->filter = QEvent::GraphicsSceneMouseRelease; // send event to child QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(child->counter, 1); QCOMPARE(filter->counter, 2); // mouse press is filtered QCOMPARE(root->counter, 1); // mouse release is filtered // reparent to another sub-graph ChildEventTester *parent = new ChildEventTester(QRectF(10, 10, 10, 10), root); child->setParentItem(parent); // send event to child QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); QCOMPARE(child->counter, 2); // mouse press is _not_ filtered QCOMPARE(parent->counter, 0); QCOMPARE(filter->counter, 2); QCOMPARE(root->counter, 2); // mouse release is filtered } void tst_QGraphicsItem::filtersChildEvents2() { ChildEventFilterTester *root = new ChildEventFilterTester(QRectF(0, 0, 10, 10)); root->setFiltersChildEvents(true); root->filter = QEvent::GraphicsSceneMousePress; QVERIFY(root->filtersChildEvents()); ChildEventTester *child = new ChildEventTester(QRectF(0, 0, 10, 10), root); QVERIFY(!child->filtersChildEvents()); ChildEventTester *child2 = new ChildEventTester(QRectF(0, 0, 10, 10)); ChildEventTester *child3 = new ChildEventTester(QRectF(0, 0, 10, 10), child2); ChildEventTester *child4 = new ChildEventTester(QRectF(0, 0, 10, 10), child3); child2->setParentItem(root); QVERIFY(!child2->filtersChildEvents()); QVERIFY(!child3->filtersChildEvents()); QVERIFY(!child4->filtersChildEvents()); QGraphicsScene scene; scene.addItem(root); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QApplication::processEvents(); QMouseEvent event(QEvent::MouseButtonPress, view.mapFromScene(5, 5), view.viewport()->mapToGlobal(view.mapFromScene(5, 5)), Qt::LeftButton, 0, 0); QApplication::sendEvent(view.viewport(), &event); QTRY_COMPARE(root->counter, 1); QCOMPARE(child->counter, 0); QCOMPARE(child2->counter, 0); QCOMPARE(child3->counter, 0); QCOMPARE(child4->counter, 0); } class CustomItem : public QGraphicsItem { public: QRectF boundingRect() const { return QRectF(-110, -110, 220, 220); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { for (int x = -100; x <= 100; x += 25) painter->drawLine(x, -100, x, 100); for (int y = -100; y <= 100; y += 25) painter->drawLine(-100, y, 100, y); QFont font = painter->font(); font.setPointSize(4); painter->setFont(font); for (int x = -100; x < 100; x += 25) { for (int y = -100; y < 100; y += 25) { painter->drawText(QRectF(x, y, 25, 25), Qt::AlignCenter, QString("%1x%2").arg(x).arg(y)); } } } }; void tst_QGraphicsItem::ensureVisible() { QGraphicsScene scene; scene.setSceneRect(-200, -200, 400, 400); QGraphicsItem *item = new CustomItem; scene.addItem(item); QGraphicsView view(&scene); view.setFixedSize(300, 300); view.show(); QTest::qWaitForWindowShown(&view); for (int i = 0; i < 25; ++i) { view.scale(qreal(1.06), qreal(1.06)); QApplication::processEvents(); } item->ensureVisible(-100, -100, 25, 25); QTest::qWait(25); for (int x = -100; x < 100; x += 25) { for (int y = -100; y < 100; y += 25) { int xmargin = rand() % 75; int ymargin = rand() % 75; item->ensureVisible(x, y, 25, 25, xmargin, ymargin); QApplication::processEvents(); QPolygonF viewScenePoly; viewScenePoly << view.mapToScene(view.rect().topLeft()) << view.mapToScene(view.rect().topRight()) << view.mapToScene(view.rect().bottomRight()) << view.mapToScene(view.rect().bottomLeft()); QVERIFY(scene.items(viewScenePoly).contains(item)); QPainterPath path; path.addPolygon(viewScenePoly); QVERIFY(path.contains(item->mapToScene(x + 12, y + 12))); QPolygonF viewScenePolyMinusMargins; viewScenePolyMinusMargins << view.mapToScene(view.rect().topLeft() + QPoint(xmargin, ymargin)) << view.mapToScene(view.rect().topRight() + QPoint(-xmargin, ymargin)) << view.mapToScene(view.rect().bottomRight() + QPoint(-xmargin, -ymargin)) << view.mapToScene(view.rect().bottomLeft() + QPoint(xmargin, -ymargin)); QPainterPath path2; path2.addPolygon(viewScenePolyMinusMargins); QVERIFY(path2.contains(item->mapToScene(x + 12, y + 12))); } } item->ensureVisible(100, 100, 25, 25); QTest::qWait(25); } void tst_QGraphicsItem::cursor() { #ifndef QT_NO_CURSOR QGraphicsScene scene; QGraphicsRectItem *item1 = scene.addRect(QRectF(0, 0, 50, 50)); QGraphicsRectItem *item2 = scene.addRect(QRectF(0, 0, 50, 50)); item1->setPos(-100, 0); item2->setPos(50, 0); QVERIFY(!item1->hasCursor()); QVERIFY(!item2->hasCursor()); item1->setCursor(Qt::IBeamCursor); item2->setCursor(Qt::PointingHandCursor); QVERIFY(item1->hasCursor()); QVERIFY(item2->hasCursor()); item1->setCursor(QCursor()); item2->setCursor(QCursor()); QVERIFY(item1->hasCursor()); QVERIFY(item2->hasCursor()); item1->unsetCursor(); item2->unsetCursor(); QVERIFY(!item1->hasCursor()); QVERIFY(!item2->hasCursor()); item1->setCursor(Qt::IBeamCursor); item2->setCursor(Qt::PointingHandCursor); QWidget topLevel; QGraphicsView view(&scene,&topLevel); view.setFixedSize(200, 100); topLevel.show(); QTest::mouseMove(&view, view.rect().center()); QTest::qWait(25); QCursor cursor = view.viewport()->cursor(); { QMouseEvent event(QEvent::MouseMove, QPoint(100, 50), Qt::NoButton, 0, 0); QApplication::sendEvent(view.viewport(), &event); } QTest::qWait(25); QCOMPARE(view.viewport()->cursor().shape(), cursor.shape()); { QTest::mouseMove(view.viewport(), view.mapFromScene(item1->sceneBoundingRect().center())); QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item1->sceneBoundingRect().center()), Qt::NoButton, 0, 0); QApplication::sendEvent(view.viewport(), &event); } if (!PlatformQuirks::haveMouseCursor()) return; #if !defined(Q_OS_WINCE) QTest::qWait(250); #else // Test environment does not have any cursor, therefore no shape return; #endif QCOMPARE(view.viewport()->cursor().shape(), item1->cursor().shape()); { QTest::mouseMove(view.viewport(), view.mapFromScene(item2->sceneBoundingRect().center())); QMouseEvent event(QEvent::MouseMove, view.mapFromScene(item2->sceneBoundingRect().center()), Qt::NoButton, 0, 0); QApplication::sendEvent(view.viewport(), &event); } QTest::qWait(25); QCOMPARE(view.viewport()->cursor().shape(), item2->cursor().shape()); { QTest::mouseMove(view.viewport(), view.rect().center()); QMouseEvent event(QEvent::MouseMove, QPoint(100, 25), Qt::NoButton, 0, 0); QApplication::sendEvent(view.viewport(), &event); } QTest::qWait(25); QCOMPARE(view.viewport()->cursor().shape(), cursor.shape()); #endif } /* void tst_QGraphicsItem::textControlGetterSetter() { QGraphicsTextItem *item = new QGraphicsTextItem; QVERIFY(item->textControl()->parent() == item); QPointer control = item->textControl(); delete item; QVERIFY(!control); item = new QGraphicsTextItem; QPointer oldControl = control; control = new QTextControl; item->setTextControl(control); QVERIFY(item->textControl() == control); QVERIFY(!control->parent()); QVERIFY(!oldControl); // set some text to give it a size, to test that // setTextControl (re)connects signals const QRectF oldBoundingRect = item->boundingRect(); QVERIFY(oldBoundingRect.isValid()); item->setPlainText("Some text"); item->adjustSize(); QVERIFY(item->boundingRect().isValid()); QVERIFY(item->boundingRect() != oldBoundingRect); // test that on setting a control the item size // is adjusted oldControl = control; control = new QTextControl; control->setPlainText("foo!"); item->setTextControl(control); QCOMPARE(item->boundingRect().size(), control->document()->documentLayout()->documentSize()); QVERIFY(oldControl); delete oldControl; delete item; QVERIFY(control); delete control; } */ void tst_QGraphicsItem::defaultItemTest_QGraphicsLineItem() { QGraphicsLineItem item; QCOMPARE(item.line(), QLineF()); QCOMPARE(item.pen(), QPen()); QCOMPARE(item.shape(), QPainterPath()); item.setPen(QPen(Qt::black, 1)); QCOMPARE(item.pen(), QPen(Qt::black, 1)); item.setLine(QLineF(0, 0, 10, 0)); QCOMPARE(item.line(), QLineF(0, 0, 10, 0)); QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 11, 1)); QCOMPARE(item.shape().elementCount(), 11); QPainterPath path; path.moveTo(0, -0.5); path.lineTo(10, -0.5); path.lineTo(10.5, -0.5); path.lineTo(10.5, 0.5); path.lineTo(10, 0.5); path.lineTo(0, 0.5); path.lineTo(-0.5, 0.5); path.lineTo(-0.5, -0.5); path.lineTo(0, -0.5); path.lineTo(0, 0); path.lineTo(10, 0); path.closeSubpath(); for (int i = 0; i < 11; ++i) QCOMPARE(QPointF(item.shape().elementAt(i)), QPointF(path.elementAt(i))); } void tst_QGraphicsItem::defaultItemTest_QGraphicsPixmapItem() { QGraphicsPixmapItem item; QVERIFY(item.pixmap().isNull()); QCOMPARE(item.offset(), QPointF()); QCOMPARE(item.transformationMode(), Qt::FastTransformation); QPixmap pixmap(300, 200); pixmap.fill(Qt::red); item.setPixmap(pixmap); QCOMPARE(item.pixmap(), pixmap); item.setTransformationMode(Qt::FastTransformation); QCOMPARE(item.transformationMode(), Qt::FastTransformation); item.setTransformationMode(Qt::SmoothTransformation); QCOMPARE(item.transformationMode(), Qt::SmoothTransformation); item.setOffset(-15, -15); QCOMPARE(item.offset(), QPointF(-15, -15)); item.setOffset(QPointF(-10, -10)); QCOMPARE(item.offset(), QPointF(-10, -10)); QCOMPARE(item.boundingRect(), QRectF(-10, -10, 300, 200)); } void tst_QGraphicsItem::defaultItemTest_QGraphicsTextItem() { QGraphicsTextItem *text = new QGraphicsTextItem; QVERIFY(!text->openExternalLinks()); QVERIFY(text->textCursor().isNull()); QCOMPARE(text->defaultTextColor(), QPalette().color(QPalette::Text)); QVERIFY(text->document() != 0); QCOMPARE(text->font(), QApplication::font()); QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::NoTextInteraction)); QCOMPARE(text->textWidth(), -1.0); QCOMPARE(text->toPlainText(), QString("")); QGraphicsScene scene; scene.addItem(text); text->setPlainText("Hello world"); text->setFlag(QGraphicsItem::ItemIsMovable); { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(1, 1)); event.setButton(Qt::LeftButton); event.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event); QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove); event2.setScenePos(QPointF(11, 11)); event2.setButton(Qt::LeftButton); event2.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event2); } QCOMPARE(text->pos(), QPointF(10, 10)); text->setTextInteractionFlags(Qt::NoTextInteraction); QVERIFY(!(text->flags() & QGraphicsItem::ItemAcceptsInputMethod)); text->setTextInteractionFlags(Qt::TextEditorInteraction); QCOMPARE(text->textInteractionFlags(), Qt::TextInteractionFlags(Qt::TextEditorInteraction)); QVERIFY(text->flags() & QGraphicsItem::ItemAcceptsInputMethod); { QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove); event2.setScenePos(QPointF(21, 21)); event2.setButton(Qt::LeftButton); event2.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event2); } QCOMPARE(text->pos(), QPointF(20, 20)); // clicked on edge, item moved } void tst_QGraphicsItem::defaultItemTest_QGraphicsEllipseItem() { QGraphicsEllipseItem item; QVERIFY(item.rect().isNull()); QVERIFY(item.boundingRect().isNull()); QVERIFY(item.shape().isEmpty()); QCOMPARE(item.spanAngle(), 360 * 16); QCOMPARE(item.startAngle(), 0); item.setRect(0, 0, 100, 100); QCOMPARE(item.boundingRect(), QRectF(0, 0, 100, 100)); item.setSpanAngle(90 * 16); qFuzzyCompare(item.boundingRect().left(), qreal(50.0)); qFuzzyCompare(item.boundingRect().top(), qreal(0.0)); qFuzzyCompare(item.boundingRect().width(), qreal(50.0)); qFuzzyCompare(item.boundingRect().height(), qreal(50.0)); item.setPen(QPen(Qt::black, 1)); QCOMPARE(item.boundingRect(), QRectF(49.5, -0.5, 51, 51)); item.setSpanAngle(180 * 16); QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 51)); item.setSpanAngle(360 * 16); QCOMPARE(item.boundingRect(), QRectF(-0.5, -0.5, 101, 101)); } class ItemChangeTester : public QGraphicsRectItem { public: ItemChangeTester() { setFlag(ItemSendsGeometryChanges); clear(); } ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent) { setFlag(ItemSendsGeometryChanges); clear(); } void clear() { itemChangeReturnValue = QVariant(); itemSceneChangeTargetScene = 0; changes.clear(); values.clear(); oldValues.clear(); } QVariant itemChangeReturnValue; QGraphicsScene *itemSceneChangeTargetScene; QList changes; QList values; QList oldValues; protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value) { changes << change; values << value; switch (change) { case QGraphicsItem::ItemPositionChange: oldValues << pos(); break; case QGraphicsItem::ItemPositionHasChanged: break; case QGraphicsItem::ItemMatrixChange: { QVariant variant; qVariantSetValue(variant, matrix()); oldValues << variant; } break; case QGraphicsItem::ItemTransformChange: { QVariant variant; qVariantSetValue(variant, transform()); oldValues << variant; } break; case QGraphicsItem::ItemTransformHasChanged: break; case QGraphicsItem::ItemVisibleChange: oldValues << isVisible(); break; case QGraphicsItem::ItemVisibleHasChanged: break; case QGraphicsItem::ItemEnabledChange: oldValues << isEnabled(); break; case QGraphicsItem::ItemEnabledHasChanged: break; case QGraphicsItem::ItemSelectedChange: oldValues << isSelected(); break; case QGraphicsItem::ItemSelectedHasChanged: break; case QGraphicsItem::ItemParentChange: oldValues << qVariantFromValue(parentItem()); break; case QGraphicsItem::ItemParentHasChanged: break; case QGraphicsItem::ItemChildAddedChange: oldValues << children().size(); break; case QGraphicsItem::ItemChildRemovedChange: oldValues << children().size(); break; case QGraphicsItem::ItemSceneChange: oldValues << qVariantFromValue(scene()); if (itemSceneChangeTargetScene && qVariantValue(value) && itemSceneChangeTargetScene != qVariantValue(value)) { return qVariantFromValue(itemSceneChangeTargetScene); } return value; case QGraphicsItem::ItemSceneHasChanged: break; case QGraphicsItem::ItemCursorChange: #ifndef QT_NO_CURSOR oldValues << cursor(); #endif break; case QGraphicsItem::ItemCursorHasChanged: break; case QGraphicsItem::ItemToolTipChange: oldValues << toolTip(); break; case QGraphicsItem::ItemToolTipHasChanged: break; case QGraphicsItem::ItemFlagsChange: oldValues << quint32(flags()); break; case QGraphicsItem::ItemFlagsHaveChanged: break; case QGraphicsItem::ItemZValueChange: oldValues << zValue(); break; case QGraphicsItem::ItemZValueHasChanged: break; case QGraphicsItem::ItemOpacityChange: oldValues << opacity(); break; case QGraphicsItem::ItemOpacityHasChanged: break; case QGraphicsItem::ItemScenePositionHasChanged: break; case QGraphicsItem::ItemRotationChange: oldValues << rotation(); break; case QGraphicsItem::ItemRotationHasChanged: break; case QGraphicsItem::ItemScaleChange: oldValues << scale(); break; case QGraphicsItem::ItemScaleHasChanged: break; case QGraphicsItem::ItemTransformOriginPointChange: oldValues << transformOriginPoint(); break; case QGraphicsItem::ItemTransformOriginPointHasChanged: break; } return itemChangeReturnValue.isValid() ? itemChangeReturnValue : value; } }; void tst_QGraphicsItem::itemChange() { ItemChangeTester tester; tester.itemSceneChangeTargetScene = 0; ItemChangeTester testerHelper; QVERIFY(tester.changes.isEmpty()); QVERIFY(tester.values.isEmpty()); int changeCount = 0; { // ItemEnabledChange tester.itemChangeReturnValue = true; tester.setEnabled(false); ++changeCount; ++changeCount; // HasChanged QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemEnabledChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemEnabledHasChanged); QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false)); QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true)); QCOMPARE(tester.oldValues.last(), QVariant(true)); QCOMPARE(tester.isEnabled(), true); } { // ItemMatrixChange / ItemTransformHasChanged qVariantSetValue(tester.itemChangeReturnValue, QMatrix().rotate(90)); tester.setMatrix(QMatrix().translate(50, 0), true); ++changeCount; // notification sent too QCOMPARE(tester.changes.size(), ++changeCount); QCOMPARE(int(tester.changes.at(tester.changes.size() - 2)), int(QGraphicsItem::ItemMatrixChange)); QCOMPARE(int(tester.changes.last()), int(QGraphicsItem::ItemTransformHasChanged)); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 2)), QMatrix().translate(50, 0)); QCOMPARE(tester.values.last(), QVariant(QTransform(QMatrix().rotate(90)))); QVariant variant; qVariantSetValue(variant, QMatrix()); QCOMPARE(tester.oldValues.last(), variant); QCOMPARE(tester.matrix(), QMatrix().rotate(90)); } { tester.resetTransform(); ++changeCount; ++changeCount; // notification sent too // ItemTransformChange / ItemTransformHasChanged qVariantSetValue(tester.itemChangeReturnValue, QTransform().rotate(90)); tester.translate(50, 0); ++changeCount; // notification sent too ++changeCount; QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformHasChanged); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 2)), QTransform().translate(50, 0)); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 1)), QTransform().rotate(90)); QVariant variant; qVariantSetValue(variant, QTransform()); QCOMPARE(tester.oldValues.last(), variant); QCOMPARE(tester.transform(), QTransform().rotate(90)); } { // ItemPositionChange / ItemPositionHasChanged tester.itemChangeReturnValue = QPointF(42, 0); tester.setPos(0, 42); ++changeCount; // notification sent too ++changeCount; QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemPositionChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemPositionHasChanged); QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(0, 42))); QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(42, 0))); QCOMPARE(tester.oldValues.last(), QVariant(QPointF())); QCOMPARE(tester.pos(), QPointF(42, 0)); } { // ItemZValueChange / ItemZValueHasChanged tester.itemChangeReturnValue = qreal(2.0); tester.setZValue(1.0); ++changeCount; // notification sent too ++changeCount; QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemZValueChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemZValueHasChanged); QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.0))); QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0))); QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0))); QCOMPARE(tester.zValue(), qreal(2.0)); } { // ItemRotationChange / ItemRotationHasChanged tester.itemChangeReturnValue = qreal(15.0); tester.setRotation(10.0); ++changeCount; // notification sent too ++changeCount; QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemRotationChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemRotationHasChanged); QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(10.0))); QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(15.0))); QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0))); QCOMPARE(tester.rotation(), qreal(15.0)); } { // ItemScaleChange / ItemScaleHasChanged tester.itemChangeReturnValue = qreal(2.0); tester.setScale(1.5); ++changeCount; // notification sent too ++changeCount; QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemScaleChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemScaleHasChanged); QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.5))); QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0))); QCOMPARE(tester.oldValues.last(), QVariant(qreal(1.0))); QCOMPARE(tester.scale(), qreal(2.0)); } { // ItemTransformOriginPointChange / ItemTransformOriginPointHasChanged tester.itemChangeReturnValue = QPointF(2.0, 2.0); tester.setTransformOriginPoint(1.0, 1.0); ++changeCount; // notification sent too ++changeCount; QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemTransformOriginPointChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemTransformOriginPointHasChanged); QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(QPointF(1.0, 1.0))); QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(QPointF(2.0, 2.0))); QCOMPARE(tester.oldValues.last(), QVariant(QPointF(0.0, 0.0))); QCOMPARE(tester.transformOriginPoint(), QPointF(2.0, 2.0)); } { // ItemFlagsChange tester.itemChangeReturnValue = QGraphicsItem::ItemIsSelectable; tester.setFlag(QGraphicsItem::ItemIsSelectable, false); QCOMPARE(tester.changes.size(), changeCount); // No change tester.setFlag(QGraphicsItem::ItemIsSelectable, true); ++changeCount; ++changeCount; // ItemFlagsHasChanged QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemFlagsChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemFlagsHaveChanged); QVariant expectedFlags = qVariantFromValue(QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges)); QCOMPARE(tester.values.at(tester.values.size() - 2), expectedFlags); QCOMPARE(tester.values.at(tester.values.size() - 1), qVariantFromValue((quint32)QGraphicsItem::ItemIsSelectable)); } { // ItemSelectedChange tester.setSelected(false); QCOMPARE(tester.changes.size(), changeCount); // No change :-) tester.itemChangeReturnValue = true; tester.setSelected(true); ++changeCount; ++changeCount; // ItemSelectedHasChanged QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSelectedHasChanged); QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(true)); QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(true)); QCOMPARE(tester.oldValues.last(), QVariant(false)); QCOMPARE(tester.isSelected(), true); tester.itemChangeReturnValue = false; tester.setSelected(true); // the value hasn't changed to the itemChange return value // bacause itemChange is never called (true -> true is a noop). QCOMPARE(tester.isSelected(), true); } { // ItemVisibleChange tester.itemChangeReturnValue = false; QVERIFY(tester.isVisible()); tester.setVisible(false); ++changeCount; // ItemVisibleChange ++changeCount; // ItemSelectedChange ++changeCount; // ItemSelectedHasChanged ++changeCount; // ItemVisibleHasChanged QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemVisibleChange); QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSelectedChange); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSelectedHasChanged); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemVisibleHasChanged); QCOMPARE(tester.values.at(tester.values.size() - 4), QVariant(false)); QCOMPARE(tester.values.at(tester.values.size() - 3), QVariant(false)); QCOMPARE(tester.values.at(tester.values.size() - 2), QVariant(false)); QCOMPARE(tester.values.at(tester.values.size() - 1), QVariant(false)); QCOMPARE(tester.isVisible(), false); } { // ItemParentChange qVariantSetValue(tester.itemChangeReturnValue, 0); tester.setParentItem(&testerHelper); QCOMPARE(tester.changes.size(), ++changeCount); QCOMPARE(tester.changes.last(), QGraphicsItem::ItemParentChange); QCOMPARE(qVariantValue(tester.values.last()), (QGraphicsItem *)&testerHelper); QCOMPARE(qVariantValue(tester.oldValues.last()), (QGraphicsItem *)0); QCOMPARE(tester.parentItem(), (QGraphicsItem *)0); } { // ItemOpacityChange tester.itemChangeReturnValue = 1.0; tester.setOpacity(0.7); QCOMPARE(tester.changes.size(), ++changeCount); QCOMPARE(tester.changes.last(), QGraphicsItem::ItemOpacityChange); QVERIFY(qFuzzyCompare(qreal(tester.values.last().toDouble()), qreal(0.7))); QCOMPARE(tester.oldValues.last().toDouble(), double(1.0)); QCOMPARE(tester.opacity(), qreal(1.0)); tester.itemChangeReturnValue = 0.7; tester.setOpacity(0.7); ++changeCount; // ItemOpacityChange ++changeCount; // ItemOpacityHasChanged QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemOpacityChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemOpacityHasChanged); QCOMPARE(tester.opacity(), qreal(0.7)); } { // ItemChildAddedChange tester.itemChangeReturnValue.clear(); testerHelper.setParentItem(&tester); QCOMPARE(tester.changes.size(), ++changeCount); QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildAddedChange); QCOMPARE(qVariantValue(tester.values.last()), (QGraphicsItem *)&testerHelper); } { // ItemChildRemovedChange 1 testerHelper.setParentItem(0); QCOMPARE(tester.changes.size(), ++changeCount); QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildRemovedChange); QCOMPARE(qVariantValue(tester.values.last()), (QGraphicsItem *)&testerHelper); // ItemChildRemovedChange 1 ItemChangeTester *test = new ItemChangeTester; test->itemSceneChangeTargetScene = 0; int count = 0; QGraphicsScene *scene = new QGraphicsScene; scene->addItem(test); count = test->changes.size(); //We test here the fact that when a child is deleted the parent receive only one ItemChildRemovedChange QGraphicsRectItem *child = new QGraphicsRectItem(test); //We received ItemChildAddedChange QCOMPARE(test->changes.size(), ++count); QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildAddedChange); delete child; child = 0; QCOMPARE(test->changes.size(), ++count); QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange); ItemChangeTester *childTester = new ItemChangeTester(test); //Changes contains all sceneHasChanged and so on, we don't want to test that int childCount = childTester->changes.size(); //We received ItemChildAddedChange QCOMPARE(test->changes.size(), ++count); child = new QGraphicsRectItem(childTester); //We received ItemChildAddedChange QCOMPARE(childTester->changes.size(), ++childCount); QCOMPARE(childTester->changes.last(), QGraphicsItem::ItemChildAddedChange); //Delete the child of the top level with all its children delete childTester; //Only one removal QCOMPARE(test->changes.size(), ++count); QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange); delete scene; } { // ItemChildRemovedChange 2 ItemChangeTester parent; ItemChangeTester *child = new ItemChangeTester; child->setParentItem(&parent); QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildAddedChange); QCOMPARE(qVariantValue(parent.values.last()), (QGraphicsItem *)child); delete child; QCOMPARE(parent.changes.last(), QGraphicsItem::ItemChildRemovedChange); QCOMPARE(qVariantValue(parent.values.last()), (QGraphicsItem *)child); } { // !!! Note: If this test crashes because of double-deletion, there's // a bug somewhere in QGraphicsScene or QGraphicsItem. // ItemSceneChange QGraphicsScene scene; QGraphicsScene scene2; scene.addItem(&tester); ++changeCount; // ItemSceneChange (scene) ++changeCount; // ItemSceneHasChanged (scene) QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.scene(), &scene); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged); // Item's old value was 0 // Item's current value is scene QCOMPARE(qVariantValue(tester.oldValues.last()), (QGraphicsScene *)0); QCOMPARE(qVariantValue(tester.values.last()), (QGraphicsScene *)&scene); scene2.addItem(&tester); ++changeCount; // ItemSceneChange (0) was: (scene) ++changeCount; // ItemSceneHasChanged (0) ++changeCount; // ItemSceneChange (scene2) was: (0) ++changeCount; // ItemSceneHasChanged (scene2) QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.scene(), &scene2); QCOMPARE(tester.changes.at(tester.changes.size() - 4), QGraphicsItem::ItemSceneChange); QCOMPARE(tester.changes.at(tester.changes.size() - 3), QGraphicsItem::ItemSceneHasChanged); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged); // Item's last old value was scene // Item's last current value is 0 QCOMPARE(qVariantValue(tester.oldValues.at(tester.oldValues.size() - 2)), (QGraphicsScene *)&scene); QCOMPARE(qVariantValue(tester.oldValues.at(tester.oldValues.size() - 1)), (QGraphicsScene *)0); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 4)), (QGraphicsScene *)0); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)0); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene2); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene2); // Item's last old value was 0 // Item's last current value is scene2 QCOMPARE(qVariantValue(tester.oldValues.last()), (QGraphicsScene *)0); QCOMPARE(qVariantValue(tester.values.last()), (QGraphicsScene *)&scene2); scene2.removeItem(&tester); ++changeCount; // ItemSceneChange (0) was: (scene2) ++changeCount; // ItemSceneHasChanged (0) QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.scene(), (QGraphicsScene *)0); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemSceneChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemSceneHasChanged); // Item's last old value was scene2 // Item's last current value is 0 QCOMPARE(qVariantValue(tester.oldValues.last()), (QGraphicsScene *)&scene2); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)0); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)0); tester.itemSceneChangeTargetScene = &scene; scene2.addItem(&tester); ++changeCount; // ItemSceneChange (scene2) was: (0) ++changeCount; // ItemSceneChange (scene) was: (0) ++changeCount; // ItemSceneHasChanged (scene) QCOMPARE(tester.values.size(), changeCount); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 3)), (QGraphicsScene *)&scene2); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 2)), (QGraphicsScene *)&scene); QCOMPARE(qVariantValue(tester.values.at(tester.values.size() - 1)), (QGraphicsScene *)&scene); QCOMPARE(tester.scene(), &scene); tester.itemSceneChangeTargetScene = 0; tester.itemChangeReturnValue = QVariant(); scene.removeItem(&tester); ++changeCount; // ItemSceneChange ++changeCount; // ItemSceneHasChanged QCOMPARE(tester.scene(), (QGraphicsScene *)0); } { // ItemToolTipChange/ItemToolTipHasChanged const QString toolTip(QLatin1String("I'm soo cool")); const QString overridenToolTip(QLatin1String("No, you are not soo cool")); tester.itemChangeReturnValue = overridenToolTip; tester.setToolTip(toolTip); ++changeCount; // ItemToolTipChange ++changeCount; // ItemToolTipHasChanged QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(changeCount - 2), QGraphicsItem::ItemToolTipChange); QCOMPARE(tester.values.at(changeCount - 2).toString(), toolTip); QCOMPARE(tester.changes.at(changeCount - 1), QGraphicsItem::ItemToolTipHasChanged); QCOMPARE(tester.values.at(changeCount - 1).toString(), overridenToolTip); QCOMPARE(tester.toolTip(), overridenToolTip); tester.itemChangeReturnValue = QVariant(); } } class EventFilterTesterItem : public QGraphicsLineItem { public: QList filteredEvents; QList filteredEventReceivers; bool handlesSceneEvents; QList receivedEvents; EventFilterTesterItem() : handlesSceneEvents(false) {} protected: bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) { filteredEvents << event->type(); filteredEventReceivers << watched; return handlesSceneEvents; } bool sceneEvent(QEvent *event) { return QGraphicsLineItem::sceneEvent(event); } }; void tst_QGraphicsItem::sceneEventFilter() { QGraphicsScene scene; QGraphicsView view(&scene); view.show(); QApplication::setActiveWindow(&view); QTest::qWaitForWindowShown(&view); QTest::qWait(25); QGraphicsTextItem *text1 = scene.addText(QLatin1String("Text1")); QGraphicsTextItem *text2 = scene.addText(QLatin1String("Text2")); QGraphicsTextItem *text3 = scene.addText(QLatin1String("Text3")); text1->setFlag(QGraphicsItem::ItemIsFocusable); text2->setFlag(QGraphicsItem::ItemIsFocusable); text3->setFlag(QGraphicsItem::ItemIsFocusable); EventFilterTesterItem *tester = new EventFilterTesterItem; scene.addItem(tester); QTRY_VERIFY(!text1->hasFocus()); text1->installSceneEventFilter(tester); text1->setFocus(); QTRY_VERIFY(text1->hasFocus()); QCOMPARE(tester->filteredEvents.size(), 1); QCOMPARE(tester->filteredEvents.at(0), QEvent::FocusIn); QCOMPARE(tester->filteredEventReceivers.at(0), static_cast(text1)); text2->installSceneEventFilter(tester); text3->installSceneEventFilter(tester); text2->setFocus(); text3->setFocus(); QCOMPARE(tester->filteredEvents.size(), 5); QCOMPARE(tester->filteredEvents.at(1), QEvent::FocusOut); QCOMPARE(tester->filteredEventReceivers.at(1), static_cast(text1)); QCOMPARE(tester->filteredEvents.at(2), QEvent::FocusIn); QCOMPARE(tester->filteredEventReceivers.at(2), static_cast(text2)); QCOMPARE(tester->filteredEvents.at(3), QEvent::FocusOut); QCOMPARE(tester->filteredEventReceivers.at(3), static_cast(text2)); QCOMPARE(tester->filteredEvents.at(4), QEvent::FocusIn); QCOMPARE(tester->filteredEventReceivers.at(4), static_cast(text3)); text1->removeSceneEventFilter(tester); text1->setFocus(); QCOMPARE(tester->filteredEvents.size(), 6); QCOMPARE(tester->filteredEvents.at(5), QEvent::FocusOut); QCOMPARE(tester->filteredEventReceivers.at(5), static_cast(text3)); tester->handlesSceneEvents = true; text2->setFocus(); QCOMPARE(tester->filteredEvents.size(), 7); QCOMPARE(tester->filteredEvents.at(6), QEvent::FocusIn); QCOMPARE(tester->filteredEventReceivers.at(6), static_cast(text2)); QVERIFY(text2->hasFocus()); //Let check if the items are correctly removed from the sceneEventFilters array //to avoid stale pointers. QGraphicsView gv; QGraphicsScene *anotherScene = new QGraphicsScene; QGraphicsTextItem *ti = anotherScene->addText("This is a test #1"); ti->moveBy(50, 50); QGraphicsTextItem *ti2 = anotherScene->addText("This is a test #2"); QGraphicsTextItem *ti3 = anotherScene->addText("This is a test #3"); gv.setScene(anotherScene); gv.show(); QTest::qWaitForWindowShown(&gv); QTest::qWait(25); ti->installSceneEventFilter(ti2); ti3->installSceneEventFilter(ti); delete ti2; //we souldn't crash QTest::mouseMove(gv.viewport(), gv.mapFromScene(ti->scenePos())); QTest::qWait(30); delete ti; } class GeometryChanger : public QGraphicsItem { public: void changeGeometry() { prepareGeometryChange(); } }; void tst_QGraphicsItem::prepareGeometryChange() { { QGraphicsScene scene; QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100)); QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item)); ((GeometryChanger *)item)->changeGeometry(); QVERIFY(scene.items(QRectF(0, 0, 100, 100)).contains(item)); } } class PaintTester : public QGraphicsRectItem { public: PaintTester() : widget(NULL), painted(0) { setRect(QRectF(10, 10, 20, 20));} void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *w) { widget = w; painted++; } QWidget* widget; int painted; }; void tst_QGraphicsItem::paint() { QGraphicsScene scene; PaintTester paintTester; scene.addItem(&paintTester); QGraphicsView view(&scene); if(PlatformQuirks::isAutoMaximizing()) view.showFullScreen(); else view.show(); QTest::qWaitForWindowShown(&view); QApplication::processEvents(); #ifdef Q_OS_WIN32 //we try to switch the desktop: if it fails, we skip the test if (::SwitchDesktop( ::GetThreadDesktop( ::GetCurrentThreadId() ) ) == 0) { QSKIP("The Graphics View doesn't get the paint events", SkipSingle); } #endif QTRY_COMPARE(paintTester.widget, view.viewport()); view.hide(); QGraphicsScene scene2; QGraphicsView view2(&scene2); view2.show(); QTest::qWaitForWindowShown(&view2); QTest::qWait(25); PaintTester tester2; scene2.addItem(&tester2); qApp->processEvents(); //First show one paint QTRY_COMPARE(tester2.painted, 1); //nominal case, update call paint tester2.update(); qApp->processEvents(); QTRY_VERIFY(tester2.painted == 2); //we remove the item from the scene, number of updates is still the same tester2.update(); scene2.removeItem(&tester2); qApp->processEvents(); QTRY_VERIFY(tester2.painted == 2); //We re-add the item, the number of paint should increase scene2.addItem(&tester2); tester2.update(); qApp->processEvents(); QTRY_VERIFY(tester2.painted == 3); } class HarakiriItem : public QGraphicsRectItem { public: HarakiriItem(int harakiriPoint) : QGraphicsRectItem(QRectF(0, 0, 100, 100)), harakiri(harakiriPoint) { dead = 0; } static int dead; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QGraphicsRectItem::paint(painter, option, widget); if (harakiri == 0) { // delete unsupported since 4.5 /* dead = 1; delete this; */ } } void advance(int n) { if (harakiri == 1 && n == 0) { // delete unsupported /* dead = 1; delete this; */ } if (harakiri == 2 && n == 1) { dead = 1; delete this; } } protected: void contextMenuEvent(QGraphicsSceneContextMenuEvent *) { if (harakiri == 3) { dead = 1; delete this; } } void dragEnterEvent(QGraphicsSceneDragDropEvent *event) { // ?? QGraphicsRectItem::dragEnterEvent(event); } void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) { // ?? QGraphicsRectItem::dragLeaveEvent(event); } void dragMoveEvent(QGraphicsSceneDragDropEvent *event) { // ?? QGraphicsRectItem::dragMoveEvent(event); } void dropEvent(QGraphicsSceneDragDropEvent *event) { // ?? QGraphicsRectItem::dropEvent(event); } void focusInEvent(QFocusEvent *) { if (harakiri == 4) { dead = 1; delete this; } } void focusOutEvent(QFocusEvent *) { if (harakiri == 5) { dead = 1; delete this; } } void hoverEnterEvent(QGraphicsSceneHoverEvent *) { if (harakiri == 6) { dead = 1; delete this; } } void hoverLeaveEvent(QGraphicsSceneHoverEvent *) { if (harakiri == 7) { dead = 1; delete this; } } void hoverMoveEvent(QGraphicsSceneHoverEvent *) { if (harakiri == 8) { dead = 1; delete this; } } void inputMethodEvent(QInputMethodEvent *event) { // ?? QGraphicsRectItem::inputMethodEvent(event); } QVariant inputMethodQuery(Qt::InputMethodQuery query) const { // ?? return QGraphicsRectItem::inputMethodQuery(query); } QVariant itemChange(GraphicsItemChange change, const QVariant &value) { // deletion not supported return QGraphicsRectItem::itemChange(change, value); } void keyPressEvent(QKeyEvent *) { if (harakiri == 9) { dead = 1; delete this; } } void keyReleaseEvent(QKeyEvent *) { if (harakiri == 10) { dead = 1; delete this; } } void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { if (harakiri == 11) { dead = 1; delete this; } } void mouseMoveEvent(QGraphicsSceneMouseEvent *) { if (harakiri == 12) { dead = 1; delete this; } } void mousePressEvent(QGraphicsSceneMouseEvent *) { if (harakiri == 13) { dead = 1; delete this; } } void mouseReleaseEvent(QGraphicsSceneMouseEvent *) { if (harakiri == 14) { dead = 1; delete this; } } bool sceneEvent(QEvent *event) { // deletion not supported return QGraphicsRectItem::sceneEvent(event); } bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) { // deletion not supported return QGraphicsRectItem::sceneEventFilter(watched, event); } void wheelEvent(QGraphicsSceneWheelEvent *) { if (harakiri == 16) { dead = 1; delete this; } } private: int harakiri; }; int HarakiriItem::dead; void tst_QGraphicsItem::deleteItemInEventHandlers() { for (int i = 0; i < 17; ++i) { QGraphicsScene scene; HarakiriItem *item = new HarakiriItem(i); item->setAcceptsHoverEvents(true); item->setFlag(QGraphicsItem::ItemIsFocusable); scene.addItem(item); item->installSceneEventFilter(item); // <- ehey! QGraphicsView view(&scene); view.show(); qApp->processEvents(); qApp->processEvents(); if (!item->dead) scene.advance(); if (!item->dead) { QContextMenuEvent event(QContextMenuEvent::Other, view.mapFromScene(item->scenePos())); QCoreApplication::sendEvent(view.viewport(), &event); } if (!item->dead) QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos())); if (!item->dead) QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos())); if (!item->dead) QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(item->scenePos())); if (!item->dead) QTest::mouseClick(view.viewport(), Qt::RightButton, 0, view.mapFromScene(item->scenePos())); if (!item->dead) QTest::mouseMove(view.viewport(), view.mapFromScene(item->scenePos() + QPointF(20, -20))); if (!item->dead) item->setFocus(); if (!item->dead) item->clearFocus(); if (!item->dead) item->setFocus(); if (!item->dead) QTest::keyPress(view.viewport(), Qt::Key_A); if (!item->dead) QTest::keyRelease(view.viewport(), Qt::Key_A); if (!item->dead) QTest::keyPress(view.viewport(), Qt::Key_A); if (!item->dead) QTest::keyRelease(view.viewport(), Qt::Key_A); } } class ItemPaintsOutsideShape : public QGraphicsItem { public: QRectF boundingRect() const { return QRectF(0, 0, 100, 100); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->fillRect(-50, -50, 200, 200, Qt::red); painter->fillRect(0, 0, 100, 100, Qt::blue); } }; void tst_QGraphicsItem::itemClipsToShape() { QGraphicsItem *clippedItem = new ItemPaintsOutsideShape; clippedItem->setFlag(QGraphicsItem::ItemClipsToShape); QGraphicsItem *unclippedItem = new ItemPaintsOutsideShape; unclippedItem->setPos(200, 0); QGraphicsScene scene(-50, -50, 400, 200); scene.addItem(clippedItem); scene.addItem(unclippedItem); QImage image(400, 200, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); scene.render(&painter); painter.end(); QCOMPARE(image.pixel(45, 100), QRgb(0)); QCOMPARE(image.pixel(100, 45), QRgb(0)); QCOMPARE(image.pixel(155, 100), QRgb(0)); QCOMPARE(image.pixel(45, 155), QRgb(0)); QCOMPARE(image.pixel(55, 100), QColor(Qt::blue).rgba()); QCOMPARE(image.pixel(100, 55), QColor(Qt::blue).rgba()); QCOMPARE(image.pixel(145, 100), QColor(Qt::blue).rgba()); QCOMPARE(image.pixel(55, 145), QColor(Qt::blue).rgba()); QCOMPARE(image.pixel(245, 100), QColor(Qt::red).rgba()); QCOMPARE(image.pixel(300, 45), QColor(Qt::red).rgba()); QCOMPARE(image.pixel(355, 100), QColor(Qt::red).rgba()); QCOMPARE(image.pixel(245, 155), QColor(Qt::red).rgba()); QCOMPARE(image.pixel(255, 100), QColor(Qt::blue).rgba()); QCOMPARE(image.pixel(300, 55), QColor(Qt::blue).rgba()); QCOMPARE(image.pixel(345, 100), QColor(Qt::blue).rgba()); QCOMPARE(image.pixel(255, 145), QColor(Qt::blue).rgba()); } void tst_QGraphicsItem::itemClipsChildrenToShape() { QGraphicsScene scene; QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::yellow)); QGraphicsItem *ellipse = scene.addEllipse(0, 0, 100, 100, QPen(Qt::NoPen), QBrush(Qt::green)); ellipse->setParentItem(rect); QGraphicsItem *clippedEllipse = scene.addEllipse(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::blue)); clippedEllipse->setParentItem(ellipse); QGraphicsItem *clippedEllipse2 = scene.addEllipse(0, 0, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red)); clippedEllipse2->setParentItem(clippedEllipse); QGraphicsItem *clippedEllipse3 = scene.addEllipse(50, 50, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red)); clippedEllipse3->setParentItem(clippedEllipse); QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape)); ellipse->setFlag(QGraphicsItem::ItemClipsChildrenToShape); QVERIFY((ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape)); QImage image(100, 100, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); scene.render(&painter); painter.end(); QCOMPARE(image.pixel(16, 16), QColor(255, 0, 0).rgba()); QCOMPARE(image.pixel(32, 32), QColor(0, 0, 255).rgba()); QCOMPARE(image.pixel(50, 50), QColor(0, 255, 0).rgba()); QCOMPARE(image.pixel(12, 12), QColor(255, 255, 0).rgba()); QCOMPARE(image.pixel(60, 60), QColor(255, 0, 0).rgba()); } void tst_QGraphicsItem::itemClipsChildrenToShape2() { QGraphicsRectItem *parent = new QGraphicsRectItem(QRectF(0, 0, 10, 10)); QGraphicsEllipseItem *child1 = new QGraphicsEllipseItem(QRectF(50, 50, 100, 100)); QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(15, 15, 80, 80)); child1->setParentItem(parent); child1->setFlag(QGraphicsItem::ItemClipsChildrenToShape); child2->setParentItem(child1); parent->setBrush(Qt::blue); child1->setBrush(Qt::green); child2->setBrush(Qt::red); QGraphicsScene scene; scene.addItem(parent); QCOMPARE(scene.itemAt(5, 5), (QGraphicsItem *)parent); QCOMPARE(scene.itemAt(15, 5), (QGraphicsItem *)0); QCOMPARE(scene.itemAt(5, 15), (QGraphicsItem *)0); QCOMPARE(scene.itemAt(60, 60), (QGraphicsItem *)0); QCOMPARE(scene.itemAt(140, 60), (QGraphicsItem *)0); QCOMPARE(scene.itemAt(60, 140), (QGraphicsItem *)0); QCOMPARE(scene.itemAt(140, 140), (QGraphicsItem *)0); QCOMPARE(scene.itemAt(75, 75), (QGraphicsItem *)child2); QCOMPARE(scene.itemAt(75, 100), (QGraphicsItem *)child1); QCOMPARE(scene.itemAt(100, 75), (QGraphicsItem *)child1); #if 1 QImage image(100, 100, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter painter(&image); scene.render(&painter); painter.end(); QCOMPARE(image.pixel(5, 5), QColor(0, 0, 255).rgba()); QCOMPARE(image.pixel(5, 10), QRgb(0)); QCOMPARE(image.pixel(10, 5), QRgb(0)); QCOMPARE(image.pixel(40, 40), QRgb(0)); QCOMPARE(image.pixel(90, 40), QRgb(0)); QCOMPARE(image.pixel(40, 90), QRgb(0)); QCOMPARE(image.pixel(95, 95), QRgb(0)); QCOMPARE(image.pixel(50, 70), QColor(0, 255, 0).rgba()); QCOMPARE(image.pixel(70, 50), QColor(0, 255, 0).rgba()); QCOMPARE(image.pixel(50, 60), QColor(255, 0, 0).rgba()); QCOMPARE(image.pixel(60, 50), QColor(255, 0, 0).rgba()); #else QGraphicsView view(&scene); view.show(); QTest::qWait(5000); #endif } void tst_QGraphicsItem::itemClipsChildrenToShape3() { // Construct a scene with nested children, each 50 pixels offset from the elder. // Set a top-level clipping flag QGraphicsScene scene; QGraphicsRectItem *parent = scene.addRect( 0, 0, 150, 150 ); QGraphicsRectItem *child = scene.addRect( 0, 0, 150, 150 ); QGraphicsRectItem *grandchild = scene.addRect( 0, 0, 150, 150 ); child->setParentItem(parent); grandchild->setParentItem(child); child->setPos( 50, 50 ); grandchild->setPos( 50, 50 ); parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape); QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)parent); QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)child); QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild); QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0); // Move child to fully overlap the parent. The grandchild should // now occupy two-thirds of the scene child->prepareGeometryChange(); child->setPos( 0, 0 ); QCOMPARE(scene.itemAt(25,25), (QGraphicsItem *)child); QCOMPARE(scene.itemAt(75,75), (QGraphicsItem *)grandchild); QCOMPARE(scene.itemAt(125,125), (QGraphicsItem *)grandchild); QCOMPARE(scene.itemAt(175,175), (QGraphicsItem *)0); } class MyProxyWidget : public QGraphicsProxyWidget { public: MyProxyWidget(QGraphicsItem *parent) : QGraphicsProxyWidget(parent) { painted = false; } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QGraphicsProxyWidget::paint(painter, option, widget); painted = true; } bool painted; }; void tst_QGraphicsItem::itemClipsChildrenToShape4() { QGraphicsScene scene; QGraphicsView view(&scene); QGraphicsWidget * outerWidget = new QGraphicsWidget(); outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); MyProxyWidget * innerWidget = new MyProxyWidget(outerWidget); QLabel * label = new QLabel(); label->setText("Welcome back my friends to the show that never ends..."); innerWidget->setWidget(label); view.resize(300, 300); scene.addItem(outerWidget); outerWidget->resize( 200, 100 ); scene.addEllipse( 100, 100, 100, 50 ); // <-- this is important to trigger the right codepath* //now the label is shown outerWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false ); QApplication::setActiveWindow(&view); view.show(); QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view); QTRY_COMPARE(innerWidget->painted, true); } //#define DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5 static inline void renderSceneToImage(QGraphicsScene *scene, QImage *image, const QString &filename) { image->fill(0); QPainter painter(image); scene->render(&painter); painter.end(); #ifdef DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5 image->save(filename); #else Q_UNUSED(filename); #endif } void tst_QGraphicsItem::itemClipsChildrenToShape5() { class ParentItem : public QGraphicsRectItem { public: ParentItem(qreal x, qreal y, qreal width, qreal height) : QGraphicsRectItem(x, y, width, height) {} QPainterPath shape() const { QPainterPath path; path.addRect(50, 50, 200, 200); return path; } }; ParentItem *parent = new ParentItem(0, 0, 300, 300); parent->setBrush(Qt::blue); parent->setOpacity(0.5); const QRegion parentRegion(0, 0, 300, 300); const QRegion clippedParentRegion = parentRegion & QRect(50, 50, 200, 200); QRegion childRegion; QRegion grandChildRegion; QGraphicsRectItem *topLeftChild = new QGraphicsRectItem(0, 0, 100, 100); topLeftChild->setBrush(Qt::red); topLeftChild->setParentItem(parent); childRegion += QRect(0, 0, 100, 100); QGraphicsRectItem *topRightChild = new QGraphicsRectItem(0, 0, 100, 100); topRightChild->setBrush(Qt::red); topRightChild->setParentItem(parent); topRightChild->setFlag(QGraphicsItem::ItemClipsChildrenToShape); topRightChild->setPos(200, 0); childRegion += QRect(200, 0, 100, 100); QGraphicsRectItem *topRightGrandChild = new QGraphicsRectItem(0, 0, 100, 100); topRightGrandChild->setBrush(Qt::green); topRightGrandChild->setParentItem(topRightChild); topRightGrandChild->setPos(-40, 40); grandChildRegion += QRect(200 - 40, 0 + 40, 100, 100) & QRect(200, 0, 100, 100); QGraphicsRectItem *bottomLeftChild = new QGraphicsRectItem(0, 0, 100, 100); bottomLeftChild->setBrush(Qt::red); bottomLeftChild->setParentItem(parent); bottomLeftChild->setFlag(QGraphicsItem::ItemClipsToShape); bottomLeftChild->setPos(0, 200); childRegion += QRect(0, 200, 100, 100); QGraphicsRectItem *bottomLeftGrandChild = new QGraphicsRectItem(0, 0, 160, 160); bottomLeftGrandChild->setBrush(Qt::green); bottomLeftGrandChild->setParentItem(bottomLeftChild); bottomLeftGrandChild->setFlag(QGraphicsItem::ItemClipsToShape); bottomLeftGrandChild->setPos(0, -60); grandChildRegion += QRect(0, 200 - 60, 160, 160); QGraphicsRectItem *bottomRightChild = new QGraphicsRectItem(0, 0, 100, 100); bottomRightChild->setBrush(Qt::red); bottomRightChild->setParentItem(parent); bottomRightChild->setPos(200, 200); childRegion += QRect(200, 200, 100, 100); QPoint controlPoints[17] = { QPoint(5, 5) , QPoint(95, 5) , QPoint(205, 5) , QPoint(295, 5) , QPoint(5, 95) , QPoint(95, 95) , QPoint(205, 95) , QPoint(295, 95) , QPoint(150, 150), QPoint(5, 205), QPoint(95, 205), QPoint(205, 205), QPoint(295, 205), QPoint(5, 295), QPoint(95, 295), QPoint(205, 295), QPoint(295, 295), }; const QRegion clippedChildRegion = childRegion & QRect(50, 50, 200, 200); const QRegion clippedGrandChildRegion = grandChildRegion & QRect(50, 50, 200, 200); QGraphicsScene scene; scene.addItem(parent); QImage sceneImage(300, 300, QImage::Format_ARGB32); #define VERIFY_CONTROL_POINTS(pRegion, cRegion, gRegion) \ for (int i = 0; i < 17; ++i) { \ QPoint controlPoint = controlPoints[i]; \ QRgb pixel = sceneImage.pixel(controlPoint.x(), controlPoint.y()); \ if (pRegion.contains(controlPoint)) \ QVERIFY(qBlue(pixel) != 0); \ else \ QVERIFY(qBlue(pixel) == 0); \ if (cRegion.contains(controlPoint)) \ QVERIFY(qRed(pixel) != 0); \ else \ QVERIFY(qRed(pixel) == 0); \ if (gRegion.contains(controlPoint)) \ QVERIFY(qGreen(pixel) != 0); \ else \ QVERIFY(qGreen(pixel) == 0); \ } const QList children = parent->childItems(); const int childrenCount = children.count(); for (int i = 0; i < 5; ++i) { QString clipString; QString childString; switch (i) { case 0: // All children stacked in front. childString = QLatin1String("ChildrenInFront.png"); foreach (QGraphicsItem *child, children) child->setFlag(QGraphicsItem::ItemStacksBehindParent, false); break; case 1: // All children stacked behind. childString = QLatin1String("ChildrenBehind.png"); foreach (QGraphicsItem *child, children) child->setFlag(QGraphicsItem::ItemStacksBehindParent, true); break; case 2: // First half of the children behind, second half in front. childString = QLatin1String("FirstHalfBehind_SecondHalfInFront.png"); for (int j = 0; j < childrenCount; ++j) { QGraphicsItem *child = children.at(j); child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j < childrenCount / 2)); } break; case 3: // First half of the children in front, second half behind. childString = QLatin1String("FirstHalfInFront_SecondHalfBehind.png"); for (int j = 0; j < childrenCount; ++j) { QGraphicsItem *child = children.at(j); child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j >= childrenCount / 2)); } break; case 4: // Child2 and child4 behind, rest in front. childString = QLatin1String("Child2And4Behind_RestInFront.png"); for (int j = 0; j < childrenCount; ++j) { QGraphicsItem *child = children.at(j); if (j == 1 || j == 3) child->setFlag(QGraphicsItem::ItemStacksBehindParent, true); else child->setFlag(QGraphicsItem::ItemStacksBehindParent, false); } break; default: qFatal("internal error"); } // Nothing is clipped. parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false); parent->setFlag(QGraphicsItem::ItemClipsToShape, false); clipString = QLatin1String("nothingClipped_"); renderSceneToImage(&scene, &sceneImage, clipString + childString); VERIFY_CONTROL_POINTS(parentRegion, childRegion, grandChildRegion); // Parent clips children to shape. parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape); clipString = QLatin1String("parentClipsChildrenToShape_"); renderSceneToImage(&scene, &sceneImage, clipString + childString); VERIFY_CONTROL_POINTS(parentRegion, clippedChildRegion, clippedGrandChildRegion); // Parent clips itself and children to shape. parent->setFlag(QGraphicsItem::ItemClipsToShape); clipString = QLatin1String("parentClipsItselfAndChildrenToShape_"); renderSceneToImage(&scene, &sceneImage, clipString + childString); VERIFY_CONTROL_POINTS(clippedParentRegion, clippedChildRegion, clippedGrandChildRegion); // Parent clips itself to shape. parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false); clipString = QLatin1String("parentClipsItselfToShape_"); renderSceneToImage(&scene, &sceneImage, clipString + childString); VERIFY_CONTROL_POINTS(clippedParentRegion, childRegion, grandChildRegion); } } void tst_QGraphicsItem::itemClipsTextChildToShape() { // Construct a scene with a rect that clips its children, with one text // child that has text that exceeds the size of the rect. QGraphicsScene scene; QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::black), Qt::black); rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape); QGraphicsTextItem *text = new QGraphicsTextItem("This is a long sentence that's wider than 50 pixels."); text->setParentItem(rect); // Render this scene to a transparent image. QRectF sr = scene.itemsBoundingRect(); QImage image(sr.size().toSize(), QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter painter(&image); scene.render(&painter); // Erase the area immediately underneath the rect. painter.setCompositionMode(QPainter::CompositionMode_Source); painter.fillRect(rect->sceneBoundingRect().translated(-sr.topLeft()).adjusted(-0.5, -0.5, 0.5, 0.5), Qt::transparent); painter.end(); // Check that you get a truly transparent image back (i.e., the text was // clipped away, so there should be no trails left after erasing only the // rect's area). QImage emptyImage(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied); emptyImage.fill(0); QCOMPARE(image, emptyImage); } void tst_QGraphicsItem::itemClippingDiscovery() { // A simple scene with an ellipse parent and two rect children, one a // child of the other. QGraphicsScene scene; QGraphicsEllipseItem *clipItem = scene.addEllipse(0, 0, 100, 100); QGraphicsRectItem *leftRectItem = scene.addRect(0, 0, 50, 100); QGraphicsRectItem *rightRectItem = scene.addRect(50, 0, 50, 100); leftRectItem->setParentItem(clipItem); rightRectItem->setParentItem(clipItem); // The rects item are both visible at these points. QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)leftRectItem); QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)rightRectItem); // The ellipse clips the rects now. clipItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape); // The rect items are no longer visible at these points. QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0); if (sizeof(qreal) != sizeof(double)) QSKIP("This fails due to internal rounding errors", SkipSingle); QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)0); } void tst_QGraphicsItem::ancestorFlags() { QGraphicsItem *level1 = new QGraphicsRectItem; QGraphicsItem *level21 = new QGraphicsRectItem; level21->setParentItem(level1); QGraphicsItem *level22 = new QGraphicsRectItem; level22->setParentItem(level1); QGraphicsItem *level31 = new QGraphicsRectItem; level31->setParentItem(level21); QGraphicsItem *level32 = new QGraphicsRectItem; level32->setParentItem(level21); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 0); QCOMPARE(int(level32->d_ptr->ancestorFlags), 0); // HandlesChildEvents: 1) Root level sets a flag level1->setHandlesChildEvents(true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 1); QCOMPARE(int(level22->d_ptr->ancestorFlags), 1); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // HandlesChildEvents: 2) Root level set it again level1->setHandlesChildEvents(true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 1); QCOMPARE(int(level22->d_ptr->ancestorFlags), 1); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // HandlesChildEvents: 3) Root level unsets a flag level1->setHandlesChildEvents(false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 0); QCOMPARE(int(level32->d_ptr->ancestorFlags), 0); // HandlesChildEvents: 4) Child item sets a flag level21->setHandlesChildEvents(true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // HandlesChildEvents: 5) Parent item sets a flag level1->setHandlesChildEvents(true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 1); QCOMPARE(int(level22->d_ptr->ancestorFlags), 1); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // HandlesChildEvents: 6) Child item unsets a flag level21->setHandlesChildEvents(false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 1); QCOMPARE(int(level22->d_ptr->ancestorFlags), 1); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // HandlesChildEvents: 7) Parent item unsets a flag level21->setHandlesChildEvents(true); level1->setHandlesChildEvents(false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // Reparent the child to root level21->setParentItem(0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // Reparent the child to level1 again. level1->setHandlesChildEvents(true); level21->setParentItem(level1); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 1); QCOMPARE(int(level22->d_ptr->ancestorFlags), 1); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // Reparenting level31 back to level1. level31->setParentItem(level1); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 1); QCOMPARE(int(level22->d_ptr->ancestorFlags), 1); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // Reparenting level31 back to level21. level31->setParentItem(0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 0); level31->setParentItem(level21); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 1); QCOMPARE(int(level22->d_ptr->ancestorFlags), 1); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // Level1 doesn't handle child events level1->setHandlesChildEvents(false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 1); QCOMPARE(int(level32->d_ptr->ancestorFlags), 1); // Nobody handles child events level21->setHandlesChildEvents(false); for (int i = 0; i < 2; ++i) { QGraphicsItem::GraphicsItemFlag flag = !i ? QGraphicsItem::ItemClipsChildrenToShape : QGraphicsItem::ItemIgnoresTransformations; int ancestorFlag = !i ? QGraphicsItemPrivate::AncestorClipsChildren : QGraphicsItemPrivate::AncestorIgnoresTransformations; QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 0); QCOMPARE(int(level32->d_ptr->ancestorFlags), 0); // HandlesChildEvents: 1) Root level sets a flag level1->setFlag(flag, true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // HandlesChildEvents: 2) Root level set it again level1->setFlag(flag, true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // HandlesChildEvents: 3) Root level unsets a flag level1->setFlag(flag, false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 0); QCOMPARE(int(level32->d_ptr->ancestorFlags), 0); // HandlesChildEvents: 4) Child item sets a flag level21->setFlag(flag, true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // HandlesChildEvents: 5) Parent item sets a flag level1->setFlag(flag, true); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // HandlesChildEvents: 6) Child item unsets a flag level21->setFlag(flag, false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // HandlesChildEvents: 7) Parent item unsets a flag level21->setFlag(flag, true); level1->setFlag(flag, false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // Reparent the child to root level21->setParentItem(0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // Reparent the child to level1 again. level1->setFlag(flag, true); level21->setParentItem(level1); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // Reparenting level31 back to level1. level31->setParentItem(level1); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // Reparenting level31 back to level21. level31->setParentItem(0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 0); level31->setParentItem(level21); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level22->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // Level1 doesn't handle child events level1->setFlag(flag, false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), ancestorFlag); QCOMPARE(int(level32->d_ptr->ancestorFlags), ancestorFlag); // Nobody handles child events level21->setFlag(flag, false); QCOMPARE(int(level1->d_ptr->ancestorFlags), 0); QCOMPARE(int(level21->d_ptr->ancestorFlags), 0); QCOMPARE(int(level22->d_ptr->ancestorFlags), 0); QCOMPARE(int(level31->d_ptr->ancestorFlags), 0); QCOMPARE(int(level32->d_ptr->ancestorFlags), 0); } delete level1; } void tst_QGraphicsItem::untransformable() { QGraphicsItem *item1 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100)); item1->setZValue(1); item1->setFlag(QGraphicsItem::ItemIgnoresTransformations); item1->rotate(45); ((QGraphicsEllipseItem *)item1)->setBrush(Qt::red); QGraphicsItem *item2 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100)); item2->setParentItem(item1); item2->rotate(45); item2->setPos(100, 0); ((QGraphicsEllipseItem *)item2)->setBrush(Qt::green); QGraphicsItem *item3 = new QGraphicsEllipseItem(QRectF(-50, -50, 100, 100)); item3->setParentItem(item2); item3->setPos(100, 0); ((QGraphicsEllipseItem *)item3)->setBrush(Qt::blue); QGraphicsScene scene(-500, -500, 1000, 1000); scene.addItem(item1); QWidget topLevel; QGraphicsView view(&scene,&topLevel); view.resize(300, 300); topLevel.show(); view.scale(8, 8); view.centerOn(0, 0); // Painting with the DiagCrossPattern is really slow on Mac // when zoomed out. (The test times out). Task to fix is 155567. #if !defined(Q_WS_MAC) || 1 view.setBackgroundBrush(QBrush(Qt::black, Qt::DiagCrossPattern)); #endif QTest::qWaitForWindowShown(&view); for (int i = 0; i < 10; ++i) { QPoint center = view.viewport()->rect().center(); QCOMPARE(view.itemAt(center), item1); QCOMPARE(view.itemAt(center - QPoint(40, 0)), item1); QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item1); QCOMPARE(view.itemAt(center - QPoint(0, 40)), item1); QCOMPARE(view.itemAt(center - QPoint(0, -40)), item1); center += QPoint(70, 70); QCOMPARE(view.itemAt(center - QPoint(40, 0)), item2); QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item2); QCOMPARE(view.itemAt(center - QPoint(0, 40)), item2); QCOMPARE(view.itemAt(center - QPoint(0, -40)), item2); center += QPoint(0, 100); QCOMPARE(view.itemAt(center - QPoint(40, 0)), item3); QCOMPARE(view.itemAt(center - QPoint(-40, 0)), item3); QCOMPARE(view.itemAt(center - QPoint(0, 40)), item3); QCOMPARE(view.itemAt(center - QPoint(0, -40)), item3); view.scale(0.5, 0.5); view.rotate(13); view.shear(qreal(0.01), qreal(0.01)); view.translate(10, 10); QTest::qWait(25); } } class ContextMenuItem : public QGraphicsRectItem { public: ContextMenuItem() : ignoreEvent(true), gotEvent(false), eventWasAccepted(false) { } bool ignoreEvent; bool gotEvent; bool eventWasAccepted; protected: void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { gotEvent = true; eventWasAccepted = event->isAccepted(); if (ignoreEvent) event->ignore(); } }; void tst_QGraphicsItem::contextMenuEventPropagation() { ContextMenuItem *bottomItem = new ContextMenuItem; bottomItem->setRect(0, 0, 100, 100); ContextMenuItem *topItem = new ContextMenuItem; topItem->setParentItem(bottomItem); topItem->setRect(0, 0, 100, 100); QGraphicsScene scene; QGraphicsView view(&scene); view.setAlignment(Qt::AlignLeft | Qt::AlignTop); view.show(); view.resize(200, 200); QTest::qWaitForWindowShown(&view); QTest::qWait(20); QContextMenuEvent event(QContextMenuEvent::Mouse, QPoint(10, 10), view.viewport()->mapToGlobal(QPoint(10, 10))); event.ignore(); QApplication::sendEvent(view.viewport(), &event); QVERIFY(!event.isAccepted()); scene.addItem(bottomItem); topItem->ignoreEvent = true; bottomItem->ignoreEvent = true; QApplication::sendEvent(view.viewport(), &event); QVERIFY(!event.isAccepted()); QCOMPARE(topItem->gotEvent, true); QCOMPARE(topItem->eventWasAccepted, true); QCOMPARE(bottomItem->gotEvent, true); QCOMPARE(bottomItem->eventWasAccepted, true); topItem->ignoreEvent = false; topItem->gotEvent = false; bottomItem->gotEvent = false; QApplication::sendEvent(view.viewport(), &event); QVERIFY(event.isAccepted()); QCOMPARE(topItem->gotEvent, true); QCOMPARE(bottomItem->gotEvent, false); QCOMPARE(topItem->eventWasAccepted, true); } void tst_QGraphicsItem::itemIsMovable() { QGraphicsRectItem *rect = new QGraphicsRectItem(-50, -50, 100, 100); rect->setFlag(QGraphicsItem::ItemIsMovable); QGraphicsScene scene; scene.addItem(rect); { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setButton(Qt::LeftButton); event.setButtons(Qt::LeftButton); qApp->sendEvent(&scene, &event); } { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove); event.setButton(Qt::LeftButton); event.setButtons(Qt::LeftButton); qApp->sendEvent(&scene, &event); } QCOMPARE(rect->pos(), QPointF(0, 0)); { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove); event.setButtons(Qt::LeftButton); event.setScenePos(QPointF(10, 10)); qApp->sendEvent(&scene, &event); } QCOMPARE(rect->pos(), QPointF(10, 10)); { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove); event.setButtons(Qt::RightButton); event.setScenePos(QPointF(20, 20)); qApp->sendEvent(&scene, &event); } QCOMPARE(rect->pos(), QPointF(10, 10)); { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseMove); event.setButtons(Qt::LeftButton); event.setScenePos(QPointF(30, 30)); qApp->sendEvent(&scene, &event); } QCOMPARE(rect->pos(), QPointF(30, 30)); } class ItemAddScene : public QGraphicsScene { Q_OBJECT public: ItemAddScene() { QTimer::singleShot(500, this, SLOT(newTextItem())); } public slots: void newTextItem() { // Add a text item QGraphicsItem *item = new QGraphicsTextItem("This item will not ensure that it's visible", 0, this); item->setPos(.0, .0); item->show(); } }; void tst_QGraphicsItem::task141694_textItemEnsureVisible() { ItemAddScene scene; scene.setSceneRect(-1000, -1000, 2000, 2000); QGraphicsView view(&scene); view.setFixedSize(200, 200); view.show(); QTest::qWaitForWindowShown(&view); view.ensureVisible(-1000, -1000, 5, 5); int hscroll = view.horizontalScrollBar()->value(); int vscroll = view.verticalScrollBar()->value(); QTest::qWait(10); // This should not cause the view to scroll QTRY_COMPARE(view.horizontalScrollBar()->value(), hscroll); QCOMPARE(view.verticalScrollBar()->value(), vscroll); } void tst_QGraphicsItem::task128696_textItemEnsureMovable() { QGraphicsTextItem *item = new QGraphicsTextItem; item->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); item->setTextInteractionFlags(Qt::TextEditorInteraction); item->setPlainText("abc de\nf ghi\n j k l"); QGraphicsScene scene; scene.setSceneRect(-100, -100, 200, 200); scene.addItem(item); QGraphicsView view(&scene); view.setFixedSize(200, 200); view.show(); QGraphicsSceneMouseEvent event1(QEvent::GraphicsSceneMousePress); event1.setScenePos(QPointF(0, 0)); event1.setButton(Qt::LeftButton); event1.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item); QGraphicsSceneMouseEvent event2(QEvent::GraphicsSceneMouseMove); event2.setScenePos(QPointF(10, 10)); event2.setButton(Qt::LeftButton); event2.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event2); QCOMPARE(item->pos(), QPointF(10, 10)); } void tst_QGraphicsItem::task177918_lineItemUndetected() { QGraphicsScene scene; QGraphicsLineItem *line = scene.addLine(10, 10, 10, 10); QCOMPARE(line->boundingRect(), QRectF(10, 10, 0, 0)); QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemShape).isEmpty()); QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemShape).isEmpty()); QVERIFY(!scene.items(9, 9, 2, 2, Qt::IntersectsItemBoundingRect).isEmpty()); QVERIFY(!scene.items(9, 9, 2, 2, Qt::ContainsItemBoundingRect).isEmpty()); } void tst_QGraphicsItem::task240400_clickOnTextItem_data() { QTest::addColumn("flags"); QTest::addColumn("textFlags"); QTest::newRow("editor, noflags") << 0 << int(Qt::TextEditorInteraction); QTest::newRow("editor, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::TextEditorInteraction); QTest::newRow("editor, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::TextEditorInteraction); QTest::newRow("editor, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable) << int(Qt::TextEditorInteraction); QTest::newRow("noninteractive, noflags") << 0 << int(Qt::NoTextInteraction); QTest::newRow("noninteractive, movable") << int(QGraphicsItem::ItemIsMovable) << int(Qt::NoTextInteraction); QTest::newRow("noninteractive, selectable") << int(QGraphicsItem::ItemIsSelectable) << int(Qt::NoTextInteraction); QTest::newRow("noninteractive, movable | selectable") << int(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable) << int(Qt::NoTextInteraction); } void tst_QGraphicsItem::task240400_clickOnTextItem() { QFETCH(int, flags); QFETCH(int, textFlags); QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); QGraphicsTextItem *item = scene.addText("Hello"); item->setFlags(QGraphicsItem::GraphicsItemFlags(flags)); item->setTextInteractionFlags(Qt::TextInteractionFlags(textFlags)); bool focusable = (item->flags() & QGraphicsItem::ItemIsFocusable); QVERIFY(textFlags ? focusable : !focusable); int column = item->textCursor().columnNumber(); QCOMPARE(column, 0); QVERIFY(!item->hasFocus()); // Click in the top-left corner of the item { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1)); event.setButton(Qt::LeftButton); event.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event); } if (flags || textFlags) QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item); else QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(item->sceneBoundingRect().topLeft() + QPointF(0.1, 0.1)); event.setButton(Qt::LeftButton); event.setButtons(0); QApplication::sendEvent(&scene, &event); } if (textFlags) QVERIFY(item->hasFocus()); else QVERIFY(!item->hasFocus()); QVERIFY(!scene.mouseGrabberItem()); bool selectable = (flags & QGraphicsItem::ItemIsSelectable); QVERIFY(selectable ? item->isSelected() : !item->isSelected()); // Now click in the middle and check that the cursor moved. { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(item->sceneBoundingRect().center()); event.setButton(Qt::LeftButton); event.setButtons(Qt::LeftButton); QApplication::sendEvent(&scene, &event); } if (flags || textFlags) QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item); else QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(item->sceneBoundingRect().center()); event.setButton(Qt::LeftButton); event.setButtons(0); QApplication::sendEvent(&scene, &event); } if (textFlags) QVERIFY(item->hasFocus()); else QVERIFY(!item->hasFocus()); QVERIFY(!scene.mouseGrabberItem()); QVERIFY(selectable ? item->isSelected() : !item->isSelected()); // if (textFlags & Qt::TextEditorInteraction) QVERIFY(item->textCursor().columnNumber() > column); else QCOMPARE(item->textCursor().columnNumber(), 0); } class TextItem : public QGraphicsSimpleTextItem { public: TextItem(const QString& text) : QGraphicsSimpleTextItem(text) { updates = 0; } void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { updates++; QGraphicsSimpleTextItem::paint(painter, option, widget); } int updates; }; void tst_QGraphicsItem::ensureUpdateOnTextItem() { QGraphicsScene scene; QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(25); TextItem *text1 = new TextItem(QLatin1String("123")); scene.addItem(text1); qApp->processEvents(); QTRY_COMPARE(text1->updates,1); //same bouding rect but we have to update text1->setText(QLatin1String("321")); qApp->processEvents(); QTRY_COMPARE(text1->updates,2); } void tst_QGraphicsItem::task243707_addChildBeforeParent() { // Task reports that adding the child before the parent leads to an // inconsistent internal state that can cause a crash. This test shows // one such crash. QGraphicsScene scene; QGraphicsWidget *widget = new QGraphicsWidget; QGraphicsWidget *widget2 = new QGraphicsWidget(widget); scene.addItem(widget2); QVERIFY(!widget2->parentItem()); scene.addItem(widget); QVERIFY(!widget->commonAncestorItem(widget2)); QVERIFY(!widget2->commonAncestorItem(widget)); } void tst_QGraphicsItem::task197802_childrenVisibility() { QGraphicsScene scene; QGraphicsRectItem item(QRectF(0,0,20,20)); QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(0,0,10,10), &item); scene.addItem(&item); //freshly created: both visible QVERIFY(item.isVisible()); QVERIFY(item2->isVisible()); //hide child: parent visible, child not item2->hide(); QVERIFY(item.isVisible()); QVERIFY(!item2->isVisible()); //hide parent: parent and child invisible item.hide(); QVERIFY(!item.isVisible()); QVERIFY(!item2->isVisible()); //ask to show the child: parent and child invisible anyways item2->show(); QVERIFY(!item.isVisible()); QVERIFY(!item2->isVisible()); //show the parent: both parent and child visible item.show(); QVERIFY(item.isVisible()); QVERIFY(item2->isVisible()); delete item2; } void tst_QGraphicsItem::boundingRegion_data() { QTest::addColumn("line"); QTest::addColumn("granularity"); QTest::addColumn("transform"); QTest::addColumn("expectedRegion"); QTest::newRow("(0, 0, 10, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.0) << QTransform() << QRegion(QRect(0, 0, 10, 10)); { QRegion r; r += QRect(0, 0, 6, 2); r += QRect(0, 2, 8, 2); r += QRect(0, 4, 10, 2); r += QRect(2, 6, 8, 2); r += QRect(4, 8, 6, 2); QTest::newRow("(0, 0, 10, 10) | 0.5 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.5) << QTransform() << r; } { QRegion r; r += QRect(0, 0, 4, 1); r += QRect(0, 1, 5, 1); r += QRect(0, 2, 6, 1); r += QRect(0, 3, 7, 1); r += QRect(1, 4, 7, 1); r += QRect(2, 5, 7, 1); r += QRect(3, 6, 7, 1); r += QRect(4, 7, 6, 1); r += QRect(5, 8, 5, 1); r += QRect(6, 9, 4, 1); QTest::newRow("(0, 0, 10, 10) | 1.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(1.0) << QTransform() << r; } QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform() << QRegion(QRect(0, 0, 10, 1)); QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform() << QRegion(QRect(0, 0, 10, 1)); QTest::newRow("(0, 0, 10, 0) | 1.0 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(1.0) << QTransform() << QRegion(QRect(0, 0, 10, 1)); QTest::newRow("(0, 0, 0, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.0) << QTransform() << QRegion(QRect(0, 0, 1, 10)); QTest::newRow("(0, 0, 0, 10) | 0.5 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(0.5) << QTransform() << QRegion(QRect(0, 0, 1, 10)); QTest::newRow("(0, 0, 0, 10) | 1.0 | identity | {(0, 0, 1, 10)}") << QLineF(0, 0, 0, 10) << qreal(1.0) << QTransform() << QRegion(QRect(0, 0, 1, 10)); } void tst_QGraphicsItem::boundingRegion() { QFETCH(QLineF, line); QFETCH(qreal, granularity); QFETCH(QTransform, transform); QFETCH(QRegion, expectedRegion); QGraphicsLineItem item(line); QCOMPARE(item.boundingRegionGranularity(), qreal(0.0)); item.setBoundingRegionGranularity(granularity); QCOMPARE(item.boundingRegionGranularity(), granularity); QCOMPARE(item.boundingRegion(transform), expectedRegion); } void tst_QGraphicsItem::itemTransform_parentChild() { QGraphicsScene scene; QGraphicsItem *parent = scene.addRect(0, 0, 100, 100); QGraphicsItem *child = scene.addRect(0, 0, 100, 100); child->setParentItem(parent); child->setPos(10, 10); child->scale(2, 2); child->rotate(90); QCOMPARE(child->itemTransform(parent).map(QPointF(10, 10)), QPointF(-10, 30)); QCOMPARE(parent->itemTransform(child).map(QPointF(-10, 30)), QPointF(10, 10)); } void tst_QGraphicsItem::itemTransform_siblings() { QGraphicsScene scene; QGraphicsItem *parent = scene.addRect(0, 0, 100, 100); QGraphicsItem *brother = scene.addRect(0, 0, 100, 100); QGraphicsItem *sister = scene.addRect(0, 0, 100, 100); parent->scale(10, 5); parent->rotate(-180); parent->shear(2, 3); brother->setParentItem(parent); sister->setParentItem(parent); brother->setPos(10, 10); brother->scale(2, 2); brother->rotate(90); sister->setPos(10, 10); sister->scale(2, 2); sister->rotate(90); QCOMPARE(brother->itemTransform(sister).map(QPointF(10, 10)), QPointF(10, 10)); QCOMPARE(sister->itemTransform(brother).map(QPointF(10, 10)), QPointF(10, 10)); } void tst_QGraphicsItem::itemTransform_unrelated() { QGraphicsScene scene; QGraphicsItem *stranger1 = scene.addRect(0, 0, 100, 100); QGraphicsItem *stranger2 = scene.addRect(0, 0, 100, 100); stranger1->setPos(10, 10); stranger1->scale(2, 2); stranger1->rotate(90); stranger2->setPos(10, 10); stranger2->scale(2, 2); stranger2->rotate(90); QCOMPARE(stranger1->itemTransform(stranger2).map(QPointF(10, 10)), QPointF(10, 10)); QCOMPARE(stranger2->itemTransform(stranger1).map(QPointF(10, 10)), QPointF(10, 10)); } void tst_QGraphicsItem::opacity_data() { QTest::addColumn("p_opacity"); QTest::addColumn("p_opacityFlags"); QTest::addColumn("c1_opacity"); QTest::addColumn("c1_opacityFlags"); QTest::addColumn("c2_opacity"); QTest::addColumn("c2_opacityFlags"); QTest::addColumn("p_effectiveOpacity"); QTest::addColumn("c1_effectiveOpacity"); QTest::addColumn("c2_effectiveOpacity"); QTest::addColumn("c3_effectiveOpacity"); // Modify the opacity and see how it propagates QTest::newRow("A: 1.0 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0); QTest::newRow("B: 0.5 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5); QTest::newRow("C: 0.5 0 0.1 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(0.1) << 0 << qreal(1.0) << 0 << qreal(0.5) << qreal(0.05) << qreal(0.05) << qreal(0.05); QTest::newRow("D: 0.0 0 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0); // Parent doesn't propagate to children - now modify the opacity and see how it propagates int flags = QGraphicsItem::ItemDoesntPropagateOpacityToChildren; QTest::newRow("E: 1.0 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << flags << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0); QTest::newRow("F: 0.5 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << flags << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0); QTest::newRow("G: 0.5 2 0.1 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << flags << qreal(0.1) << 0 << qreal(1.0) << 0 << qreal(0.5) << qreal(0.1) << qreal(0.1) << qreal(0.1); QTest::newRow("H: 0.0 2 1.0 0 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << flags << qreal(1.0) << 0 << qreal(1.0) << 0 << qreal(0.0) << qreal(1.0) << qreal(1.0) << qreal(1.0); // Child ignores parent - now modify the opacity and see how it propagates flags = QGraphicsItem::ItemIgnoresParentOpacity; QTest::newRow("I: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 << qreal(1.0) << flags << qreal(1.0) << 0 << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0); QTest::newRow("J: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 << qreal(0.5) << flags << qreal(0.5) << 0 << qreal(0.5) << qreal(0.5) << qreal(0.25) << qreal(0.25); QTest::newRow("K: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.2) << 0 << qreal(0.2) << flags << qreal(0.2) << 0 << qreal(0.2) << qreal(0.2) << qreal(0.04) << qreal(0.04); QTest::newRow("L: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.0) << 0 << qreal(0.0) << flags << qreal(0.0) << 0 << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0); // Child ignores parent and doesn't propagate - now modify the opacity and see how it propagates flags = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren; QTest::newRow("M: 1.0 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p << qreal(1.0) << flags // c1 (no prop) << qreal(1.0) << 0 // c2 << qreal(1.0) << qreal(1.0) << qreal(1.0) << qreal(1.0); QTest::newRow("M: 0.5 0 1.0 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p << qreal(1.0) << flags // c1 (no prop) << qreal(1.0) << 0 // c2 << qreal(0.5) << qreal(1.0) << qreal(1.0) << qreal(1.0); QTest::newRow("M: 0.5 0 0.5 1 1.0 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p << qreal(0.5) << flags // c1 (no prop) << qreal(1.0) << 0 // c2 << qreal(0.5) << qreal(0.5) << qreal(1.0) << qreal(1.0); QTest::newRow("M: 0.5 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(0.5) << 0 // p << qreal(0.5) << flags // c1 (no prop) << qreal(0.5) << 0 // c2 << qreal(0.5) << qreal(0.5) << qreal(0.5) << qreal(0.5); QTest::newRow("M: 1.0 0 0.5 1 0.5 1.0 1.0 1.0 1.0") << qreal(1.0) << 0 // p << qreal(0.5) << flags // c1 (no prop) << qreal(0.5) << 0 // c2 << qreal(1.0) << qreal(0.5) << qreal(0.5) << qreal(0.5); } void tst_QGraphicsItem::opacity() { QFETCH(qreal, p_opacity); QFETCH(int, p_opacityFlags); QFETCH(qreal, p_effectiveOpacity); QFETCH(qreal, c1_opacity); QFETCH(int, c1_opacityFlags); QFETCH(qreal, c1_effectiveOpacity); QFETCH(qreal, c2_opacity); QFETCH(int, c2_opacityFlags); QFETCH(qreal, c2_effectiveOpacity); QFETCH(qreal, c3_effectiveOpacity); QGraphicsRectItem *p = new QGraphicsRectItem; QGraphicsRectItem *c1 = new QGraphicsRectItem(p); QGraphicsRectItem *c2 = new QGraphicsRectItem(c1); QGraphicsRectItem *c3 = new QGraphicsRectItem(c2); QCOMPARE(p->opacity(), qreal(1.0)); QCOMPARE(p->effectiveOpacity(), qreal(1.0)); int opacityMask = QGraphicsItem::ItemIgnoresParentOpacity | QGraphicsItem::ItemDoesntPropagateOpacityToChildren; QVERIFY(!(p->flags() & opacityMask)); p->setOpacity(p_opacity); c1->setOpacity(c1_opacity); c2->setOpacity(c2_opacity); p->setFlags(QGraphicsItem::GraphicsItemFlags(p->flags() | p_opacityFlags)); c1->setFlags(QGraphicsItem::GraphicsItemFlags(c1->flags() | c1_opacityFlags)); c2->setFlags(QGraphicsItem::GraphicsItemFlags(c2->flags() | c2_opacityFlags)); QCOMPARE(int(p->flags() & opacityMask), p_opacityFlags); QCOMPARE(int(c1->flags() & opacityMask), c1_opacityFlags); QCOMPARE(int(c2->flags() & opacityMask), c2_opacityFlags); QCOMPARE(p->opacity(), p_opacity); QCOMPARE(p->effectiveOpacity(), p_effectiveOpacity); QCOMPARE(c1->effectiveOpacity(), c1_effectiveOpacity); QCOMPARE(c2->effectiveOpacity(), c2_effectiveOpacity); QCOMPARE(c3->effectiveOpacity(), c3_effectiveOpacity); } void tst_QGraphicsItem::opacity2() { EventTester *parent = new EventTester; EventTester *child = new EventTester(parent); EventTester *grandChild = new EventTester(child); QGraphicsScene scene; scene.addItem(parent); MyGraphicsView view(&scene); if(PlatformQuirks::isAutoMaximizing()) view.showFullScreen(); else view.show(); QTest::qWaitForWindowShown(&view); QTRY_VERIFY(view.repaints >= 1); #define RESET_REPAINT_COUNTERS \ parent->repaints = 0; \ child->repaints = 0; \ grandChild->repaints = 0; \ view.repaints = 0; RESET_REPAINT_COUNTERS child->setOpacity(0.0); QTest::qWait(10); QTRY_COMPARE(view.repaints, 1); QCOMPARE(parent->repaints, 1); QCOMPARE(child->repaints, 0); QCOMPARE(grandChild->repaints, 0); RESET_REPAINT_COUNTERS child->setOpacity(1.0); QTest::qWait(10); QTRY_COMPARE(view.repaints, 1); QCOMPARE(parent->repaints, 1); QCOMPARE(child->repaints, 1); QCOMPARE(grandChild->repaints, 1); RESET_REPAINT_COUNTERS parent->setOpacity(0.0); QTest::qWait(10); QTRY_COMPARE(view.repaints, 1); QCOMPARE(parent->repaints, 0); QCOMPARE(child->repaints, 0); QCOMPARE(grandChild->repaints, 0); RESET_REPAINT_COUNTERS parent->setOpacity(1.0); QTest::qWait(10); QTRY_COMPARE(view.repaints, 1); QCOMPARE(parent->repaints, 1); QCOMPARE(child->repaints, 1); QCOMPARE(grandChild->repaints, 1); grandChild->setFlag(QGraphicsItem::ItemIgnoresParentOpacity); RESET_REPAINT_COUNTERS child->setOpacity(0.0); QTest::qWait(10); QTRY_COMPARE(view.repaints, 1); QCOMPARE(parent->repaints, 1); QCOMPARE(child->repaints, 0); QCOMPARE(grandChild->repaints, 1); RESET_REPAINT_COUNTERS child->setOpacity(0.0); // Already 0.0; no change. QTest::qWait(10); QTRY_COMPARE(view.repaints, 0); QCOMPARE(parent->repaints, 0); QCOMPARE(child->repaints, 0); QCOMPARE(grandChild->repaints, 0); } void tst_QGraphicsItem::opacityZeroUpdates() { EventTester *parent = new EventTester; EventTester *child = new EventTester(parent); child->setPos(10, 10); QGraphicsScene scene; scene.addItem(parent); MyGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTRY_VERIFY(view.repaints > 0); view.reset(); parent->setOpacity(0.0); QTest::qWait(20); // transforming items bounding rect to view coordinates const QRect childDeviceBoundingRect = child->deviceTransform(view.viewportTransform()) .mapRect(child->boundingRect()).toRect(); const QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform()) .mapRect(parent->boundingRect()).toRect(); QRegion expectedRegion = parentDeviceBoundingRect.adjusted(-2, -2, 2, 2); expectedRegion += childDeviceBoundingRect.adjusted(-2, -2, 2, 2); COMPARE_REGIONS(view.paintedRegion, expectedRegion); } class StacksBehindParentHelper : public QGraphicsRectItem { public: StacksBehindParentHelper(QList *paintedItems, const QRectF &rect, QGraphicsItem *parent = 0) : QGraphicsRectItem(rect, parent), paintedItems(paintedItems) { } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QGraphicsRectItem::paint(painter, option, widget); paintedItems->append(this); } private: QList *paintedItems; }; void tst_QGraphicsItem::itemStacksBehindParent() { StacksBehindParentHelper *parent1 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50)); StacksBehindParentHelper *child11 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent1); StacksBehindParentHelper *grandChild111 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child11); StacksBehindParentHelper *child12 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent1); StacksBehindParentHelper *grandChild121 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child12); StacksBehindParentHelper *parent2 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50)); StacksBehindParentHelper *child21 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent2); StacksBehindParentHelper *grandChild211 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child21); StacksBehindParentHelper *child22 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent2); StacksBehindParentHelper *grandChild221 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child22); parent1->setData(0, "parent1"); child11->setData(0, "child11"); grandChild111->setData(0, "grandChild111"); child12->setData(0, "child12"); grandChild121->setData(0, "grandChild121"); parent2->setData(0, "parent2"); child21->setData(0, "child21"); grandChild211->setData(0, "grandChild211"); child22->setData(0, "child22"); grandChild221->setData(0, "grandChild221"); // Disambiguate siblings parent1->setZValue(1); child11->setZValue(1); child21->setZValue(1); QGraphicsScene scene; scene.addItem(parent1); scene.addItem(parent2); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTRY_VERIFY(!paintedItems.isEmpty()); QTest::qWait(100); paintedItems.clear(); view.viewport()->update(); QApplication::processEvents(); QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList() << grandChild111 << child11 << grandChild121 << child12 << parent1 << grandChild211 << child21 << grandChild221 << child22 << parent2)); QTRY_COMPARE(paintedItems, QList() << parent2 << child22 << grandChild221 << child21 << grandChild211 << parent1 << child12 << grandChild121 << child11 << grandChild111); child11->setFlag(QGraphicsItem::ItemStacksBehindParent); scene.update(); paintedItems.clear(); QApplication::processEvents(); QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList() << grandChild121 << child12 << parent1 << grandChild111 << child11 << grandChild211 << child21 << grandChild221 << child22 << parent2)); QCOMPARE(paintedItems, QList() << parent2 << child22 << grandChild221 << child21 << grandChild211 << child11 << grandChild111 << parent1 << child12 << grandChild121); child12->setFlag(QGraphicsItem::ItemStacksBehindParent); paintedItems.clear(); scene.update(); QApplication::processEvents(); QTRY_COMPARE(scene.items(0, 0, 100, 100), (QList() << parent1 << grandChild111 << child11 << grandChild121 << child12 << grandChild211 << child21 << grandChild221 << child22 << parent2)); QCOMPARE(paintedItems, QList() << parent2 << child22 << grandChild221 << child21 << grandChild211 << child12 << grandChild121 << child11 << grandChild111 << parent1); } class ClippingAndTransformsScene : public QGraphicsScene { public: QList drawnItems; protected: void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget = 0) { drawnItems.clear(); for (int i = 0; i < numItems; ++i) drawnItems << items[i]; QGraphicsScene::drawItems(painter, numItems, items, options, widget); } }; void tst_QGraphicsItem::nestedClipping() { ClippingAndTransformsScene scene; scene.setSceneRect(-50, -50, 200, 200); QGraphicsRectItem *root = new QGraphicsRectItem(QRectF(0, 0, 100, 100)); root->setBrush(QColor(0, 0, 255)); root->setFlag(QGraphicsItem::ItemClipsChildrenToShape); QGraphicsRectItem *l1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100)); l1->setParentItem(root); l1->setPos(-50, 0); l1->setBrush(QColor(255, 0, 0)); l1->setFlag(QGraphicsItem::ItemClipsChildrenToShape); QGraphicsEllipseItem *l2 = new QGraphicsEllipseItem(QRectF(0, 0, 100, 100)); l2->setParentItem(l1); l2->setPos(50, 50); l2->setFlag(QGraphicsItem::ItemClipsChildrenToShape); l2->setBrush(QColor(255, 255, 0)); QGraphicsRectItem *l3 = new QGraphicsRectItem(QRectF(0, 0, 25, 25)); l3->setParentItem(l2); l3->setBrush(QColor(0, 255, 0)); l3->setPos(50 - 12, -12); scene.addItem(root); root->setData(0, "root"); l1->setData(0, "l1"); l2->setData(0, "l2"); l3->setData(0, "l3"); QGraphicsView view(&scene); view.setOptimizationFlag(QGraphicsView::IndirectPainting); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(25); QList expected; expected << root << l1 << l2 << l3; QTRY_COMPARE(scene.drawnItems, expected); QImage image(200, 200, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter painter(&image); scene.render(&painter); painter.end(); // Check transparent areas QCOMPARE(image.pixel(100, 25), qRgba(0, 0, 0, 0)); QCOMPARE(image.pixel(100, 175), qRgba(0, 0, 0, 0)); QCOMPARE(image.pixel(25, 100), qRgba(0, 0, 0, 0)); QCOMPARE(image.pixel(175, 100), qRgba(0, 0, 0, 0)); QCOMPARE(image.pixel(70, 80), qRgba(255, 0, 0, 255)); QCOMPARE(image.pixel(80, 130), qRgba(255, 255, 0, 255)); QCOMPARE(image.pixel(92, 105), qRgba(0, 255, 0, 255)); QCOMPARE(image.pixel(105, 105), qRgba(0, 0, 255, 255)); #if 0 // Enable this to compare if the test starts failing. image.save("nestedClipping_reference.png"); #endif } class TransformDebugItem : public QGraphicsRectItem { public: TransformDebugItem() : QGraphicsRectItem(QRectF(-10, -10, 20, 20)) { setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256)); } QTransform x; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) { x = painter->worldTransform(); QGraphicsRectItem::paint(painter, option, widget); } }; void tst_QGraphicsItem::nestedClippingTransforms() { TransformDebugItem *rootClipper = new TransformDebugItem; rootClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape); TransformDebugItem *child = new TransformDebugItem; child->setParentItem(rootClipper); child->setPos(2, 2); TransformDebugItem *grandChildClipper = new TransformDebugItem; grandChildClipper->setParentItem(child); grandChildClipper->setFlag(QGraphicsItem::ItemClipsChildrenToShape); grandChildClipper->setPos(4, 4); TransformDebugItem *greatGrandChild = new TransformDebugItem; greatGrandChild->setPos(2, 2); greatGrandChild->setParentItem(grandChildClipper); TransformDebugItem *grandChildClipper2 = new TransformDebugItem; grandChildClipper2->setParentItem(child); grandChildClipper2->setFlag(QGraphicsItem::ItemClipsChildrenToShape); grandChildClipper2->setPos(8, 8); TransformDebugItem *greatGrandChild2 = new TransformDebugItem; greatGrandChild2->setPos(2, 2); greatGrandChild2->setParentItem(grandChildClipper2); TransformDebugItem *grandChildClipper3 = new TransformDebugItem; grandChildClipper3->setParentItem(child); grandChildClipper3->setFlag(QGraphicsItem::ItemClipsChildrenToShape); grandChildClipper3->setPos(12, 12); TransformDebugItem *greatGrandChild3 = new TransformDebugItem; greatGrandChild3->setPos(2, 2); greatGrandChild3->setParentItem(grandChildClipper3); QGraphicsScene scene; scene.addItem(rootClipper); QImage image(scene.itemsBoundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter p(&image); scene.render(&p); p.end(); QCOMPARE(rootClipper->x, QTransform(1, 0, 0, 0, 1, 0, 10, 10, 1)); QCOMPARE(child->x, QTransform(1, 0, 0, 0, 1, 0, 12, 12, 1)); QCOMPARE(grandChildClipper->x, QTransform(1, 0, 0, 0, 1, 0, 16, 16, 1)); QCOMPARE(greatGrandChild->x, QTransform(1, 0, 0, 0, 1, 0, 18, 18, 1)); QCOMPARE(grandChildClipper2->x, QTransform(1, 0, 0, 0, 1, 0, 20, 20, 1)); QCOMPARE(greatGrandChild2->x, QTransform(1, 0, 0, 0, 1, 0, 22, 22, 1)); QCOMPARE(grandChildClipper3->x, QTransform(1, 0, 0, 0, 1, 0, 24, 24, 1)); QCOMPARE(greatGrandChild3->x, QTransform(1, 0, 0, 0, 1, 0, 26, 26, 1)); } void tst_QGraphicsItem::sceneTransformCache() { // Test that an item's scene transform is updated correctly when the // parent is transformed. QGraphicsScene scene; QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100); QGraphicsRectItem *rect2 = scene.addRect(0, 0, 100, 100); rect2->setParentItem(rect); rect2->rotate(90); rect->translate(0, 50); QGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif rect->translate(0, 100); QTransform x; x.translate(0, 150); x.rotate(90); QCOMPARE(rect2->sceneTransform(), x); scene.removeItem(rect); //Crazy use case : rect4 child of rect3 so the transformation of rect4 will be cached.Good! //We remove rect4 from the scene, then the validTransform bit flag is set to 0 and the index of the cache //add to the freeTransformSlots. The problem was that sceneTransformIndex was not set to -1 so if a new item arrive //with a child (rect6) that will be cached then it will take the freeSlot (ex rect4) and put it his transform. But if rect4 is //added back to the scene then it will set the transform to his old sceneTransformIndex value that will erase the new //value of rect6 so rect6 transform will be wrong. QGraphicsRectItem *rect3 = scene.addRect(0, 0, 100, 100); QGraphicsRectItem *rect4 = scene.addRect(0, 0, 100, 100); rect3->setPos(QPointF(10,10)); rect4->setParentItem(rect3); rect4->setPos(QPointF(10,10)); QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(20,20)); scene.removeItem(rect4); //rect4 transform is local only QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10)); QGraphicsRectItem *rect5 = scene.addRect(0, 0, 100, 100); QGraphicsRectItem *rect6 = scene.addRect(0, 0, 100, 100); rect5->setPos(QPointF(20,20)); rect6->setParentItem(rect5); rect6->setPos(QPointF(10,10)); //test if rect6 transform is ok QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30)); scene.addItem(rect4); QCOMPARE(rect4->mapToScene(rect4->boundingRect().topLeft()), QPointF(10,10)); //test if rect6 transform is still correct QCOMPARE(rect6->mapToScene(rect6->boundingRect().topLeft()), QPointF(30,30)); } void tst_QGraphicsItem::tabChangesFocus_data() { QTest::addColumn("tabChangesFocus"); QTest::newRow("tab changes focus") << true; QTest::newRow("tab doesn't change focus") << false; } void tst_QGraphicsItem::tabChangesFocus() { QFETCH(bool, tabChangesFocus); QGraphicsScene scene; QGraphicsTextItem *item = scene.addText("Hello"); item->setTabChangesFocus(tabChangesFocus); item->setTextInteractionFlags(Qt::TextEditorInteraction); item->setFocus(); QDial *dial1 = new QDial; QGraphicsView *view = new QGraphicsView(&scene); QDial *dial2 = new QDial; QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(dial1); layout->addWidget(view); layout->addWidget(dial2); QWidget widget; widget.setLayout(layout); widget.show(); QTest::qWaitForWindowShown(&widget); QTest::qWait(2000); QTRY_VERIFY(scene.isActive()); dial1->setFocus(); QTest::qWait(15); QTRY_VERIFY(dial1->hasFocus()); QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab); QTest::qWait(15); QTRY_VERIFY(view->hasFocus()); QTRY_VERIFY(item->hasFocus()); QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab); QTest::qWait(15); if (tabChangesFocus) { QTRY_VERIFY(!view->hasFocus()); QTRY_VERIFY(!item->hasFocus()); QTRY_VERIFY(dial2->hasFocus()); } else { QTRY_VERIFY(view->hasFocus()); QTRY_VERIFY(item->hasFocus()); QCOMPARE(item->toPlainText(), QString("\tHello")); } } void tst_QGraphicsItem::cacheMode() { QGraphicsScene scene(0, 0, 100, 100); QGraphicsView view(&scene); view.resize(150, 150); view.show(); QApplication::setActiveWindow(&view); QTest::qWaitForWindowShown(&view); // Increase the probability of window activation // not causing another repaint of test items. QTest::qWait(50); EventTester *tester = new EventTester; EventTester *testerChild = new EventTester; testerChild->setParentItem(tester); EventTester *testerChild2 = new EventTester; testerChild2->setParentItem(testerChild); testerChild2->setFlag(QGraphicsItem::ItemIgnoresTransformations); scene.addItem(tester); QTest::qWait(10); for (int i = 0; i < 2; ++i) { // No visual change. QTRY_COMPARE(tester->repaints, 1); QCOMPARE(testerChild->repaints, 1); QCOMPARE(testerChild2->repaints, 1); tester->setCacheMode(QGraphicsItem::NoCache); testerChild->setCacheMode(QGraphicsItem::NoCache); testerChild2->setCacheMode(QGraphicsItem::NoCache); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 1); QCOMPARE(testerChild->repaints, 1); QCOMPARE(testerChild2->repaints, 1); tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache); testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache); testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache); QTest::qWait(25); } // The first move causes a repaint as the item is painted into its pixmap. // (Only occurs if the item has previously been painted without cache). tester->setPos(10, 10); testerChild->setPos(10, 10); testerChild2->setPos(10, 10); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 2); QCOMPARE(testerChild->repaints, 2); QCOMPARE(testerChild2->repaints, 2); // Consecutive moves should not repaint. tester->setPos(20, 20); testerChild->setPos(20, 20); testerChild2->setPos(20, 20); QTest::qWait(250); QCOMPARE(tester->repaints, 2); QCOMPARE(testerChild->repaints, 2); QCOMPARE(testerChild2->repaints, 2); // Translating does not result in a repaint. tester->translate(10, 10); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 2); QCOMPARE(testerChild->repaints, 2); QCOMPARE(testerChild2->repaints, 2); // Rotating results in a repaint. tester->rotate(45); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 3); QCOMPARE(testerChild->repaints, 3); QCOMPARE(testerChild2->repaints, 2); // Change to ItemCoordinateCache (triggers repaint). tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache); // autosize QTest::qWait(25); QTRY_COMPARE(tester->repaints, 4); QCOMPARE(testerChild->repaints, 4); QCOMPARE(testerChild2->repaints, 3); // Rotating items with ItemCoordinateCache doesn't cause a repaint. tester->rotate(22); testerChild->rotate(22); testerChild2->rotate(22); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 4); QTRY_COMPARE(testerChild->repaints, 4); QTRY_COMPARE(testerChild2->repaints, 3); tester->resetTransform(); testerChild->resetTransform(); testerChild2->resetTransform(); // Explicit update causes a repaint. tester->update(0, 0, 5, 5); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 5); QCOMPARE(testerChild->repaints, 4); QCOMPARE(testerChild2->repaints, 3); // Updating outside the item's bounds does not cause a repaint. tester->update(10, 10, 5, 5); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 5); QCOMPARE(testerChild->repaints, 4); QCOMPARE(testerChild2->repaints, 3); // Resizing an item should cause a repaint of that item. (because of // autosize). tester->setGeometry(QRectF(-15, -15, 30, 30)); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 6); QCOMPARE(testerChild->repaints, 4); QCOMPARE(testerChild2->repaints, 3); // Set fixed size. tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30)); testerChild->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30)); testerChild2->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(30, 30)); QTest::qWait(20); QTRY_COMPARE(tester->repaints, 7); QCOMPARE(testerChild->repaints, 5); QCOMPARE(testerChild2->repaints, 4); // Resizing the item should cause a repaint. testerChild->setGeometry(QRectF(-15, -15, 30, 30)); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 7); QCOMPARE(testerChild->repaints, 6); QCOMPARE(testerChild2->repaints, 4); // Scaling the view does not cause a repaint. view.scale(0.7, 0.7); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 7); QCOMPARE(testerChild->repaints, 6); QCOMPARE(testerChild2->repaints, 4); // Switch to device coordinate cache. tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache); testerChild->setCacheMode(QGraphicsItem::DeviceCoordinateCache); testerChild2->setCacheMode(QGraphicsItem::DeviceCoordinateCache); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 8); QCOMPARE(testerChild->repaints, 7); QCOMPARE(testerChild2->repaints, 5); // Scaling the view back should cause repaints for two of the items. view.setTransform(QTransform()); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 9); QCOMPARE(testerChild->repaints, 8); QCOMPARE(testerChild2->repaints, 5); // Rotating the base item (perspective) should repaint two items. tester->setTransform(QTransform().rotate(10, Qt::XAxis)); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 10); QCOMPARE(testerChild->repaints, 9); QCOMPARE(testerChild2->repaints, 5); // Moving the middle item should case a repaint even if it's a move, // because the parent is rotated with a perspective. testerChild->setPos(1, 1); QTest::qWait(25); QTRY_COMPARE(tester->repaints, 11); QTRY_COMPARE(testerChild->repaints, 10); QTRY_COMPARE(testerChild2->repaints, 5); tester->resetTransform(); // Make a huge item tester->setGeometry(QRectF(-4000, -4000, 8000, 8000)); QTRY_COMPARE(tester->repaints, 12); QTRY_COMPARE(testerChild->repaints, 11); QTRY_COMPARE(testerChild2->repaints, 5); // Move the large item - will cause a repaint as the // cache is clipped. tester->setPos(5, 0); QTRY_COMPARE(tester->repaints, 13); QTRY_COMPARE(testerChild->repaints, 11); QTRY_COMPARE(testerChild2->repaints, 5); // Hiding and showing should invalidate the cache tester->hide(); QTest::qWait(25); tester->show(); QTRY_COMPARE(tester->repaints, 14); QTRY_COMPARE(testerChild->repaints, 12); QTRY_COMPARE(testerChild2->repaints, 6); } void tst_QGraphicsItem::cacheMode2() { QGraphicsScene scene(0, 0, 100, 100); QGraphicsView view(&scene); view.resize(150, 150); view.show(); QApplication::setActiveWindow(&view); QTest::qWaitForWindowShown(&view); // Increase the probability of window activation // not causing another repaint of test items. QTest::qWait(50); EventTester *tester = new EventTester; scene.addItem(tester); QTest::qWait(10); QTRY_COMPARE(tester->repaints, 1); // Switching from NoCache to NoCache (no repaint) tester->setCacheMode(QGraphicsItem::NoCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 1); // Switching from NoCache to DeviceCoordinateCache (no repaint) tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 1); // Switching from DeviceCoordinateCache to DeviceCoordinateCache (no repaint) tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 1); // Switching from DeviceCoordinateCache to NoCache (no repaint) tester->setCacheMode(QGraphicsItem::NoCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 1); // Switching from NoCache to ItemCoordinateCache (repaint) tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 2); // Switching from ItemCoordinateCache to ItemCoordinateCache (no repaint) tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 2); // Switching from ItemCoordinateCache to ItemCoordinateCache with different size (repaint) tester->setCacheMode(QGraphicsItem::ItemCoordinateCache, QSize(100, 100)); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 3); // Switching from ItemCoordinateCache to NoCache (repaint) tester->setCacheMode(QGraphicsItem::NoCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 4); // Switching from DeviceCoordinateCache to ItemCoordinateCache (repaint) tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 4); tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 5); // Switching from ItemCoordinateCache to DeviceCoordinateCache (repaint) tester->setCacheMode(QGraphicsItem::DeviceCoordinateCache); QTest::qWait(50); QTRY_COMPARE(tester->repaints, 6); } void tst_QGraphicsItem::updateCachedItemAfterMove() { // A simple item that uses ItemCoordinateCache EventTester *tester = new EventTester; tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); // Add to a scene, show in a view, ensure it's painted and reset its // repaint counter. QGraphicsScene scene; scene.addItem(tester); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(12); QTRY_VERIFY(tester->repaints > 0); tester->repaints = 0; // Move the item, should not cause repaints tester->setPos(10, 0); QTest::qWait(12); QCOMPARE(tester->repaints, 0); // Move then update, should cause one repaint tester->setPos(20, 0); tester->update(); QTest::qWait(12); QCOMPARE(tester->repaints, 1); // Hiding the item doesn't cause a repaint tester->hide(); QTest::qWait(12); QCOMPARE(tester->repaints, 1); // Moving a hidden item doesn't cause a repaint tester->setPos(30, 0); tester->update(); QTest::qWait(12); QCOMPARE(tester->repaints, 1); } class Track : public QGraphicsRectItem { public: Track(const QRectF &rect) : QGraphicsRectItem(rect) { setAcceptHoverEvents(true); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) { QGraphicsRectItem::paint(painter, option, widget); painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1x%2\n%3x%4").arg(p.x()).arg(p.y()).arg(sp.x()).arg(sp.y())); } protected: void hoverMoveEvent(QGraphicsSceneHoverEvent *event) { p = event->pos(); sp = event->widget()->mapFromGlobal(event->screenPos()); update(); } private: QPointF p; QPoint sp; }; void tst_QGraphicsItem::deviceTransform_data() { QTest::addColumn("untransformable1"); QTest::addColumn("untransformable2"); QTest::addColumn("untransformable3"); QTest::addColumn("rotation1"); QTest::addColumn("rotation2"); QTest::addColumn("rotation3"); QTest::addColumn("deviceX"); QTest::addColumn("mapResult1"); QTest::addColumn("mapResult2"); QTest::addColumn("mapResult3"); QTest::newRow("nil") << false << false << false << qreal(0.0) << qreal(0.0) << qreal(0.0) << QTransform() << QPointF(150, 150) << QPointF(250, 250) << QPointF(350, 350); QTest::newRow("deviceX rot 90") << false << false << false << qreal(0.0) << qreal(0.0) << qreal(0.0) << QTransform().rotate(90) << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-350, 350); QTest::newRow("deviceX rot 90 100") << true << false << false << qreal(0.0) << qreal(0.0) << qreal(0.0) << QTransform().rotate(90) << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350); QTest::newRow("deviceX rot 90 010") << false << true << false << qreal(0.0) << qreal(0.0) << qreal(0.0) << QTransform().rotate(90) << QPointF(-150, 150) << QPointF(-150, 250) << QPointF(-50, 350); QTest::newRow("deviceX rot 90 001") << false << false << true << qreal(0.0) << qreal(0.0) << qreal(0.0) << QTransform().rotate(90) << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-250, 350); QTest::newRow("deviceX rot 90 111") << true << true << true << qreal(0.0) << qreal(0.0) << qreal(0.0) << QTransform().rotate(90) << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350); QTest::newRow("deviceX rot 90 101") << true << false << true << qreal(0.0) << qreal(0.0) << qreal(0.0) << QTransform().rotate(90) << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350); } void tst_QGraphicsItem::deviceTransform() { QFETCH(bool, untransformable1); QFETCH(bool, untransformable2); QFETCH(bool, untransformable3); QFETCH(qreal, rotation1); QFETCH(qreal, rotation2); QFETCH(qreal, rotation3); QFETCH(QTransform, deviceX); QFETCH(QPointF, mapResult1); QFETCH(QPointF, mapResult2); QFETCH(QPointF, mapResult3); QGraphicsScene scene; Track *rect1 = new Track(QRectF(0, 0, 100, 100)); Track *rect2 = new Track(QRectF(0, 0, 100, 100)); Track *rect3 = new Track(QRectF(0, 0, 100, 100)); rect2->setParentItem(rect1); rect3->setParentItem(rect2); rect1->setPos(100, 100); rect2->setPos(100, 100); rect3->setPos(100, 100); rect1->rotate(rotation1); rect2->rotate(rotation2); rect3->rotate(rotation3); rect1->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable1); rect2->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable2); rect3->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable3); rect1->setBrush(Qt::red); rect2->setBrush(Qt::green); rect3->setBrush(Qt::blue); scene.addItem(rect1); QCOMPARE(rect1->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult1); QCOMPARE(rect2->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult2); QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3); } void tst_QGraphicsItem::update() { QGraphicsScene scene; scene.setSceneRect(-100, -100, 200, 200); QWidget topLevel; MyGraphicsView view(&scene,&topLevel); topLevel.resize(300, 300); topLevel.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif QTest::qWait(100); EventTester *item = new EventTester; scene.addItem(item); QTest::qWait(100); // Make sure all pending updates are processed. item->repaints = 0; item->update(); // Item marked as dirty scene.update(); // Entire scene marked as dirty qApp->processEvents(); QCOMPARE(item->repaints, 1); // Make sure the dirty state from the previous update is reset so that // the item don't think it is already dirty and discards this update. item->update(); qApp->processEvents(); QCOMPARE(item->repaints, 2); // Make sure a partial update doesn't cause a full update to be discarded. view.reset(); item->repaints = 0; item->update(QRectF(0, 0, 5, 5)); item->update(); qApp->processEvents(); QCOMPARE(item->repaints, 1); QCOMPARE(view.repaints, 1); QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform()) .mapRect(item->boundingRect()).toAlignedRect(); QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // The entire item's bounding rect (adjusted for antialiasing) should have been painted. QCOMPARE(view.paintedRegion, expectedRegion); // Make sure update requests outside the bounding rect are discarded. view.reset(); item->repaints = 0; item->update(-15, -15, 5, 5); // Item's brect: (-10, -10, 20, 20) qApp->processEvents(); QCOMPARE(item->repaints, 0); QCOMPARE(view.repaints, 0); // Make sure the area occupied by an item is repainted when hiding it. view.reset(); item->repaints = 0; item->update(); // Full update; all sub-sequent update requests are discarded. item->hide(); // visible set to 0. ignoreVisible must be set to 1; the item won't be processed otherwise. qApp->processEvents(); QCOMPARE(item->repaints, 0); QCOMPARE(view.repaints, 1); // The entire item's bounding rect (adjusted for antialiasing) should have been painted. QCOMPARE(view.paintedRegion, expectedRegion); // Make sure item is repainted when shown (after being hidden). view.reset(); item->repaints = 0; item->show(); qApp->processEvents(); QCOMPARE(item->repaints, 1); QCOMPARE(view.repaints, 1); // The entire item's bounding rect (adjusted for antialiasing) should have been painted. QCOMPARE(view.paintedRegion, expectedRegion); item->repaints = 0; item->hide(); qApp->processEvents(); view.reset(); const QPointF originalPos = item->pos(); item->setPos(5000, 5000); qApp->processEvents(); QCOMPARE(item->repaints, 0); QCOMPARE(view.repaints, 0); qApp->processEvents(); item->setPos(originalPos); qApp->processEvents(); QCOMPARE(item->repaints, 0); QCOMPARE(view.repaints, 0); item->show(); qApp->processEvents(); QCOMPARE(item->repaints, 1); QCOMPARE(view.repaints, 1); // The entire item's bounding rect (adjusted for antialiasing) should have been painted. QCOMPARE(view.paintedRegion, expectedRegion); QGraphicsViewPrivate *viewPrivate = static_cast(qt_widget_private(&view)); item->setPos(originalPos + QPoint(50, 50)); viewPrivate->updateAll(); QVERIFY(viewPrivate->fullUpdatePending); QTest::qWait(50); item->repaints = 0; view.reset(); item->setPos(originalPos); QTest::qWait(50); qApp->processEvents(); QCOMPARE(item->repaints, 1); QCOMPARE(view.repaints, 1); COMPARE_REGIONS(view.paintedRegion, expectedRegion + expectedRegion.translated(50, 50)); // Make sure moving a parent item triggers an update on the children // (even though the parent itself is outside the viewport). QGraphicsRectItem *parent = new QGraphicsRectItem(0, 0, 10, 10); parent->setPos(-400, 0); item->setParentItem(parent); item->setPos(400, 0); scene.addItem(parent); QTest::qWait(50); itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform()) .mapRect(item->boundingRect()).toAlignedRect(); expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); view.reset(); item->repaints = 0; parent->translate(-400, 0); qApp->processEvents(); QCOMPARE(item->repaints, 0); QCOMPARE(view.repaints, 1); QCOMPARE(view.paintedRegion, expectedRegion); view.reset(); item->repaints = 0; parent->translate(400, 0); qApp->processEvents(); QCOMPARE(item->repaints, 1); QCOMPARE(view.repaints, 1); QCOMPARE(view.paintedRegion, expectedRegion); QCOMPARE(view.paintedRegion, expectedRegion); } void tst_QGraphicsItem::setTransformProperties_data() { QTest::addColumn("origin"); QTest::addColumn("rotation"); QTest::addColumn("scale"); QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(1.0); QTest::newRow("rotation") << QPointF() << qreal(42.2) << qreal(1.0); QTest::newRow("rotation dicentred") << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-2578.2) << qreal(1.0); QTest::newRow("Scale") << QPointF() << qreal(0.0) << qreal(6); QTest::newRow("Everything dicentred") << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196); } /** * the normal QCOMPARE doesn't work because it doesn't use qFuzzyCompare */ #define QCOMPARE_TRANSFORM(X1, X2) QVERIFY(((X1)*(X2).inverted()).isIdentity()) void tst_QGraphicsItem::setTransformProperties() { QFETCH(QPointF,origin); QFETCH(qreal,rotation); QFETCH(qreal,scale); QTransform result; result.translate(origin.x(), origin.y()); result.rotate(rotation, Qt::ZAxis); result.scale(scale, scale); result.translate(-origin.x(), -origin.y()); QGraphicsScene scene; QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100)); scene.addItem(item); item->setRotation(rotation); item->setScale(scale); item->setTransformOriginPoint(origin); QCOMPARE(item->rotation(), rotation); QCOMPARE(item->scale(), scale); QCOMPARE(item->transformOriginPoint(), origin); QCOMPARE(QTransform(), item->transform()); QCOMPARE(result, item->sceneTransform()); //----------------------------------------------------------------- //Change the rotation Z item->setRotation(45); QTransform result2; result2.translate(origin.x(), origin.y()); result2.rotate(45); result2.scale(scale, scale); result2.translate(-origin.x(), -origin.y()); QCOMPARE(item->rotation(), 45.); QCOMPARE(item->scale(), scale); QCOMPARE(item->transformOriginPoint(), origin); QCOMPARE(QTransform(), item->transform()); QCOMPARE(result2, item->sceneTransform()); //----------------------------------------------------------------- // calling setTransform() and setPos should change the sceneTransform item->setTransform(result); item->setPos(100, -150.5); QCOMPARE(item->rotation(), 45.); QCOMPARE(item->scale(), scale); QCOMPARE(item->transformOriginPoint(), origin); QCOMPARE(result, item->transform()); QTransform result3(result); result3.translate(origin.x(), origin.y()); result3.rotate(45); result3.scale(scale, scale); result3.translate(-origin.x(), -origin.y()); result3 *= QTransform::fromTranslate(100, -150.5); //the pos; QCOMPARE(result3, item->sceneTransform()); //----------------------------------------------------- // setting the propertiees should be the same as setting a transform {//with center origin on the matrix QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119)); scene.addItem(item1); QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119)); scene.addItem(item2); item1->setPos(12.3, -5); item2->setPos(12.3, -5); item1->setRotation(rotation); item1->setScale(scale); item1->setTransformOriginPoint(origin); item2->setTransform(result); QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform()); QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform()); QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform()); } } class MyStyleOptionTester : public QGraphicsRectItem { public: MyStyleOptionTester(const QRectF &rect) : QGraphicsRectItem(rect), startTrack(false) {} void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) { if (startTrack) { //Doesn't use the extended style option so the exposed rect is the boundingRect if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) { QCOMPARE(option->exposedRect, boundingRect()); QCOMPARE(option->matrix, QMatrix()); } else { QVERIFY(option->exposedRect != QRect()); QVERIFY(option->exposedRect != boundingRect()); QCOMPARE(option->matrix, sceneTransform().toAffine()); } } QGraphicsRectItem::paint(painter, option, widget); } bool startTrack; }; void tst_QGraphicsItem::itemUsesExtendedStyleOption() { QGraphicsScene scene(0, 0, 300, 300); QGraphicsPixmapItem item; item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true); QCOMPARE(item.flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption)); item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false); QCOMPARE(item.flags(), 0); //We now test the content of the style option MyStyleOptionTester *rect = new MyStyleOptionTester(QRect(0, 0, 100, 100)); scene.addItem(rect); rect->setPos(200, 200); QWidget topLevel; QGraphicsView view(&scene, &topLevel); topLevel.setWindowFlags(Qt::X11BypassWindowManagerHint); rect->startTrack = false; topLevel.show(); QTest::qWaitForWindowShown(&view); QTest::qWait(60); rect->startTrack = true; rect->update(10, 10, 10, 10); QTest::qWait(60); rect->startTrack = false; rect->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true); QVERIFY((rect->flags() & QGraphicsItem::ItemUsesExtendedStyleOption)); QTest::qWait(60); rect->startTrack = true; rect->update(10, 10, 10, 10); QTest::qWait(60); } void tst_QGraphicsItem::itemSendsGeometryChanges() { ItemChangeTester item; item.setFlags(0); item.clear(); QTransform x = QTransform().rotate(45); QPointF pos(10, 10); qreal o(0.5); qreal r(10.0); qreal s(1.5); QPointF origin(1.0, 1.0); item.setTransform(x); item.setPos(pos); item.setRotation(r); item.setScale(s); item.setTransformOriginPoint(origin); QCOMPARE(item.transform(), x); QCOMPARE(item.pos(), pos); QCOMPARE(item.rotation(), r); QCOMPARE(item.scale(), s); QCOMPARE(item.transformOriginPoint(), origin); QCOMPARE(item.changes.size(), 0); item.setOpacity(o); QCOMPARE(item.changes.size(), 2); // opacity item.setFlag(QGraphicsItem::ItemSendsGeometryChanges); QCOMPARE(item.changes.size(), 4); // flags item.setTransform(QTransform()); item.setPos(QPointF()); QCOMPARE(item.changes.size(), 8); // transform + pos QCOMPARE(item.transform(), QTransform()); QCOMPARE(item.pos(), QPointF()); QCOMPARE(item.opacity(), o); item.setRotation(0.0); item.setScale(1.0); item.setTransformOriginPoint(0.0, 0.0); QCOMPARE(item.changes.size(), 14); // rotation + scale + origin QCOMPARE(item.rotation(), qreal(0.0)); QCOMPARE(item.scale(), qreal(1.0)); QCOMPARE(item.transformOriginPoint(), QPointF(0.0, 0.0)); QCOMPARE(item.changes, QList() << QGraphicsItem::ItemOpacityChange << QGraphicsItem::ItemOpacityHasChanged << QGraphicsItem::ItemFlagsChange << QGraphicsItem::ItemFlagsHaveChanged << QGraphicsItem::ItemTransformChange << QGraphicsItem::ItemTransformHasChanged << QGraphicsItem::ItemPositionChange << QGraphicsItem::ItemPositionHasChanged << QGraphicsItem::ItemRotationChange << QGraphicsItem::ItemRotationHasChanged << QGraphicsItem::ItemScaleChange << QGraphicsItem::ItemScaleHasChanged << QGraphicsItem::ItemTransformOriginPointChange << QGraphicsItem::ItemTransformOriginPointHasChanged); } // Make sure we update moved items correctly. void tst_QGraphicsItem::moveItem() { QGraphicsScene scene; scene.setSceneRect(-50, -50, 200, 200); MyGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif QTest::qWait(100); EventTester *parent = new EventTester; EventTester *child = new EventTester(parent); EventTester *grandChild = new EventTester(child); #define RESET_COUNTERS \ parent->repaints = 0; \ child->repaints = 0; \ grandChild->repaints = 0; \ view.reset(); scene.addItem(parent); QTest::qWait(100); RESET_COUNTERS // Item's boundingRect: (-10, -10, 20, 20). QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform()) .mapRect(parent->boundingRect()).toAlignedRect() .adjusted(-2, -2, 2, 2); // Adjusted for antialiasing. parent->setPos(20, 20); qApp->processEvents(); QCOMPARE(parent->repaints, 1); QCOMPARE(view.repaints, 1); QRegion expectedParentRegion = parentDeviceBoundingRect; // old position parentDeviceBoundingRect.translate(20, 20); expectedParentRegion += parentDeviceBoundingRect; // new position COMPARE_REGIONS(view.paintedRegion, expectedParentRegion); RESET_COUNTERS child->setPos(20, 20); qApp->processEvents(); QCOMPARE(parent->repaints, 1); QCOMPARE(child->repaints, 1); QCOMPARE(view.repaints, 1); const QRegion expectedChildRegion = expectedParentRegion.translated(20, 20); COMPARE_REGIONS(view.paintedRegion, expectedChildRegion); RESET_COUNTERS grandChild->setPos(20, 20); qApp->processEvents(); QCOMPARE(parent->repaints, 1); QCOMPARE(child->repaints, 1); QCOMPARE(grandChild->repaints, 1); QCOMPARE(view.repaints, 1); const QRegion expectedGrandChildRegion = expectedParentRegion.translated(40, 40); COMPARE_REGIONS(view.paintedRegion, expectedGrandChildRegion); RESET_COUNTERS parent->translate(20, 20); qApp->processEvents(); QCOMPARE(parent->repaints, 1); QCOMPARE(child->repaints, 1); QCOMPARE(grandChild->repaints, 1); QCOMPARE(view.repaints, 1); expectedParentRegion.translate(20, 20); expectedParentRegion += expectedChildRegion.translated(20, 20); expectedParentRegion += expectedGrandChildRegion.translated(20, 20); COMPARE_REGIONS(view.paintedRegion, expectedParentRegion); } void tst_QGraphicsItem::moveLineItem() { QGraphicsScene scene; scene.setSceneRect(0, 0, 200, 200); QGraphicsLineItem *item = new QGraphicsLineItem(0, 0, 100, 0); item->setPos(50, 50); scene.addItem(item); MyGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif QTest::qWait(200); view.reset(); QRectF brect = item->boundingRect(); // Do same adjustments as in qgraphicsscene.cpp if (!brect.width()) brect.adjust(qreal(-0.00001), 0, qreal(0.00001), 0); if (!brect.height()) brect.adjust(0, qreal(-0.00001), 0, qreal(0.00001)); const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform()) .mapRect(brect).toAlignedRect(); QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // antialiasing // Make sure the calculated region is correct. item->update(); QTest::qWait(10); QTRY_COMPARE(view.paintedRegion, expectedRegion); view.reset(); // Old position: (50, 50) item->setPos(50, 100); expectedRegion += expectedRegion.translated(0, 50); QTest::qWait(10); QCOMPARE(view.paintedRegion, expectedRegion); } void tst_QGraphicsItem::sorting_data() { QTest::addColumn("index"); QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex); QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex); } void tst_QGraphicsItem::sorting() { if (PlatformQuirks::isAutoMaximizing()) QSKIP("Skipped because Platform is auto maximizing", SkipAll); _paintedItems.clear(); QGraphicsScene scene; QGraphicsItem *grid[100][100]; for (int x = 0; x < 100; ++x) { for (int y = 0; y < 100; ++y) { PainterItem *item = new PainterItem; item->setPos(x * 25, y * 25); item->setData(0, QString("%1x%2").arg(x).arg(y)); grid[x][y] = item; scene.addItem(item); } } PainterItem *item1 = new PainterItem; PainterItem *item2 = new PainterItem; item1->setData(0, "item1"); item2->setData(0, "item2"); scene.addItem(item1); scene.addItem(item2); QGraphicsView view(&scene); view.setResizeAnchor(QGraphicsView::NoAnchor); view.setTransformationAnchor(QGraphicsView::NoAnchor); view.resize(120, 100); view.setFrameStyle(0); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif QTest::qWait(100); _paintedItems.clear(); view.viewport()->repaint(); #if defined(Q_WS_MAC) // There's no difference between repaint and update on the Mac, // so we have to process events here to make sure we get the event. QTest::qWait(100); #endif QCOMPARE(_paintedItems, QList() << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3] << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3] << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3] << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3] << grid[4][0] << grid[4][1] << grid[4][2] << grid[4][3] << item1 << item2); } void tst_QGraphicsItem::itemHasNoContents() { PainterItem *item1 = new PainterItem; PainterItem *item2 = new PainterItem; item2->setParentItem(item1); item2->setPos(50, 50); item1->setFlag(QGraphicsItem::ItemHasNoContents); item1->setFlag(QGraphicsItem::ItemClipsChildrenToShape); QGraphicsScene scene; scene.addItem(item1); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTRY_VERIFY(!_paintedItems.isEmpty()); _paintedItems.clear(); view.viewport()->repaint(); #ifdef Q_WS_MAC // There's no difference between update() and repaint() on the Mac, // so we have to process events here to make sure we get the event. QTest::qWait(10); #endif QTRY_COMPARE(_paintedItems, QList() << item2); } void tst_QGraphicsItem::hitTestUntransformableItem() { QGraphicsScene scene; scene.setSceneRect(-100, -100, 200, 200); QGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif QTest::qWait(100); // Confuse the BSP with dummy items. QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20); dummy->setPos(-100, -100); scene.addItem(dummy); for (int i = 0; i < 100; ++i) { QGraphicsItem *parent = dummy; dummy = new QGraphicsRectItem(0, 0, 20, 20); dummy->setPos(-100 + i, -100 + i); dummy->setParentItem(parent); } QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20); item1->setPos(-200, -200); QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 20, 20); item2->setFlag(QGraphicsItem::ItemIgnoresTransformations); item2->setParentItem(item1); item2->setPos(200, 200); QGraphicsRectItem *item3 = new QGraphicsRectItem(0, 0, 20, 20); item3->setParentItem(item2); item3->setPos(80, 80); scene.addItem(item1); QTest::qWait(100); QList items = scene.items(QPointF(80, 80)); QCOMPARE(items.size(), 1); QCOMPARE(items.at(0), static_cast(item3)); scene.setItemIndexMethod(QGraphicsScene::NoIndex); QTest::qWait(100); items = scene.items(QPointF(80, 80)); QCOMPARE(items.size(), 1); QCOMPARE(items.at(0), static_cast(item3)); } void tst_QGraphicsItem::hitTestGraphicsEffectItem() { QGraphicsScene scene; scene.setSceneRect(-100, -100, 200, 200); QWidget toplevel; QGraphicsView view(&scene, &toplevel); toplevel.resize(300, 300); toplevel.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&toplevel); #endif QTest::qWait(100); // Confuse the BSP with dummy items. QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20); dummy->setPos(-100, -100); scene.addItem(dummy); for (int i = 0; i < 100; ++i) { QGraphicsItem *parent = dummy; dummy = new QGraphicsRectItem(0, 0, 20, 20); dummy->setPos(-100 + i, -100 + i); dummy->setParentItem(parent); } const QRectF itemBoundingRect(0, 0, 20, 20); EventTester *item1 = new EventTester; item1->br = itemBoundingRect; item1->setPos(-200, -200); item1->brush = Qt::red; EventTester *item2 = new EventTester; item2->br = itemBoundingRect; item2->setFlag(QGraphicsItem::ItemIgnoresTransformations); item2->setParentItem(item1); item2->setPos(200, 200); item2->brush = Qt::green; EventTester *item3 = new EventTester; item3->br = itemBoundingRect; item3->setParentItem(item2); item3->setPos(80, 80); item3->brush = Qt::blue; scene.addItem(item1); QTest::qWait(100); item1->repaints = 0; item2->repaints = 0; item3->repaints = 0; // Apply shadow effect to the entire sub-tree. QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect; shadow->setOffset(-20, -20); item1->setGraphicsEffect(shadow); QTest::qWait(50); // Make sure all visible items are repainted. QCOMPARE(item1->repaints, 1); QCOMPARE(item2->repaints, 1); QCOMPARE(item3->repaints, 1); // Make sure an item doesn't respond to a click on its shadow. QList items = scene.items(QPointF(75, 75)); QVERIFY(items.isEmpty()); items = scene.items(QPointF(80, 80)); QCOMPARE(items.size(), 1); QCOMPARE(items.at(0), static_cast(item3)); scene.setItemIndexMethod(QGraphicsScene::NoIndex); QTest::qWait(100); items = scene.items(QPointF(75, 75)); QVERIFY(items.isEmpty()); items = scene.items(QPointF(80, 80)); QCOMPARE(items.size(), 1); QCOMPARE(items.at(0), static_cast(item3)); } void tst_QGraphicsItem::focusProxy() { QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); QGraphicsItem *item = scene.addRect(0, 0, 10, 10); item->setFlag(QGraphicsItem::ItemIsFocusable); QVERIFY(!item->focusProxy()); QGraphicsItem *item2 = scene.addRect(0, 0, 10, 10); item2->setFlag(QGraphicsItem::ItemIsFocusable); item->setFocusProxy(item2); QCOMPARE(item->focusProxy(), item2); item->setFocus(); QVERIFY(item->hasFocus()); QVERIFY(item2->hasFocus()); // Try to make a focus chain loop QString err; QTextStream stream(&err); stream << "QGraphicsItem::setFocusProxy: " << (void*)item << " is already in the focus proxy chain" << flush; QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData()); item2->setFocusProxy(item); // fails QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2); QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0); // Try to assign self as focus proxy QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: cannot assign self as focus proxy"); item->setFocusProxy(item); // fails QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2); QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0); // Reset the focus proxy item->setFocusProxy(0); QCOMPARE(item->focusProxy(), (QGraphicsItem *)0); QVERIFY(!item->hasFocus()); QVERIFY(item2->hasFocus()); // Test deletion item->setFocusProxy(item2); QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2); delete item2; QCOMPARE(item->focusProxy(), (QGraphicsItem *)0); // Test event delivery item2 = scene.addRect(0, 0, 10, 10); item2->setFlag(QGraphicsItem::ItemIsFocusable); item->setFocusProxy(item2); item->clearFocus(); EventSpy focusInSpy(&scene, item, QEvent::FocusIn); EventSpy focusOutSpy(&scene, item, QEvent::FocusOut); EventSpy focusInSpy2(&scene, item2, QEvent::FocusIn); EventSpy focusOutSpy2(&scene, item2, QEvent::FocusOut); QCOMPARE(focusInSpy.count(), 0); QCOMPARE(focusOutSpy.count(), 0); QCOMPARE(focusInSpy2.count(), 0); QCOMPARE(focusOutSpy2.count(), 0); item->setFocus(); QCOMPARE(focusInSpy.count(), 0); QCOMPARE(focusInSpy2.count(), 1); item->clearFocus(); QCOMPARE(focusOutSpy.count(), 0); QCOMPARE(focusOutSpy2.count(), 1); // Test two items proxying one item. QGraphicsItem *item3 = scene.addRect(0, 0, 10, 10); item3->setFlag(QGraphicsItem::ItemIsFocusable); item3->setFocusProxy(item2); // item and item3 use item2 as proxy QCOMPARE(item->focusProxy(), item2); QCOMPARE(item2->focusProxy(), (QGraphicsItem *)0); QCOMPARE(item3->focusProxy(), item2); delete item2; QCOMPARE(item->focusProxy(), (QGraphicsItem *)0); QCOMPARE(item3->focusProxy(), (QGraphicsItem *)0); } void tst_QGraphicsItem::subFocus() { // Construct a text item that's not part of a scene (yet) // and has no parent. Setting focus on it will not make // the item gain input focus; that requires a scene. But // it does set subfocus, indicating that the item wishes // to gain focus later. QGraphicsTextItem *text = new QGraphicsTextItem("Hello"); text->setTextInteractionFlags(Qt::TextEditorInteraction); QVERIFY(!text->hasFocus()); text->setFocus(); QVERIFY(!text->hasFocus()); QCOMPARE(text->focusItem(), (QGraphicsItem *)text); // Add a sibling. QGraphicsTextItem *text2 = new QGraphicsTextItem("Hi"); text2->setTextInteractionFlags(Qt::TextEditorInteraction); text2->setPos(30, 30); // Add both items to a scene and check that it's text that // got input focus. QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); scene.addItem(text); scene.addItem(text2); QVERIFY(text->hasFocus()); text->setData(0, "text"); text2->setData(0, "text2"); // Remove text2 and set subfocus on it. Then readd. Reparent it onto the // other item and see that it gains input focus. scene.removeItem(text2); text2->setFocus(); scene.addItem(text2); QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2); text2->setParentItem(text); QCOMPARE(text->focusItem(), (QGraphicsItem *)text2); QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2); QVERIFY(!text->hasFocus()); QVERIFY(text2->hasFocus()); // Remove both items from the scene, restore subfocus and // readd them. Now the subfocus should kick in and give // text2 focus. scene.removeItem(text); QCOMPARE(text->focusItem(), (QGraphicsItem *)0); QCOMPARE(text2->focusItem(), (QGraphicsItem *)0); text2->setFocus(); QCOMPARE(text->focusItem(), (QGraphicsItem *)text2); QCOMPARE(text2->focusItem(), (QGraphicsItem *)text2); scene.addItem(text); // Hiding and showing text should pass focus to text2. QCOMPARE(text->focusItem(), (QGraphicsItem *)text2); QVERIFY(text2->hasFocus()); // Subfocus should repropagate to root when reparenting. QGraphicsRectItem *rect = new QGraphicsRectItem; QGraphicsRectItem *rect2 = new QGraphicsRectItem(rect); QGraphicsRectItem *rect3 = new QGraphicsRectItem(rect2); rect3->setFlag(QGraphicsItem::ItemIsFocusable); text->setData(0, "text"); text2->setData(0, "text2"); rect->setData(0, "rect"); rect2->setData(0, "rect2"); rect3->setData(0, "rect3"); rect3->setFocus(); QVERIFY(!rect3->hasFocus()); QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3); QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3); QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3); rect->setParentItem(text2); QCOMPARE(text->focusItem(), (QGraphicsItem *)rect3); QCOMPARE(text2->focusItem(), (QGraphicsItem *)rect3); QCOMPARE(rect->focusItem(), (QGraphicsItem *)rect3); QCOMPARE(rect2->focusItem(), (QGraphicsItem *)rect3); QCOMPARE(rect3->focusItem(), (QGraphicsItem *)rect3); QVERIFY(!rect->hasFocus()); QVERIFY(!rect2->hasFocus()); QVERIFY(rect3->hasFocus()); delete rect2; QCOMPARE(text->focusItem(), (QGraphicsItem *)0); QCOMPARE(text2->focusItem(), (QGraphicsItem *)0); QCOMPARE(rect->focusItem(), (QGraphicsItem *)0); } void tst_QGraphicsItem::focusProxyDeletion() { QGraphicsRectItem *rect = new QGraphicsRectItem; QGraphicsRectItem *rect2 = new QGraphicsRectItem; rect->setFocusProxy(rect2); QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2); delete rect2; QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0); rect2 = new QGraphicsRectItem; rect->setFocusProxy(rect2); delete rect; // don't crash rect = new QGraphicsRectItem; rect->setFocusProxy(rect2); QGraphicsScene *scene = new QGraphicsScene; scene->addItem(rect); scene->addItem(rect2); delete rect2; QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0); rect2 = new QGraphicsRectItem; QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::setFocusProxy: focus proxy must be in same scene"); rect->setFocusProxy(rect2); QCOMPARE(rect->focusProxy(), (QGraphicsItem *)0); scene->addItem(rect2); rect->setFocusProxy(rect2); QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2); delete rect; // don't crash rect = new QGraphicsRectItem; rect2 = new QGraphicsRectItem; rect->setFocusProxy(rect2); QCOMPARE(rect->focusProxy(), (QGraphicsItem *)rect2); scene->addItem(rect); scene->addItem(rect2); rect->setFocusProxy(rect2); delete scene; // don't crash } void tst_QGraphicsItem::negativeZStacksBehindParent() { QGraphicsRectItem rect; QCOMPARE(rect.zValue(), qreal(0.0)); QVERIFY(!(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent)); QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent)); rect.setZValue(-1); QCOMPARE(rect.zValue(), qreal(-1.0)); QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent)); rect.setZValue(0); rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent); QVERIFY(rect.flags() & QGraphicsItem::ItemNegativeZStacksBehindParent); QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent)); rect.setZValue(-1); QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent); rect.setZValue(0); QVERIFY(!(rect.flags() & QGraphicsItem::ItemStacksBehindParent)); rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false); rect.setZValue(-1); rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, true); QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent); rect.setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent, false); QVERIFY(rect.flags() & QGraphicsItem::ItemStacksBehindParent); } void tst_QGraphicsItem::setGraphicsEffect() { // Check that we don't have any effect by default. QGraphicsItem *item = new QGraphicsRectItem(0, 0, 10, 10); QVERIFY(!item->graphicsEffect()); // SetGet check. QPointer blurEffect = new QGraphicsBlurEffect; item->setGraphicsEffect(blurEffect); QCOMPARE(item->graphicsEffect(), static_cast(blurEffect)); // Ensure the existing effect is deleted when setting a new one. QPointer shadowEffect = new QGraphicsDropShadowEffect; item->setGraphicsEffect(shadowEffect); QVERIFY(!blurEffect); QCOMPARE(item->graphicsEffect(), static_cast(shadowEffect)); blurEffect = new QGraphicsBlurEffect; // Ensure the effect is uninstalled when setting it on a new target. QGraphicsItem *anotherItem = new QGraphicsRectItem(0, 0, 10, 10); anotherItem->setGraphicsEffect(blurEffect); item->setGraphicsEffect(blurEffect); QVERIFY(!anotherItem->graphicsEffect()); QVERIFY(!shadowEffect); // Ensure the existing effect is deleted when deleting the item. delete item; QVERIFY(!blurEffect); delete anotherItem; // Ensure the effect is uninstalled when deleting it item = new QGraphicsRectItem(0, 0, 10, 10); blurEffect = new QGraphicsBlurEffect; item->setGraphicsEffect(blurEffect); delete blurEffect; QVERIFY(!item->graphicsEffect()); // Ensure the existing effect is uninstalled and deleted when setting a null effect blurEffect = new QGraphicsBlurEffect; item->setGraphicsEffect(blurEffect); item->setGraphicsEffect(0); QVERIFY(!item->graphicsEffect()); QVERIFY(!blurEffect); delete item; } void tst_QGraphicsItem::panel() { QGraphicsScene scene; QGraphicsRectItem *panel1 = new QGraphicsRectItem; QGraphicsRectItem *panel2 = new QGraphicsRectItem; QGraphicsRectItem *panel3 = new QGraphicsRectItem; QGraphicsRectItem *panel4 = new QGraphicsRectItem; QGraphicsRectItem *notPanel1 = new QGraphicsRectItem; QGraphicsRectItem *notPanel2 = new QGraphicsRectItem; panel1->setFlag(QGraphicsItem::ItemIsPanel); panel2->setFlag(QGraphicsItem::ItemIsPanel); panel3->setFlag(QGraphicsItem::ItemIsPanel); panel4->setFlag(QGraphicsItem::ItemIsPanel); scene.addItem(panel1); scene.addItem(panel2); scene.addItem(panel3); scene.addItem(panel4); scene.addItem(notPanel1); scene.addItem(notPanel2); EventSpy spy_activate_panel1(&scene, panel1, QEvent::WindowActivate); EventSpy spy_deactivate_panel1(&scene, panel1, QEvent::WindowDeactivate); EventSpy spy_activate_panel2(&scene, panel2, QEvent::WindowActivate); EventSpy spy_deactivate_panel2(&scene, panel2, QEvent::WindowDeactivate); EventSpy spy_activate_panel3(&scene, panel3, QEvent::WindowActivate); EventSpy spy_deactivate_panel3(&scene, panel3, QEvent::WindowDeactivate); EventSpy spy_activate_panel4(&scene, panel4, QEvent::WindowActivate); EventSpy spy_deactivate_panel4(&scene, panel4, QEvent::WindowDeactivate); EventSpy spy_activate_notPanel1(&scene, notPanel1, QEvent::WindowActivate); EventSpy spy_deactivate_notPanel1(&scene, notPanel1, QEvent::WindowDeactivate); EventSpy spy_activate_notPanel2(&scene, notPanel1, QEvent::WindowActivate); EventSpy spy_deactivate_notPanel2(&scene, notPanel1, QEvent::WindowDeactivate); QCOMPARE(spy_activate_panel1.count(), 0); QCOMPARE(spy_deactivate_panel1.count(), 0); QCOMPARE(spy_activate_panel2.count(), 0); QCOMPARE(spy_deactivate_panel2.count(), 0); QCOMPARE(spy_activate_panel3.count(), 0); QCOMPARE(spy_deactivate_panel3.count(), 0); QCOMPARE(spy_activate_panel4.count(), 0); QCOMPARE(spy_deactivate_panel4.count(), 0); QCOMPARE(spy_activate_notPanel1.count(), 0); QCOMPARE(spy_deactivate_notPanel1.count(), 0); QCOMPARE(spy_activate_notPanel2.count(), 0); QCOMPARE(spy_deactivate_notPanel2.count(), 0); QVERIFY(!scene.activePanel()); QVERIFY(!scene.isActive()); QEvent activate(QEvent::WindowActivate); QEvent deactivate(QEvent::WindowDeactivate); QApplication::sendEvent(&scene, &activate); // No previous activation, so the scene is active. QVERIFY(scene.isActive()); QCOMPARE(scene.activePanel(), (QGraphicsItem *)panel1); QVERIFY(panel1->isActive()); QVERIFY(!panel2->isActive()); QVERIFY(!panel3->isActive()); QVERIFY(!panel4->isActive()); QVERIFY(!notPanel1->isActive()); QVERIFY(!notPanel2->isActive()); QCOMPARE(spy_deactivate_notPanel1.count(), 0); QCOMPARE(spy_deactivate_notPanel2.count(), 0); QCOMPARE(spy_activate_panel1.count(), 1); QCOMPARE(spy_activate_panel2.count(), 0); QCOMPARE(spy_activate_panel3.count(), 0); QCOMPARE(spy_activate_panel4.count(), 0); // Switch back to scene. scene.setActivePanel(0); QVERIFY(!scene.activePanel()); QVERIFY(!panel1->isActive()); QVERIFY(!panel2->isActive()); QVERIFY(!panel3->isActive()); QVERIFY(!panel4->isActive()); QVERIFY(notPanel1->isActive()); QVERIFY(notPanel2->isActive()); QCOMPARE(spy_activate_notPanel1.count(), 1); QCOMPARE(spy_activate_notPanel2.count(), 1); // Deactivate the scene QApplication::sendEvent(&scene, &deactivate); QVERIFY(!scene.activePanel()); QVERIFY(!panel1->isActive()); QVERIFY(!panel2->isActive()); QVERIFY(!panel3->isActive()); QVERIFY(!panel4->isActive()); QVERIFY(!notPanel1->isActive()); QVERIFY(!notPanel2->isActive()); QCOMPARE(spy_deactivate_notPanel1.count(), 1); QCOMPARE(spy_deactivate_notPanel2.count(), 1); // Reactivate the scene QApplication::sendEvent(&scene, &activate); QVERIFY(!scene.activePanel()); QVERIFY(!panel1->isActive()); QVERIFY(!panel2->isActive()); QVERIFY(!panel3->isActive()); QVERIFY(!panel4->isActive()); QVERIFY(notPanel1->isActive()); QVERIFY(notPanel2->isActive()); QCOMPARE(spy_activate_notPanel1.count(), 2); QCOMPARE(spy_activate_notPanel2.count(), 2); // Switch to panel1 scene.setActivePanel(panel1); QVERIFY(panel1->isActive()); QCOMPARE(spy_deactivate_notPanel1.count(), 2); QCOMPARE(spy_deactivate_notPanel2.count(), 2); QCOMPARE(spy_activate_panel1.count(), 2); // Deactivate the scene QApplication::sendEvent(&scene, &deactivate); QVERIFY(!panel1->isActive()); QCOMPARE(spy_deactivate_panel1.count(), 2); // Reactivate the scene QApplication::sendEvent(&scene, &activate); QVERIFY(panel1->isActive()); QCOMPARE(spy_activate_panel1.count(), 3); // Deactivate the scene QApplication::sendEvent(&scene, &deactivate); QVERIFY(!panel1->isActive()); QVERIFY(!scene.activePanel()); scene.setActivePanel(0); // Reactivate the scene QApplication::sendEvent(&scene, &activate); QVERIFY(!panel1->isActive()); } void tst_QGraphicsItem::panelWithFocusItem() { QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); QGraphicsRectItem *parentPanel = new QGraphicsRectItem; QGraphicsRectItem *parentPanelFocusItem = new QGraphicsRectItem(parentPanel); parentPanel->setFlag(QGraphicsItem::ItemIsPanel); parentPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable); parentPanelFocusItem->setFocus(); scene.addItem(parentPanel); QVERIFY(parentPanel->isActive()); QVERIFY(parentPanelFocusItem->hasFocus()); QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem); QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem); QGraphicsRectItem *childPanel = new QGraphicsRectItem; QGraphicsRectItem *childPanelFocusItem = new QGraphicsRectItem(childPanel); childPanel->setFlag(QGraphicsItem::ItemIsPanel); childPanelFocusItem->setFlag(QGraphicsItem::ItemIsFocusable); childPanelFocusItem->setFocus(); QVERIFY(!childPanelFocusItem->hasFocus()); QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem); QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem); childPanel->setParentItem(parentPanel); QVERIFY(!parentPanel->isActive()); QVERIFY(!parentPanelFocusItem->hasFocus()); QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem); QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem); QVERIFY(childPanel->isActive()); QVERIFY(childPanelFocusItem->hasFocus()); QCOMPARE(childPanel->focusItem(), (QGraphicsItem *)childPanelFocusItem); QCOMPARE(childPanelFocusItem->focusItem(), (QGraphicsItem *)childPanelFocusItem); childPanel->hide(); QVERIFY(parentPanel->isActive()); QVERIFY(parentPanelFocusItem->hasFocus()); QCOMPARE(parentPanel->focusItem(), (QGraphicsItem *)parentPanelFocusItem); QCOMPARE(parentPanelFocusItem->focusItem(), (QGraphicsItem *)parentPanelFocusItem); } void tst_QGraphicsItem::addPanelToActiveScene() { QGraphicsScene scene; QVERIFY(!scene.isActive()); QGraphicsRectItem *rect = new QGraphicsRectItem; scene.addItem(rect); QVERIFY(!rect->isActive()); scene.removeItem(rect); QEvent activate(QEvent::WindowActivate); QEvent deactivate(QEvent::WindowDeactivate); QApplication::sendEvent(&scene, &activate); QVERIFY(scene.isActive()); scene.addItem(rect); QVERIFY(rect->isActive()); scene.removeItem(rect); rect->setFlag(QGraphicsItem::ItemIsPanel); scene.addItem(rect); QVERIFY(rect->isActive()); QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect); QGraphicsRectItem *rect2 = new QGraphicsRectItem; scene.addItem(rect2); QVERIFY(rect->isActive()); QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect); } void tst_QGraphicsItem::activate() { QGraphicsScene scene; QGraphicsRectItem *rect = scene.addRect(-10, -10, 20, 20); QVERIFY(!rect->isActive()); QEvent activate(QEvent::WindowActivate); QEvent deactivate(QEvent::WindowDeactivate); QApplication::sendEvent(&scene, &activate); // Non-panel item (active when scene is active). QVERIFY(rect->isActive()); QGraphicsRectItem *rect2 = new QGraphicsRectItem; rect2->setFlag(QGraphicsItem::ItemIsPanel); QGraphicsRectItem *rect3 = new QGraphicsRectItem; rect3->setFlag(QGraphicsItem::ItemIsPanel); // Test normal activation. QVERIFY(!rect2->isActive()); scene.addItem(rect2); QVERIFY(rect2->isActive()); // first panel item is activated scene.addItem(rect3); QVERIFY(!rect3->isActive()); // second panel item is _not_ activated rect3->setActive(true); QVERIFY(rect3->isActive()); scene.removeItem(rect3); QVERIFY(!rect3->isActive()); // no panel is active anymore QCOMPARE(scene.activePanel(), (QGraphicsItem *)0); scene.addItem(rect3); QVERIFY(rect3->isActive()); // second panel item is activated // Test pending activation. scene.removeItem(rect3); rect2->setActive(true); QVERIFY(rect2->isActive()); // first panel item is activated rect3->setActive(true); QVERIFY(!rect3->isActive()); // not active (yet) scene.addItem(rect3); QVERIFY(rect3->isActive()); // now becomes active // Test pending deactivation. scene.removeItem(rect3); rect3->setActive(false); scene.addItem(rect3); QVERIFY(!rect3->isActive()); // doesn't become active // Child of panel activation. rect3->setActive(true); QGraphicsRectItem *rect4 = new QGraphicsRectItem; rect4->setFlag(QGraphicsItem::ItemIsPanel); QGraphicsRectItem *rect5 = new QGraphicsRectItem(rect4); QGraphicsRectItem *rect6 = new QGraphicsRectItem(rect5); scene.addItem(rect4); QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect3); scene.removeItem(rect4); rect6->setActive(true); scene.addItem(rect4); QVERIFY(rect4->isActive()); QVERIFY(rect5->isActive()); QVERIFY(rect6->isActive()); QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect4); scene.removeItem(rect4); // no active panel rect6->setActive(false); scene.addItem(rect4); QVERIFY(!rect4->isActive()); QVERIFY(!rect5->isActive()); QVERIFY(!rect6->isActive()); QCOMPARE(scene.activePanel(), (QGraphicsItem *)0); // Controlling auto-activation when the scene changes activation. rect4->setActive(true); QApplication::sendEvent(&scene, &deactivate); QVERIFY(!scene.isActive()); QVERIFY(!rect4->isActive()); rect4->setActive(false); QApplication::sendEvent(&scene, &activate); QVERIFY(scene.isActive()); QVERIFY(!scene.activePanel()); QVERIFY(!rect4->isActive()); } void tst_QGraphicsItem::setActivePanelOnInactiveScene() { QGraphicsScene scene; QGraphicsRectItem *item = scene.addRect(QRectF()); QGraphicsRectItem *panel = scene.addRect(QRectF()); panel->setFlag(QGraphicsItem::ItemIsPanel); EventSpy itemActivateSpy(&scene, item, QEvent::WindowActivate); EventSpy itemDeactivateSpy(&scene, item, QEvent::WindowDeactivate); EventSpy panelActivateSpy(&scene, panel, QEvent::WindowActivate); EventSpy panelDeactivateSpy(&scene, panel, QEvent::WindowDeactivate); EventSpy sceneActivationChangeSpy(&scene, QEvent::ActivationChange); scene.setActivePanel(panel); QCOMPARE(scene.activePanel(), (QGraphicsItem *)0); QCOMPARE(itemActivateSpy.count(), 0); QCOMPARE(itemDeactivateSpy.count(), 0); QCOMPARE(panelActivateSpy.count(), 0); QCOMPARE(panelDeactivateSpy.count(), 0); QCOMPARE(sceneActivationChangeSpy.count(), 0); } void tst_QGraphicsItem::activationOnShowHide() { QGraphicsScene scene; QEvent activate(QEvent::WindowActivate); QApplication::sendEvent(&scene, &activate); QGraphicsRectItem *rootPanel = scene.addRect(QRectF()); rootPanel->setFlag(QGraphicsItem::ItemIsPanel); rootPanel->setActive(true); QGraphicsRectItem *subPanel = new QGraphicsRectItem; subPanel->setFlag(QGraphicsItem::ItemIsPanel); // Reparenting onto an active panel auto-activates the child panel. subPanel->setParentItem(rootPanel); QVERIFY(subPanel->isActive()); QVERIFY(!rootPanel->isActive()); // Hiding an active child panel will reactivate the parent panel. subPanel->hide(); QVERIFY(rootPanel->isActive()); // Showing a child panel will auto-activate it. subPanel->show(); QVERIFY(subPanel->isActive()); QVERIFY(!rootPanel->isActive()); // Adding an unrelated panel doesn't affect activation. QGraphicsRectItem *otherPanel = new QGraphicsRectItem; otherPanel->setFlag(QGraphicsItem::ItemIsPanel); scene.addItem(otherPanel); QVERIFY(subPanel->isActive()); // Showing an unrelated panel doesn't affect activation. otherPanel->hide(); otherPanel->show(); QVERIFY(subPanel->isActive()); // Add a non-panel item. QGraphicsRectItem *otherItem = new QGraphicsRectItem; scene.addItem(otherItem); otherItem->setActive(true); QVERIFY(otherItem->isActive()); // Reparent a panel onto an active non-panel item. subPanel->setParentItem(otherItem); QVERIFY(subPanel->isActive()); // Showing a child panel of a non-panel item will activate it. subPanel->hide(); QVERIFY(!subPanel->isActive()); QVERIFY(otherItem->isActive()); subPanel->show(); QVERIFY(subPanel->isActive()); // Hiding a toplevel active panel will pass activation back // to the non-panel items. rootPanel->setActive(true); rootPanel->hide(); QVERIFY(!rootPanel->isActive()); QVERIFY(otherItem->isActive()); } class MoveWhileDying : public QGraphicsRectItem { public: MoveWhileDying(QGraphicsItem *parent = 0) : QGraphicsRectItem(parent) { } ~MoveWhileDying() { foreach (QGraphicsItem *c, childItems()) { foreach (QGraphicsItem *cc, c->childItems()) { cc->moveBy(10, 10); } c->moveBy(10, 10); } if (QGraphicsItem *p = parentItem()) { p->moveBy(10, 10); } } }; void tst_QGraphicsItem::moveWhileDeleting() { QGraphicsScene scene; QGraphicsRectItem *rect = new QGraphicsRectItem; MoveWhileDying *silly = new MoveWhileDying(rect); QGraphicsRectItem *child = new QGraphicsRectItem(silly); scene.addItem(rect); delete rect; // don't crash! rect = new QGraphicsRectItem; silly = new MoveWhileDying(rect); child = new QGraphicsRectItem(silly); QGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif QTest::qWait(125); delete rect; rect = new QGraphicsRectItem; rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape); silly = new MoveWhileDying(rect); child = new QGraphicsRectItem(silly); QTest::qWait(125); delete rect; rect = new MoveWhileDying; rect->setFlag(QGraphicsItem::ItemClipsChildrenToShape); child = new QGraphicsRectItem(rect); silly = new MoveWhileDying(child); QTest::qWait(125); delete rect; } class MyRectItem : public QGraphicsWidget { Q_OBJECT public: MyRectItem(QGraphicsItem *parent = 0) : QGraphicsWidget(parent) { } void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->setBrush(brush); painter->drawRect(boundingRect()); } void move() { setPos(-100,-100); topLevel->collidingItems(Qt::IntersectsItemBoundingRect); } public: QGraphicsItem *topLevel; QBrush brush; }; void tst_QGraphicsItem::ensureDirtySceneTransform() { QGraphicsScene scene; MyRectItem *topLevel = new MyRectItem; topLevel->setGeometry(0, 0, 100, 100); topLevel->setPos(-50, -50); topLevel->brush = QBrush(QColor(Qt::black)); scene.addItem(topLevel); MyRectItem *parent = new MyRectItem; parent->topLevel = topLevel; parent->setGeometry(0, 0, 100, 100); parent->setPos(0, 0); parent->brush = QBrush(QColor(Qt::magenta)); parent->setObjectName("parent"); scene.addItem(parent); MyRectItem *child = new MyRectItem(parent); child->setGeometry(0, 0, 80, 80); child->setPos(10, 10); child->setObjectName("child"); child->brush = QBrush(QColor(Qt::blue)); MyRectItem *child2 = new MyRectItem(parent); child2->setGeometry(0, 0, 80, 80); child2->setPos(15, 15); child2->setObjectName("child2"); child2->brush = QBrush(QColor(Qt::green)); MyRectItem *child3 = new MyRectItem(parent); child3->setGeometry(0, 0, 80, 80); child3->setPos(20, 20); child3->setObjectName("child3"); child3->brush = QBrush(QColor(Qt::gray)); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTRY_COMPARE(QApplication::activeWindow(), static_cast(&view)); //We move the parent parent->move(); QApplication::processEvents(); //We check if all items moved QCOMPARE(child->pos(), QPointF(10, 10)); QCOMPARE(child2->pos(), QPointF(15, 15)); QCOMPARE(child3->pos(), QPointF(20, 20)); QCOMPARE(child->sceneBoundingRect(), QRectF(-90, -90, 80, 80)); QCOMPARE(child2->sceneBoundingRect(), QRectF(-85, -85, 80, 80)); QCOMPARE(child3->sceneBoundingRect(), QRectF(-80, -80, 80, 80)); QCOMPARE(child->sceneTransform(), QTransform::fromTranslate(-90, -90)); QCOMPARE(child2->sceneTransform(), QTransform::fromTranslate(-85, -85)); QCOMPARE(child3->sceneTransform(), QTransform::fromTranslate(-80, -80)); } void tst_QGraphicsItem::focusScope() { // ItemIsFocusScope is an internal feature (for now). QGraphicsScene scene; QGraphicsRectItem *scope3 = new QGraphicsRectItem; scope3->setData(0, "scope3"); scope3->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); scope3->setFocus(); QVERIFY(!scope3->focusScopeItem()); QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3); QGraphicsRectItem *scope2 = new QGraphicsRectItem; scope2->setData(0, "scope2"); scope2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); scope2->setFocus(); QVERIFY(!scope2->focusScopeItem()); scope3->setParentItem(scope2); QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3); QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3); QGraphicsRectItem *scope1 = new QGraphicsRectItem; scope1->setData(0, "scope1"); scope1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); scope1->setFocus(); QVERIFY(!scope1->focusScopeItem()); scope2->setParentItem(scope1); QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3); QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3); QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3); QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2); QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3); QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0); scene.addItem(scope1); QEvent windowActivate(QEvent::WindowActivate); qApp->sendEvent(&scene, &windowActivate); scene.setFocus(); QCOMPARE(scope1->focusItem(), (QGraphicsItem *)scope3); QCOMPARE(scope2->focusItem(), (QGraphicsItem *)scope3); QCOMPARE(scope3->focusItem(), (QGraphicsItem *)scope3); QCOMPARE(scope1->focusScopeItem(), (QGraphicsItem *)scope2); QCOMPARE(scope2->focusScopeItem(), (QGraphicsItem *)scope3); QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0); QVERIFY(scope3->hasFocus()); scope3->hide(); QVERIFY(scope2->hasFocus()); scope2->hide(); QVERIFY(scope1->hasFocus()); scope2->show(); QVERIFY(scope2->hasFocus()); scope3->show(); QVERIFY(scope3->hasFocus()); scope1->hide(); QVERIFY(!scope3->hasFocus()); scope1->show(); QVERIFY(scope3->hasFocus()); scope3->clearFocus(); QVERIFY(scope2->hasFocus()); scope2->clearFocus(); QVERIFY(scope1->hasFocus()); scope2->hide(); scope2->show(); QVERIFY(!scope2->hasFocus()); QVERIFY(scope1->hasFocus()); scope2->setFocus(); QVERIFY(scope2->hasFocus()); scope3->setFocus(); QVERIFY(scope3->hasFocus()); QGraphicsRectItem *rect4 = new QGraphicsRectItem; rect4->setData(0, "rect4"); rect4->setParentItem(scope3); QGraphicsRectItem *rect5 = new QGraphicsRectItem; rect5->setData(0, "rect5"); rect5->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); rect5->setFocus(); rect5->setParentItem(rect4); QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)rect5); QVERIFY(rect5->hasFocus()); rect4->setParentItem(0); QVERIFY(rect5->hasFocus()); QCOMPARE(scope3->focusScopeItem(), (QGraphicsItem *)0); QCOMPARE(scope3->focusItem(), (QGraphicsItem *)0); QVERIFY(!scope3->hasFocus()); QGraphicsRectItem *rectA = new QGraphicsRectItem; QGraphicsRectItem *scopeA = new QGraphicsRectItem(rectA); scopeA->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); scopeA->setFocus(); QGraphicsRectItem *scopeB = new QGraphicsRectItem(scopeA); scopeB->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); scopeB->setFocus(); scene.addItem(rectA); QVERIFY(rect5->hasFocus()); QVERIFY(!scopeB->hasFocus()); scopeA->setFocus(); QVERIFY(scopeB->hasFocus()); QCOMPARE(scopeB->focusItem(), (QGraphicsItem *)scopeB); } void tst_QGraphicsItem::focusScope2() { QGraphicsRectItem *child1 = new QGraphicsRectItem; child1->setFlags(QGraphicsItem::ItemIsFocusable); child1->setFocus(); QCOMPARE(child1->focusItem(), (QGraphicsItem *)child1); QGraphicsRectItem *child2 = new QGraphicsRectItem; child2->setFlags(QGraphicsItem::ItemIsFocusable); QGraphicsRectItem *rootFocusScope = new QGraphicsRectItem; rootFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); rootFocusScope->setFocus(); QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)rootFocusScope); child1->setParentItem(rootFocusScope); child2->setParentItem(rootFocusScope); QCOMPARE(rootFocusScope->focusScopeItem(), (QGraphicsItem *)child1); QCOMPARE(rootFocusScope->focusItem(), (QGraphicsItem *)child1); QGraphicsRectItem *siblingChild1 = new QGraphicsRectItem; siblingChild1->setFlags(QGraphicsItem::ItemIsFocusable); siblingChild1->setFocus(); QGraphicsRectItem *siblingChild2 = new QGraphicsRectItem; siblingChild2->setFlags(QGraphicsItem::ItemIsFocusable); QGraphicsRectItem *siblingFocusScope = new QGraphicsRectItem; siblingFocusScope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); siblingChild1->setParentItem(siblingFocusScope); siblingChild2->setParentItem(siblingFocusScope); QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild1); QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0); QGraphicsItem *root = new QGraphicsRectItem; rootFocusScope->setParentItem(root); siblingFocusScope->setParentItem(root); QCOMPARE(root->focusItem(), (QGraphicsItem *)child1); QGraphicsScene scene; scene.addItem(root); QEvent activate(QEvent::WindowActivate); qApp->sendEvent(&scene, &activate); scene.setFocus(); QCOMPARE(scene.focusItem(), (QGraphicsItem *)child1); // You cannot set focus on a descendant of a focus scope directly; // this will only change the scope's focus scope item pointer. If // you want to give true input focus, you must set it directly on // the scope itself siblingChild2->setFocus(); QVERIFY(!siblingChild2->hasFocus()); QVERIFY(!siblingChild2->focusItem()); QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2); QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)0); // Set focus on the scope; focus is forwarded to the focus scope item. siblingFocusScope->setFocus(); QVERIFY(siblingChild2->hasFocus()); QVERIFY(siblingChild2->focusItem()); QCOMPARE(siblingFocusScope->focusScopeItem(), (QGraphicsItem *)siblingChild2); QCOMPARE(siblingFocusScope->focusItem(), (QGraphicsItem *)siblingChild2); } void tst_QGraphicsItem::stackBefore() { QGraphicsRectItem parent; QGraphicsRectItem *child1 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent); QGraphicsRectItem *child2 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent); QGraphicsRectItem *child3 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent); QGraphicsRectItem *child4 = new QGraphicsRectItem(QRectF(0, 0, 5, 5), &parent); QCOMPARE(parent.childItems(), (QList() << child1 << child2 << child3 << child4)); child1->setData(0, "child1"); child2->setData(0, "child2"); child3->setData(0, "child3"); child4->setData(0, "child4"); // Remove and append child2->setParentItem(0); child2->setParentItem(&parent); QCOMPARE(parent.childItems(), (QList() << child1 << child3 << child4 << child2)); // Move child2 before child1 child2->stackBefore(child1); // 2134 QCOMPARE(parent.childItems(), (QList() << child2 << child1 << child3 << child4)); child2->stackBefore(child2); // 2134 QCOMPARE(parent.childItems(), (QList() << child2 << child1 << child3 << child4)); child1->setZValue(1); // 2341 QCOMPARE(parent.childItems(), (QList() << child2 << child3 << child4 << child1)); child1->stackBefore(child2); // 2341 QCOMPARE(parent.childItems(), (QList() << child2 << child3 << child4 << child1)); child1->setZValue(0); // 1234 QCOMPARE(parent.childItems(), (QList() << child1 << child2 << child3 << child4)); child4->stackBefore(child1); // 4123 QCOMPARE(parent.childItems(), (QList() << child4 << child1 << child2 << child3)); child4->setZValue(1); // 1234 (4123) QCOMPARE(parent.childItems(), (QList() << child1 << child2 << child3 << child4)); child3->stackBefore(child1); // 3124 (4312) QCOMPARE(parent.childItems(), (QList() << child3 << child1 << child2 << child4)); child4->setZValue(0); // 4312 QCOMPARE(parent.childItems(), (QList() << child4 << child3 << child1 << child2)); // Make them all toplevels child1->setParentItem(0); child2->setParentItem(0); child3->setParentItem(0); child4->setParentItem(0); QGraphicsScene scene; scene.addItem(child1); scene.addItem(child2); scene.addItem(child3); scene.addItem(child4); QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child1 << child2 << child3 << child4)); // Remove and append scene.removeItem(child2); scene.addItem(child2); QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child1 << child3 << child4 << child2)); // Move child2 before child1 child2->stackBefore(child1); // 2134 QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child2 << child1 << child3 << child4)); child2->stackBefore(child2); // 2134 QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child2 << child1 << child3 << child4)); child1->setZValue(1); // 2341 QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child2 << child3 << child4 << child1)); child1->stackBefore(child2); // 2341 QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child2 << child3 << child4 << child1)); child1->setZValue(0); // 1234 QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child1 << child2 << child3 << child4)); child4->stackBefore(child1); // 4123 QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child4 << child1 << child2 << child3)); child4->setZValue(1); // 1234 (4123) QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child1 << child2 << child3 << child4)); child3->stackBefore(child1); // 3124 (4312) QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child3 << child1 << child2 << child4)); child4->setZValue(0); // 4312 QCOMPARE(scene.items(QPointF(2, 2), Qt::IntersectsItemBoundingRect, Qt::AscendingOrder), (QList() << child4 << child3 << child1 << child2)); } void tst_QGraphicsItem::QTBUG_4233_updateCachedWithSceneRect() { EventTester *tester = new EventTester; tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); QGraphicsScene scene; scene.addItem(tester); scene.setSceneRect(-100, -100, 200, 200); // contains the tester item QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view); QTRY_COMPARE(tester->repaints, 1); scene.update(); // triggers "updateAll" optimization qApp->processEvents(); qApp->processEvents(); // in 4.6 only one processEvents is necessary QCOMPARE(tester->repaints, 1); scene.update(); // triggers "updateAll" optimization tester->update(); qApp->processEvents(); qApp->processEvents(); // in 4.6 only one processEvents is necessary QCOMPARE(tester->repaints, 2); } void tst_QGraphicsItem::sceneModality() { // 1) Test mouse events (delivery/propagation/redirection) // 2) Test hover events (incl. leave on block, enter on unblock) // 3) Test cursor stuff (incl. unset on block, set on unblock) // 4) Test clickfocus // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock) // 6) ### modality for non-panels is unsupported for now QGraphicsScene scene; QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200); bottomItem->setFlag(QGraphicsItem::ItemIsFocusable); bottomItem->setBrush(Qt::yellow); QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100); leftParent->setFlag(QGraphicsItem::ItemIsPanel); leftParent->setBrush(Qt::blue); QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50); leftChild->setFlag(QGraphicsItem::ItemIsPanel); leftChild->setBrush(Qt::green); leftChild->setParentItem(leftParent); QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100); rightParent->setFlag(QGraphicsItem::ItemIsPanel); rightParent->setBrush(Qt::red); QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50); rightChild->setFlag(QGraphicsItem::ItemIsPanel); rightChild->setBrush(Qt::gray); rightChild->setParentItem(rightParent); leftParent->setPos(-75, 0); rightParent->setPos(75, 0); bottomItem->setData(0, "bottomItem"); leftParent->setData(0, "leftParent"); leftChild->setData(0, "leftChild"); rightParent->setData(0, "rightParent"); rightChild->setData(0, "rightChild"); scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50)); EventSpy2 leftParentSpy(&scene, leftParent); EventSpy2 leftChildSpy(&scene, leftChild); EventSpy2 rightParentSpy(&scene, rightParent); EventSpy2 rightChildSpy(&scene, rightChild); EventSpy2 bottomItemSpy(&scene, bottomItem); // Scene modality, also test multiple scene modal items leftChild->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // not a panel // Click inside left child sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked // Click on left parent, event goes to modal child sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked // Click on all other items and outside the items sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3); sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4); sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5); sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked leftChildSpy.counts.clear(); rightChildSpy.counts.clear(); leftParentSpy.counts.clear(); rightParentSpy.counts.clear(); bottomItemSpy.counts.clear(); leftChild->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0); // Left parent enters scene modality. leftParent->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // Click inside left child. sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // panel stops propagation QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked // Click on left parent. sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // Click on all other items and outside the items sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton); QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 2); sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton); QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 3); sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton); QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 4); sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton); QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 5); QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); leftChildSpy.counts.clear(); rightChildSpy.counts.clear(); leftParentSpy.counts.clear(); rightParentSpy.counts.clear(); bottomItemSpy.counts.clear(); // Now both left parent and child are scene modal. Left parent is blocked. leftChild->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // Click inside left child sendMouseClick(&scene, leftChild->scenePos(), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked // Click on left parent, event goes to modal child sendMouseClick(&scene, leftParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 2); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked // Click on all other items and outside the items sendMouseClick(&scene, rightParent->sceneBoundingRect().topLeft() + QPointF(5, 5), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 3); sendMouseClick(&scene, rightChild->scenePos(), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 4); sendMouseClick(&scene, bottomItem->scenePos(), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 5); sendMouseClick(&scene, QPointF(10000, 10000), Qt::LeftButton); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMousePress], 6); QCOMPARE(leftChildSpy.counts[QEvent::GraphicsSceneMouseRelease], 0); // no grab QCOMPARE(leftParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightParentSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(rightChildSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked QCOMPARE(bottomItemSpy.counts[QEvent::GraphicsSceneMousePress], 0); // blocked leftChildSpy.counts.clear(); rightChildSpy.counts.clear(); leftParentSpy.counts.clear(); rightParentSpy.counts.clear(); bottomItemSpy.counts.clear(); // Right child enters scene modality, only left child is blocked. rightChild->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); } void tst_QGraphicsItem::panelModality() { // 1) Test mouse events (delivery/propagation/redirection) // 2) Test hover events (incl. leave on block, enter on unblock) // 3) Test cursor stuff (incl. unset on block, set on unblock) // 4) Test clickfocus // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock) // 6) ### modality for non-panels is unsupported for now QGraphicsScene scene; QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200); bottomItem->setFlag(QGraphicsItem::ItemIsFocusable); bottomItem->setBrush(Qt::yellow); QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100); leftParent->setFlag(QGraphicsItem::ItemIsPanel); leftParent->setBrush(Qt::blue); QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50); leftChild->setFlag(QGraphicsItem::ItemIsPanel); leftChild->setBrush(Qt::green); leftChild->setParentItem(leftParent); QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100); rightParent->setFlag(QGraphicsItem::ItemIsPanel); rightParent->setBrush(Qt::red); QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50); rightChild->setFlag(QGraphicsItem::ItemIsPanel); rightChild->setBrush(Qt::gray); rightChild->setParentItem(rightParent); leftParent->setPos(-75, 0); rightParent->setPos(75, 0); bottomItem->setData(0, "bottomItem"); leftParent->setData(0, "leftParent"); leftChild->setData(0, "leftChild"); rightParent->setData(0, "rightParent"); rightChild->setData(0, "rightChild"); scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50)); EventSpy2 leftParentSpy(&scene, leftParent); EventSpy2 leftChildSpy(&scene, leftChild); EventSpy2 rightParentSpy(&scene, rightParent); EventSpy2 rightChildSpy(&scene, rightChild); EventSpy2 bottomItemSpy(&scene, bottomItem); // Left Child enters panel modality, only left parent is blocked. leftChild->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); leftChild->setPanelModality(QGraphicsItem::NonModal); leftChildSpy.counts.clear(); rightChildSpy.counts.clear(); leftParentSpy.counts.clear(); rightParentSpy.counts.clear(); bottomItemSpy.counts.clear(); // Left parent enter panel modality, nothing is blocked. leftParent->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); // Left child enters panel modality, left parent is blocked again. leftChild->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(bottomItemSpy.counts[QEvent::WindowBlocked], 0); leftChildSpy.counts.clear(); rightChildSpy.counts.clear(); leftParentSpy.counts.clear(); rightParentSpy.counts.clear(); bottomItemSpy.counts.clear(); leftChild->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1); leftParent->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(bottomItemSpy.counts[QEvent::WindowUnblocked], 0); leftChildSpy.counts.clear(); rightChildSpy.counts.clear(); leftParentSpy.counts.clear(); rightParentSpy.counts.clear(); bottomItemSpy.counts.clear(); // Left and right child enter panel modality, both parents are blocked. rightChild->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); leftChild->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); } void tst_QGraphicsItem::mixedModality() { // 1) Test mouse events (delivery/propagation/redirection) // 2) Test hover events (incl. leave on block, enter on unblock) // 3) Test cursor stuff (incl. unset on block, set on unblock) // 4) Test clickfocus // 5) Test grab/ungrab events (possibly ungrab on block, regrab on unblock) // 6) ### modality for non-panels is unsupported for now QGraphicsScene scene; QGraphicsRectItem *bottomItem = scene.addRect(-150, -100, 300, 200); bottomItem->setFlag(QGraphicsItem::ItemIsFocusable); bottomItem->setBrush(Qt::yellow); QGraphicsRectItem *leftParent = scene.addRect(-50, -50, 100, 100); leftParent->setFlag(QGraphicsItem::ItemIsPanel); leftParent->setBrush(Qt::blue); QGraphicsRectItem *leftChild = scene.addRect(-25, -25, 50, 50); leftChild->setFlag(QGraphicsItem::ItemIsPanel); leftChild->setBrush(Qt::green); leftChild->setParentItem(leftParent); QGraphicsRectItem *rightParent = scene.addRect(-50, -50, 100, 100); rightParent->setFlag(QGraphicsItem::ItemIsPanel); rightParent->setBrush(Qt::red); QGraphicsRectItem *rightChild = scene.addRect(-25, -25, 50, 50); rightChild->setFlag(QGraphicsItem::ItemIsPanel); rightChild->setBrush(Qt::gray); rightChild->setParentItem(rightParent); leftParent->setPos(-75, 0); rightParent->setPos(75, 0); bottomItem->setData(0, "bottomItem"); leftParent->setData(0, "leftParent"); leftChild->setData(0, "leftChild"); rightParent->setData(0, "rightParent"); rightChild->setData(0, "rightChild"); scene.setSceneRect(scene.itemsBoundingRect().adjusted(-50, -50, 50, 50)); EventSpy2 leftParentSpy(&scene, leftParent); EventSpy2 leftChildSpy(&scene, leftChild); EventSpy2 rightParentSpy(&scene, rightParent); EventSpy2 rightChildSpy(&scene, rightChild); EventSpy2 bottomItemSpy(&scene, bottomItem); // Left Child enters panel modality, only left parent is blocked. leftChild->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 0); // Left parent enters scene modality, which blocks everything except the child. leftParent->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0); // Right child enters panel modality (changes nothing). rightChild->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0); // Left parent leaves modality. Right child is unblocked. leftParent->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 0); QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0); // Right child "upgrades" its modality to scene modal. Left child is blocked. // Right parent is unaffected. rightChild->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0); // "downgrade" right child back to panel modal, left child is unblocked rightChild->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(leftChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftChildSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightChildSpy.counts[QEvent::WindowUnblocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(leftParentSpy.counts[QEvent::WindowUnblocked], 0); QCOMPARE(rightParentSpy.counts[QEvent::WindowBlocked], 1); QCOMPARE(rightParentSpy.counts[QEvent::WindowUnblocked], 0); } void tst_QGraphicsItem::modality_hover() { QGraphicsScene scene; QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100); rect1->setFlag(QGraphicsItem::ItemIsPanel); rect1->setAcceptHoverEvents(true); rect1->setData(0, "rect1"); QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100); rect2->setParentItem(rect1); rect2->setFlag(QGraphicsItem::ItemIsPanel); rect2->setAcceptHoverEvents(true); rect2->setPos(50, 50); rect2->setPanelModality(QGraphicsItem::SceneModal); rect2->setData(0, "rect2"); EventSpy2 rect1Spy(&scene, rect1); EventSpy2 rect2Spy(&scene, rect2); sendMouseMove(&scene, QPointF(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0); sendMouseMove(&scene, QPointF(75, 75)); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 0); sendMouseMove(&scene, QPointF(-25, -25)); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 0); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 0); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 0); rect2->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1); sendMouseMove(&scene, QPointF(75, 75)); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 2); rect2->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2); // changing modality causes a spurious GraphicsSceneHoveMove, even though the mouse didn't // actually move QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3); sendMouseMove(&scene, QPointF(-25, -25)); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1); rect2->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverLeave], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2); rect2->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverEnter], 2); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneHoverMove], 2); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverEnter], 2); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverMove], 3); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneHoverLeave], 2); } void tst_QGraphicsItem::modality_mouseGrabber() { QGraphicsScene scene; QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100); rect1->setFlag(QGraphicsItem::ItemIsPanel); rect1->setFlag(QGraphicsItem::ItemIsMovable); rect1->setData(0, "rect1"); QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100); rect2->setParentItem(rect1); rect2->setFlag(QGraphicsItem::ItemIsPanel); rect2->setFlag(QGraphicsItem::ItemIsMovable); rect2->setPos(50, 50); rect2->setData(0, "rect2"); EventSpy2 rect1Spy(&scene, rect1); EventSpy2 rect2Spy(&scene, rect2); { // pressing mouse on rect1 starts implicit grab sendMousePress(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1); // grab lost when rect1 is modally shadowed rect2->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // releasing goes nowhere sendMouseRelease(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal) sendMouseClick(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); rect2->setPanelModality(QGraphicsItem::NonModal); // pressing mouse on rect1 starts implicit grab sendMousePress(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1); // grab lost to rect2 when rect1 is modally shadowed rect2->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // rect1 does *not* re-grab when rect2 is no longer modal rect2->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // release goes nowhere sendMouseRelease(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); } { // repeat the test using PanelModal rect2->setPanelModality(QGraphicsItem::NonModal); rect1Spy.counts.clear(); rect2Spy.counts.clear(); // pressing mouse on rect1 starts implicit grab sendMousePress(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1); // grab lost when rect1 is modally shadowed rect2->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // releasing goes nowhere sendMouseRelease(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // pressing mouse on rect1 starts implicit grab on rect2 (since it is modal) sendMouseClick(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rect2Spy.counts[QEvent::GraphicsSceneMouseRelease], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); rect2->setPanelModality(QGraphicsItem::NonModal); // pressing mouse on rect1 starts implicit grab sendMousePress(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMousePress], 2); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect1); // grab lost to rect2 when rect1 is modally shadowed rect2->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // rect1 does *not* re-grab when rect2 is no longer modal rect2->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); // release goes nowhere sendMouseRelease(&scene, QPoint(-25, -25)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect1Spy.counts[QEvent::GraphicsSceneMouseRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 2); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); } { // repeat the PanelModal tests, but this time the mouse events will be on a non-modal item, // meaning normal grabbing should work rect2->setPanelModality(QGraphicsItem::NonModal); rect1Spy.counts.clear(); rect2Spy.counts.clear(); QGraphicsRectItem *rect3 = scene.addRect(-50, -50, 100, 100); rect3->setFlag(QGraphicsItem::ItemIsPanel); rect3->setFlag(QGraphicsItem::ItemIsMovable); rect3->setPos(150, 50); rect3->setData(0, "rect3"); EventSpy2 rect3Spy(&scene, rect3); // pressing mouse on rect3 starts implicit grab sendMousePress(&scene, QPoint(150, 50)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMousePress], 1); QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3); // grab is *not* lost when rect1 is modally shadowed by rect2 rect2->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3); // releasing goes to rect3 sendMouseRelease(&scene, QPoint(150, 50)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 1); QCOMPARE(rect3Spy.counts[QEvent::GraphicsSceneMouseRelease], 1); QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); rect2->setPanelModality(QGraphicsItem::NonModal); // pressing mouse on rect3 starts implicit grab sendMousePress(&scene, QPoint(150, 50)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3); // grab is not lost rect2->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3); // grab stays on rect3 rect2->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 1); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) rect3); // release goes to rect3 sendMouseRelease(&scene, QPoint(150, 50)); QCOMPARE(rect1Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect1Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::GrabMouse], 0); QCOMPARE(rect2Spy.counts[QEvent::UngrabMouse], 0); QCOMPARE(rect3Spy.counts[QEvent::GrabMouse], 2); QCOMPARE(rect3Spy.counts[QEvent::UngrabMouse], 2); QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *) 0); } } void tst_QGraphicsItem::modality_clickFocus() { QGraphicsScene scene; QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100); rect1->setFlag(QGraphicsItem::ItemIsPanel); rect1->setFlag(QGraphicsItem::ItemIsFocusable); rect1->setData(0, "rect1"); QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100); rect2->setParentItem(rect1); rect2->setFlag(QGraphicsItem::ItemIsPanel); rect2->setFlag(QGraphicsItem::ItemIsFocusable); rect2->setPos(50, 50); rect2->setData(0, "rect2"); QEvent windowActivateEvent(QEvent::WindowActivate); QApplication::sendEvent(&scene, &windowActivateEvent); EventSpy2 rect1Spy(&scene, rect1); EventSpy2 rect2Spy(&scene, rect2); // activate rect1, it should not get focus rect1->setActive(true); QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0); // focus stays unset when rect2 becomes modal rect2->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0); QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0); QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0); // clicking on rect1 should not set it's focus item sendMouseClick(&scene, QPointF(-25, -25)); QCOMPARE(rect1->focusItem(), (QGraphicsItem *) 0); QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0); QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0); // clicking on rect2 gives it focus rect2->setActive(true); sendMouseClick(&scene, QPointF(75, 75)); QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect2); QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0); QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1); QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 0); // clicking on rect1 does *not* give it focus rect1->setActive(true); sendMouseClick(&scene, QPointF(-25, -25)); QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0); QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0); QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1); QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1); // focus doesn't change when leaving modality either rect2->setPanelModality(QGraphicsItem::NonModal); QCOMPARE(scene.focusItem(), (QGraphicsItem *) 0); QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 0); QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1); QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1); // click on rect1, it should get focus now sendMouseClick(&scene, QPointF(-25, -25)); QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1); QCOMPARE(rect1Spy.counts[QEvent::FocusIn], 1); QCOMPARE(rect1Spy.counts[QEvent::FocusOut], 0); QCOMPARE(rect2Spy.counts[QEvent::FocusIn], 1); QCOMPARE(rect2Spy.counts[QEvent::FocusOut], 1); } void tst_QGraphicsItem::modality_keyEvents() { QGraphicsScene scene; QGraphicsRectItem *rect1 = scene.addRect(-50, -50, 100, 100); rect1->setFlag(QGraphicsItem::ItemIsPanel); rect1->setFlag(QGraphicsItem::ItemIsFocusable); rect1->setData(0, "rect1"); QGraphicsRectItem *rect1child = scene.addRect(-10, -10, 20, 20); rect1child->setParentItem(rect1); rect1child->setFlag(QGraphicsItem::ItemIsFocusable); rect1child->setData(0, "rect1child1"); QGraphicsRectItem *rect2 = scene.addRect(-50, -50, 100, 100); rect2->setParentItem(rect1); rect2->setFlag(QGraphicsItem::ItemIsPanel); rect2->setFlag(QGraphicsItem::ItemIsFocusable); rect2->setPos(50, 50); rect2->setData(0, "rect2"); QGraphicsRectItem *rect2child = scene.addRect(-10, -10, 20, 20); rect2child->setParentItem(rect2); rect2child->setFlag(QGraphicsItem::ItemIsFocusable); rect2child->setData(0, "rect2child1"); QEvent windowActivateEvent(QEvent::WindowActivate); QApplication::sendEvent(&scene, &windowActivateEvent); EventSpy2 rect1Spy(&scene, rect1); EventSpy2 rect1childSpy(&scene, rect1child); EventSpy2 rect2Spy(&scene, rect2); EventSpy2 rect2childSpy(&scene, rect2child); // activate rect1 and give it rect1child focus rect1->setActive(true); rect1child->setFocus(); QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child); // focus stays on rect1child when rect2 becomes modal rect2->setPanelModality(QGraphicsItem::SceneModal); QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child); // but key events to rect1child should be neither delivered nor propagated sendKeyClick(&scene, Qt::Key_A); sendKeyClick(&scene, Qt::Key_S); sendKeyClick(&scene, Qt::Key_D); sendKeyClick(&scene, Qt::Key_F); QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0); QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0); QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0); // change to panel modality, rect1child1 keeps focus rect2->setPanelModality(QGraphicsItem::PanelModal); QCOMPARE(scene.focusItem(), (QGraphicsItem *) rect1child); // still no key events sendKeyClick(&scene, Qt::Key_J); sendKeyClick(&scene, Qt::Key_K); sendKeyClick(&scene, Qt::Key_L); sendKeyClick(&scene, Qt::Key_Semicolon); QCOMPARE(rect1childSpy.counts[QEvent::KeyPress], 0); QCOMPARE(rect1childSpy.counts[QEvent::KeyRelease], 0); QCOMPARE(rect1Spy.counts[QEvent::KeyPress], 0); QCOMPARE(rect1Spy.counts[QEvent::KeyRelease], 0); } void tst_QGraphicsItem::itemIsInFront() { QGraphicsScene scene; QGraphicsRectItem *rect1 = new QGraphicsRectItem; rect1->setData(0, "rect1"); scene.addItem(rect1); QGraphicsRectItem *rect1child1 = new QGraphicsRectItem(rect1); rect1child1->setZValue(1); rect1child1->setData(0, "rect1child1"); QGraphicsRectItem *rect1child2 = new QGraphicsRectItem(rect1); rect1child2->setParentItem(rect1); rect1child2->setData(0, "rect1child2"); QGraphicsRectItem *rect1child1_1 = new QGraphicsRectItem(rect1child1); rect1child1_1->setData(0, "rect1child1_1"); QGraphicsRectItem *rect1child1_2 = new QGraphicsRectItem(rect1child1); rect1child1_2->setFlag(QGraphicsItem::ItemStacksBehindParent); rect1child1_2->setData(0, "rect1child1_2"); QGraphicsRectItem *rect2 = new QGraphicsRectItem; rect2->setData(0, "rect2"); scene.addItem(rect2); QGraphicsRectItem *rect2child1 = new QGraphicsRectItem(rect2); rect2child1->setData(0, "rect2child1"); QCOMPARE(qt_closestItemFirst(rect1, rect1), false); QCOMPARE(qt_closestItemFirst(rect1, rect2), false); QCOMPARE(qt_closestItemFirst(rect1child1, rect2child1), false); QCOMPARE(qt_closestItemFirst(rect1child1, rect1child2), true); QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child2), true); QCOMPARE(qt_closestItemFirst(rect1child1_1, rect1child1), true); QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child2), true); QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1child1), false); QCOMPARE(qt_closestItemFirst(rect1child1_2, rect1), true); QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2), false); QCOMPARE(qt_closestItemFirst(rect1child1_2, rect2child1), false); } class ScenePosChangeTester : public ItemChangeTester { public: ScenePosChangeTester() { } ScenePosChangeTester(QGraphicsItem *parent) : ItemChangeTester(parent) { } }; void tst_QGraphicsItem::scenePosChange() { ScenePosChangeTester* root = new ScenePosChangeTester; ScenePosChangeTester* child1 = new ScenePosChangeTester(root); ScenePosChangeTester* grandChild1 = new ScenePosChangeTester(child1); ScenePosChangeTester* child2 = new ScenePosChangeTester(root); ScenePosChangeTester* grandChild2 = new ScenePosChangeTester(child2); child1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); QVERIFY(child1->flags() & QGraphicsItem::ItemSendsScenePositionChanges); QVERIFY(grandChild2->flags() & QGraphicsItem::ItemSendsScenePositionChanges); QGraphicsScene scene; scene.addItem(root); // ignore uninteresting changes child1->clear(); child2->clear(); grandChild1->clear(); grandChild2->clear(); // move whole tree root->moveBy(1.0, 1.0); QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); // move subtree child2->moveBy(1.0, 1.0); QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2); // reparent grandChild2->setParentItem(child1); child1->moveBy(1.0, 1.0); QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2); QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3); // change flags grandChild1->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); grandChild2->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false); QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants() child1->moveBy(1.0, 1.0); QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3); QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); QCOMPARE(grandChild2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 3); // remove scene.removeItem(grandChild1); delete grandChild2; grandChild2 = 0; QCoreApplication::processEvents(); // QGraphicsScenePrivate::_q_updateScenePosDescendants() root->moveBy(1.0, 1.0); QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 4); QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); root->setX(1); QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 5); QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); root->setY(1); QCOMPARE(child1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 6); QCOMPARE(grandChild1->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); } class MyInputContext : public QInputContext { public: MyInputContext() : nbUpdates(0) {} ~MyInputContext() {} QString identifierName() { return QString(); } QString language() { return QString(); } void reset() {} bool isComposing() const { return false; } void update() { nbUpdates++; } bool nbUpdates; }; class MyInputWidget : public QGraphicsWidget { public: MyInputWidget() { setFlag(QGraphicsItem::ItemIsFocusable, true); setFlag(QGraphicsItem::ItemAcceptsInputMethod, true); } void mousePressEvent(QGraphicsSceneMouseEvent *event) { event->accept(); } void doUpdateMicroFocus() { updateMicroFocus(); } }; void tst_QGraphicsItem::updateMicroFocus() { #if defined Q_OS_WIN || defined Q_OS_MAC QSKIP("QTBUG-9578", SkipAll); return; #endif QGraphicsScene scene; QWidget parent; QGridLayout layout; parent.setLayout(&layout); QGraphicsView view(&scene); QGraphicsView view2(&scene); layout.addWidget(&view, 0, 0); layout.addWidget(&view2, 0, 1); MyInputContext ic2; view2.setInputContext(&ic2); MyInputContext ic; view.setInputContext(&ic); MyInputWidget input; input.setPos(0, 0); input.resize(150, 150); scene.addItem(&input); input.setFocus(); parent.show(); view.setFocus(); qApp->setAutoSipEnabled(true); QApplication::setActiveWindow(&parent); QTest::qWaitForWindowShown(&parent); QTRY_COMPARE(QApplication::activeWindow(), static_cast(&parent)); //We reset the number of updates that happened previously (initialisation) ic.nbUpdates = 0; ic2.nbUpdates = 0; input.doUpdateMicroFocus(); QApplication::processEvents(); QTRY_COMPARE(ic.nbUpdates, 1); //No update since view2 does not have the focus. QTRY_COMPARE(ic2.nbUpdates, 0); } void tst_QGraphicsItem::textItem_shortcuts() { QWidget w; QVBoxLayout l; w.setLayout(&l); QGraphicsScene scene; QGraphicsView view(&scene); l.addWidget(&view); QPushButton b("Push Me"); l.addWidget(&b); QGraphicsTextItem *item = scene.addText("Troll Text"); item->setFlag(QGraphicsItem::ItemIsFocusable); item->setTextInteractionFlags(Qt::TextEditorInteraction); w.show(); QTest::qWaitForWindowShown(&w); item->setFocus(); QTRY_VERIFY(item->hasFocus()); QVERIFY(item->textCursor().selectedText().isEmpty()); // Shortcut should work (select all) QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier); QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText()); QTextCursor tc = item->textCursor(); tc.clearSelection(); item->setTextCursor(tc); QVERIFY(item->textCursor().selectedText().isEmpty()); // Shortcut should also work if the text item has the focus and another widget // has the same shortcut. b.setShortcut(QKeySequence("CTRL+A")); QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier); QTRY_COMPARE(item->textCursor().selectedText(), item->toPlainText()); } void tst_QGraphicsItem::scroll() { // Create two overlapping rectangles in the scene: // +-------+ // | | <- item1 // | +-------+ // | | | // +---| | <- item2 // | | // +-------+ EventTester *item1 = new EventTester; item1->br = QRectF(0, 0, 200, 200); item1->brush = Qt::red; item1->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); EventTester *item2 = new EventTester; item2->br = QRectF(0, 0, 200, 200); item2->brush = Qt::blue; item2->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); item2->setPos(100, 100); QGraphicsScene scene(0, 0, 300, 300); scene.addItem(item1); scene.addItem(item2); MyGraphicsView view(&scene); view.setFrameStyle(0); view.show(); QTest::qWaitForWindowShown(&view); QTRY_VERIFY(view.repaints > 0); view.reset(); item1->reset(); item2->reset(); const QRectF item1BoundingRect = item1->boundingRect(); const QRectF item2BoundingRect = item2->boundingRect(); // Scroll item1: // Item1 should get full exposure // Item2 should get exposure for the part that overlaps item1. item1->scroll(0, -10); QTRY_VERIFY(view.repaints > 0); QCOMPARE(item1->lastExposedRect, item1BoundingRect); QRectF expectedItem2Expose = item2BoundingRect; // NB! Adjusted by 2 pixels for antialiasing expectedItem2Expose &= item1->mapRectToItem(item2, item1BoundingRect.adjusted(-2, -2, 2, 2)); QCOMPARE(item2->lastExposedRect, expectedItem2Expose); // Enable ItemCoordinateCache on item1. view.reset(); item1->setCacheMode(QGraphicsItem::ItemCoordinateCache); QTRY_VERIFY(view.repaints > 0); view.reset(); item1->reset(); item2->reset(); // Scroll item1: // Item1 should only get expose for the newly exposed area (accelerated scroll). // Item2 should get exposure for the part that overlaps item1. item1->scroll(0, -10, QRectF(50, 50, 100, 100)); QTRY_VERIFY(view.repaints > 0); QCOMPARE(item1->lastExposedRect, QRectF(50, 140, 100, 10)); expectedItem2Expose = item2BoundingRect; // NB! Adjusted by 2 pixels for antialiasing expectedItem2Expose &= item1->mapRectToItem(item2, QRectF(50, 50, 100, 100).adjusted(-2, -2, 2, 2)); QCOMPARE(item2->lastExposedRect, expectedItem2Expose); } void tst_QGraphicsItem::stopClickFocusPropagation() { class MyItem : public QGraphicsRectItem { public: MyItem() : QGraphicsRectItem(0, 0, 100, 100) {} void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->fillRect(boundingRect(), hasFocus() ? QBrush(Qt::red) : brush()); } }; QGraphicsScene scene(-50, -50, 400, 400); scene.setStickyFocus(true); QGraphicsRectItem *noFocusOnTop = new MyItem; noFocusOnTop->setBrush(Qt::yellow); noFocusOnTop->setFlag(QGraphicsItem::ItemStopsClickFocusPropagation); QGraphicsRectItem *focusableUnder = new MyItem; focusableUnder->setBrush(Qt::blue); focusableUnder->setFlag(QGraphicsItem::ItemIsFocusable); focusableUnder->setPos(50, 50); QGraphicsRectItem *itemWithFocus = new MyItem; itemWithFocus->setBrush(Qt::black); itemWithFocus->setFlag(QGraphicsItem::ItemIsFocusable); itemWithFocus->setPos(250, 10); scene.addItem(noFocusOnTop); scene.addItem(focusableUnder); scene.addItem(itemWithFocus); focusableUnder->stackBefore(noFocusOnTop); itemWithFocus->setFocus(); QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QApplication::setActiveWindow(&view); QTRY_COMPARE(QApplication::activeWindow(), static_cast(&view)); QVERIFY(itemWithFocus->hasFocus()); QPointF mousePressPoint = noFocusOnTop->mapToScene(QPointF()); mousePressPoint.rx() += 60; mousePressPoint.ry() += 60; const QList itemsAtMousePressPosition = scene.items(mousePressPoint); QVERIFY(itemsAtMousePressPosition.contains(focusableUnder)); sendMousePress(&scene, mousePressPoint); QVERIFY(itemWithFocus->hasFocus()); } void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations() { // Make sure we don't invalidate the cache when applying simple // (90, 180, 270, 360) rotation transforms to the item. QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 300, 200); item->setBrush(Qt::red); item->setCacheMode(QGraphicsItem::DeviceCoordinateCache); QGraphicsScene scene; scene.setSceneRect(0, 0, 300, 200); scene.addItem(item); MyGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); QTRY_VERIFY(view.repaints > 0); QGraphicsItemCache *itemCache = QGraphicsItemPrivate::get(item)->extraItemCache(); Q_ASSERT(itemCache); QPixmapCache::Key currentKey = itemCache->deviceData.value(view.viewport()).key; // Trigger an update and verify that the cache is unchanged. QPixmapCache::Key oldKey = currentKey; view.reset(); view.viewport()->update(); QTRY_VERIFY(view.repaints > 0); currentKey = itemCache->deviceData.value(view.viewport()).key; QCOMPARE(currentKey, oldKey); // Check 90, 180, 270 and 360 degree rotations. for (int angle = 90; angle <= 360; angle += 90) { // Rotate item and verify that the cache was invalidated. oldKey = currentKey; view.reset(); QTransform transform; transform.translate(150, 100); transform.rotate(angle); transform.translate(-150, -100); item->setTransform(transform); QTRY_VERIFY(view.repaints > 0); currentKey = itemCache->deviceData.value(view.viewport()).key; QVERIFY(currentKey != oldKey); // IMPORTANT PART: // Trigger an update and verify that the cache is unchanged. oldKey = currentKey; view.reset(); view.viewport()->update(); QTRY_VERIFY(view.repaints > 0); currentKey = itemCache->deviceData.value(view.viewport()).key; QCOMPARE(currentKey, oldKey); } // 45 degree rotation. oldKey = currentKey; view.reset(); QTransform transform; transform.translate(150, 100); transform.rotate(45); transform.translate(-150, -100); item->setTransform(transform); QTRY_VERIFY(view.repaints > 0); currentKey = itemCache->deviceData.value(view.viewport()).key; QVERIFY(currentKey != oldKey); // Trigger an update and verify that the cache was invalidated. // We should always invalidate the cache for non-trivial transforms. oldKey = currentKey; view.reset(); view.viewport()->update(); QTRY_VERIFY(view.repaints > 0); currentKey = itemCache->deviceData.value(view.viewport()).key; QVERIFY(currentKey != oldKey); } void tst_QGraphicsItem::QTBUG_5418_textItemSetDefaultColor() { struct Item : public QGraphicsTextItem { int painted; void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid) { painted++; QGraphicsTextItem::paint(painter, opt, wid); } }; Item *i = new Item; i->painted = 0; i->setPlainText("I AM A TROLL"); QGraphicsScene scene; QGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); scene.addItem(i); QApplication::processEvents(); QTRY_VERIFY(i->painted); QApplication::processEvents(); i->painted = 0; QColor col(Qt::red); i->setDefaultTextColor(col); QApplication::processEvents(); QTRY_COMPARE(i->painted, 1); //check that changing the color force an update i->painted = false; QImage image(400, 200, QImage::Format_RGB32); image.fill(0); QPainter painter(&image); scene.render(&painter); painter.end(); QCOMPARE(i->painted, 1); int numRedPixel = 0; QRgb rgb = col.rgb(); for (int y = 0; y < image.height(); ++y) { for (int x = 0; x < image.width(); ++x) { // Because of antialiasing we allow a certain range of errors here. QRgb pixel = image.pixel(x, y); if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) + qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) + qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) { if (++numRedPixel >= 10) { return; } } } } QCOMPARE(numRedPixel, -1); //color not found, FAIL! i->painted = 0; i->setDefaultTextColor(col); QApplication::processEvents(); QCOMPARE(i->painted, 0); //same color as before should not trigger an update (QTBUG-6242) } void tst_QGraphicsItem::QTBUG_6738_missingUpdateWithSetParent() { // In all 3 test cases below the reparented item should disappear EventTester *parent = new EventTester; EventTester *child = new EventTester(parent); EventTester *child2 = new EventTester(parent); EventTester *child3 = new EventTester(parent); EventTester *child4 = new EventTester(parent); child->setPos(10, 10); child2->setPos(20, 20); child3->setPos(30, 30); child4->setPos(40, 40); QGraphicsScene scene; scene.addItem(parent); MyGraphicsView view(&scene); if(PlatformQuirks::isAutoMaximizing()) view.showFullScreen(); else view.show(); QTest::qWaitForWindowShown(&view); QTRY_VERIFY(view.repaints > 0); // test case #1 view.reset(); child2->setVisible(false); child2->setParentItem(child); QTRY_VERIFY(view.repaints == 1); // test case #2 view.reset(); child3->setOpacity(0.0); child3->setParentItem(child); QTRY_VERIFY(view.repaints == 1); // test case #3 view.reset(); child4->setParentItem(child); child4->setVisible(false); QTRY_VERIFY(view.repaints == 1); } void tst_QGraphicsItem::QT_2653_fullUpdateDiscardingOpacityUpdate() { QGraphicsScene scene(0, 0, 200, 200); MyGraphicsView view(&scene); EventTester *parentGreen = new EventTester(); parentGreen->setGeometry(QRectF(20, 20, 100, 100)); parentGreen->brush = Qt::green; EventTester *childYellow = new EventTester(parentGreen); childYellow->setGeometry(QRectF(10, 10, 50, 50)); childYellow->brush = Qt::yellow; scene.addItem(parentGreen); childYellow->setOpacity(0.0); parentGreen->setOpacity(0.0); // set any of the flags below to trigger a fullUpdate to reproduce the bug: // ItemIgnoresTransformations, ItemClipsChildrenToShape, ItemIsSelectable parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations); if (PlatformQuirks::isAutoMaximizing()) view.showFullScreen(); else view.show(); QTest::qWaitForWindowShown(&view); view.reset(); parentGreen->setOpacity(1.0); QTRY_COMPARE(view.repaints, 1); view.reset(); childYellow->repaints = 0; childYellow->setOpacity(1.0); QTRY_COMPARE(view.repaints, 1); QTRY_COMPARE(childYellow->repaints, 1); } void tst_QGraphicsItem::QTBUG_7714_fullUpdateDiscardingOpacityUpdate2() { QGraphicsScene scene(0, 0, 200, 200); MyGraphicsView view(&scene); MyGraphicsView origView(&scene); EventTester *parentGreen = new EventTester(); parentGreen->setGeometry(QRectF(20, 20, 100, 100)); parentGreen->brush = Qt::green; EventTester *childYellow = new EventTester(parentGreen); childYellow->setGeometry(QRectF(10, 10, 50, 50)); childYellow->brush = Qt::yellow; scene.addItem(parentGreen); origView.show(); QTest::qWaitForWindowShown(&origView); origView.setGeometry(origView.width() + 20, 20, origView.width(), origView.height()); parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations); origView.reset(); childYellow->setOpacity(0.0); QTRY_COMPARE(origView.repaints, 1); view.show(); QTest::qWaitForWindowShown(&view); view.reset(); origView.reset(); childYellow->setOpacity(1.0); QTRY_COMPARE(origView.repaints, 1); QTRY_COMPARE(view.repaints, 1); } void tst_QGraphicsItem::QT_2649_focusScope() { QGraphicsScene *scene = new QGraphicsScene; QGraphicsRectItem *subFocusItem = new QGraphicsRectItem; subFocusItem->setFlags(QGraphicsItem::ItemIsFocusable); subFocusItem->setFocus(); QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); QGraphicsRectItem *scope = new QGraphicsRectItem; scope->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsFocusScope); scope->setFocus(); subFocusItem->setParentItem(scope); QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); QGraphicsRectItem *rootItem = new QGraphicsRectItem; rootItem->setFlags(QGraphicsItem::ItemIsFocusable); scope->setParentItem(rootItem); QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); scene->addItem(rootItem); QEvent windowActivate(QEvent::WindowActivate); qApp->sendEvent(scene, &windowActivate); scene->setFocus(); QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); QVERIFY(subFocusItem->hasFocus()); scope->hide(); QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)0); QCOMPARE(scope->focusItem(), (QGraphicsItem *)0); QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)0); QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); QVERIFY(!subFocusItem->hasFocus()); scope->show(); QCOMPARE(rootItem->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(scope->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(subFocusItem->focusItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(rootItem->focusScopeItem(), (QGraphicsItem *)0); QCOMPARE(scope->focusScopeItem(), (QGraphicsItem *)subFocusItem); QCOMPARE(subFocusItem->focusScopeItem(), (QGraphicsItem *)0); QVERIFY(subFocusItem->hasFocus()); // This should not crash scope->hide(); delete scene; } class MyGraphicsItemWithItemChange : public QGraphicsWidget { public: MyGraphicsItemWithItemChange(QGraphicsItem *parent = 0) : QGraphicsWidget(parent) {} QVariant itemChange(GraphicsItemChange change, const QVariant &value) { if (change == QGraphicsItem::ItemSceneHasChanged) { foreach (QGraphicsView *view, scene()->views()) { //We trigger a sort of unindexed items in the BSP view->sceneRect(); } } return QGraphicsWidget::itemChange(change, value); } }; void tst_QGraphicsItem::sortItemsWhileAdding() { QGraphicsScene scene; QGraphicsView view(&scene); QGraphicsWidget grandGrandParent; grandGrandParent.resize(200, 200); scene.addItem(&grandGrandParent); QGraphicsWidget grandParent; grandParent.resize(200, 200); QGraphicsWidget parent(&grandParent); parent.resize(200, 200); MyGraphicsItemWithItemChange item(&parent); grandParent.setParentItem(&grandGrandParent); } void tst_QGraphicsItem::doNotMarkFullUpdateIfNotInScene() { struct Item : public QGraphicsTextItem { int painted; void paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *wid) { painted++; QGraphicsTextItem::paint(painter, opt, wid); } }; QGraphicsScene scene; MyGraphicsView view(&scene); Item *item = new Item; item->painted = 0; item->setPlainText("Grandparent"); Item *item2 = new Item; item2->setPlainText("parent"); item2->painted = 0; Item *item3 = new Item; item3->setPlainText("child"); item3->painted = 0; QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect; effect->setOpacity(0.5); item2->setGraphicsEffect(effect); item3->setParentItem(item2); item2->setParentItem(item); scene.addItem(item); if(PlatformQuirks::isAutoMaximizing()) view.showFullScreen(); else view.show(); QTest::qWaitForWindowShown(&view); QTRY_COMPARE(view.repaints, 1); QTRY_COMPARE(item->painted, 1); QTRY_COMPARE(item2->painted, 1); QTRY_COMPARE(item3->painted, 1); item2->update(); QApplication::processEvents(); QTRY_COMPARE(item->painted, 2); QTRY_COMPARE(item2->painted, 2); QTRY_COMPARE(item3->painted, 2); item2->update(); QApplication::processEvents(); QTRY_COMPARE(item->painted, 3); QTRY_COMPARE(item2->painted, 3); QTRY_COMPARE(item3->painted, 3); } void tst_QGraphicsItem::itemDiesDuringDraggingOperation() { QGraphicsScene scene; QGraphicsView view(&scene); QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100)); item->setFlag(QGraphicsItem::ItemIsMovable); item->setAcceptDrops(true); scene.addItem(item); view.show(); QApplication::setActiveWindow(&view); QTest::qWaitForWindowShown(&view); QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view); QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter); dragEnter.setScenePos(item->boundingRect().center()); QApplication::sendEvent(&scene, &dragEnter); QGraphicsSceneDragDropEvent event(QEvent::GraphicsSceneDragMove); event.setScenePos(item->boundingRect().center()); QApplication::sendEvent(&scene, &event); QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == item); delete item; QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == 0); } void tst_QGraphicsItem::QTBUG_12112_focusItem() { QGraphicsScene scene; QGraphicsView view(&scene); QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20); item1->setFlag(QGraphicsItem::ItemIsFocusable); QGraphicsRectItem *item2 = new QGraphicsRectItem(20, 20, 20, 20); item2->setFlag(QGraphicsItem::ItemIsFocusable); item1->setFocus(); scene.addItem(item2); scene.addItem(item1); view.show(); QApplication::setActiveWindow(&view); QTest::qWaitForWindowShown(&view); QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view); QVERIFY(item1->focusItem()); QVERIFY(!item2->focusItem()); item2->setFocus(); QVERIFY(!item1->focusItem()); QVERIFY(item2->focusItem()); } void tst_QGraphicsItem::QTBUG_13473_sceneposchange() { ScenePosChangeTester* parent = new ScenePosChangeTester; ScenePosChangeTester* child = new ScenePosChangeTester(parent); // parent's disabled ItemSendsGeometryChanges flag must not affect // child's scene pos change notifications parent->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false); child->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); QGraphicsScene scene; scene.addItem(parent); // ignore uninteresting changes parent->clear(); child->clear(); // move parent->moveBy(1.0, 1.0); QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 1); // transform parent->setTransform(QTransform::fromScale(0.5, 0.5)); QCOMPARE(child->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 2); } QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc"