From 6c10e72fc838f8f9f5c3a3e4a297088b1725262c Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 26 May 2011 13:56:54 +0200 Subject: Fix infinite recursion when changing geometry on Mac Some complex widgets might get a negatively sized rectangle when calling QWidgetPrivate:setGeometry_sys_helper(), triggering a infinite recursion. Normalizing the rectangle size before checking for size change is enough to break this infinite recursion. Reviewed-by: Richard Task-number: QTBUG-17333 --- src/gui/kernel/qwidget_mac.mm | 12 +++++------- tests/auto/qwidget/tst_qwidget.cpp | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 2f33f55..9481a85 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -4434,6 +4434,11 @@ void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isM QPoint oldp = q->pos(); QSize olds = q->size(); + // Apply size restrictions, applicable for Windows & Widgets. + if (QWExtra *extra = extraData()) { + w = qBound(extra->minw, w, extra->maxw); + h = qBound(extra->minh, h, extra->maxh); + } const bool isResize = (olds != QSize(w, h)); if (!realWindow && !isResize && QPoint(x, y) == oldp) @@ -4443,13 +4448,6 @@ void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isM data.window_state = data.window_state & ~Qt::WindowMaximized; const bool visible = q->isVisible(); - // Apply size restrictions, applicable for Windows & Widgets. - if (QWExtra *extra = extraData()) { - w = qMin(w, extra->maxw); - h = qMin(h, extra->maxh); - w = qMax(w, extra->minw); - h = qMax(h, extra->minh); - } data.crect = QRect(x, y, w, h); if (realWindow) { diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index f85d469..43dd077 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -71,6 +71,7 @@ #include #include #include +#include #include #include @@ -406,6 +407,7 @@ private slots: void childAt(); #ifdef Q_WS_MAC void childAt_unifiedToolBar(); + void taskQTBUG_17333_ResizeInfiniteRecursion(); #ifdef QT_MAC_USE_COCOA void taskQTBUG_11373(); #endif // QT_MAC_USE_COCOA @@ -10593,6 +10595,18 @@ void tst_QWidget::childAt_unifiedToolBar() QCOMPARE(mainWindow.childAt(labelTopLeft), static_cast(label)); } +void tst_QWidget::taskQTBUG_17333_ResizeInfiniteRecursion() +{ + QTableView tb; + const char *s = "border: 1px solid;"; + tb.setStyleSheet(s); + tb.show(); + + QTest::qWaitForWindowShown(&tb); + tb.setGeometry(QRect(100, 100, 0, 100)); + // No crash, it works. +} + #ifdef QT_MAC_USE_COCOA void tst_QWidget::taskQTBUG_11373() { -- cgit v0.12 From 575e832fd053df98e60aefebbc5843a4864f2523 Mon Sep 17 00:00:00 2001 From: John Tapsell Date: Fri, 27 May 2011 07:31:55 +0100 Subject: Fixed move a QGraphicsWidget and invalidate its layout at the same time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QGraphicsWidget::setGeometry() could sometimes call QGraphicsLayoutItem::setGeometry() with an uninitialized rectangle. This happened in the specific case where the widget had a layout that was not active, and where setPos was called on the widget. This would in turn cause it to enter setGeometry() where it would act as expected. However, due to the fact that we sent a LayoutRequest event at the end of that function, it could result in that QGraphicsLayout::activate() would call setGeometry again. Now, we would actually enter setGeometry, where wd->inSetPos == 1. Then, we would not enter the "if (!wd->inSetPos)" block nor the "if (moved)" block. It would then end up calling QGraphicsLayoutItem::setGeometry(newGeom), where newGeom was uninitialized. Bug happens only when QGraphicsLayout::setInstantInvalidatePropagation(true) was used, because that was the condition for sending the layout request from setGeometry() Tracked down and written by Stanislav Ionascu. Reviewed-by: Jan-Arve Sæther --- src/gui/graphicsview/qgraphicswidget.cpp | 3 +- tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp | 73 ++++++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 804394a..7048fcc 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -347,11 +347,10 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) { QGraphicsWidgetPrivate *wd = QGraphicsWidget::d_func(); QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr.data(); - QRectF newGeom; + QRectF newGeom = rect; QPointF oldPos = d->geom.topLeft(); if (!wd->inSetPos) { setAttribute(Qt::WA_Resized); - newGeom = rect; newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize)) .boundedTo(effectiveSizeHint(Qt::MaximumSize))); diff --git a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp index d5d56fc..9411f97 100644 --- a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp +++ b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp @@ -63,6 +63,8 @@ private slots: void automaticReparenting(); void verifyActivate(); void invalidate(); + void invalidateAndMove_data(); + void invalidateAndMove(); void constructors(); void alternativeLayoutItems(); void ownership(); @@ -556,6 +558,77 @@ void tst_QGraphicsLayout::invalidate() QGraphicsLayout::setInstantInvalidatePropagation(false); } +void tst_QGraphicsLayout::invalidateAndMove_data() +{ + QTest::addColumn("instantInvalidatePropagation"); + QTest::newRow("Without instantInvalidatePropagation") << false; + QTest::newRow("With instantInvalidatePropagation") << true; + +} +void tst_QGraphicsLayout::invalidateAndMove() +{ + // Check that if we set the position of an item and invalidate its layout at the same + // time, the widget keeps its correct size + QFETCH(bool, instantInvalidatePropagation); + QGraphicsLayout::setInstantInvalidatePropagation(instantInvalidatePropagation); + QGraphicsScene scene; + + QGraphicsWidget *widget = new QGraphicsWidget; + new QGraphicsLinearLayout(widget); + + widget->setMinimumSize(1,1); + widget->setPreferredSize(34,34); + widget->setMaximumSize(100,100); + widget->resize(widget->preferredSize()); + + scene.addItem(widget); + + qApp->processEvents(); + + /* Invalidate and reactivate. The size should not have changed */ + widget->layout()->invalidate(); + widget->layout()->activate(); + + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + qApp->processEvents(); + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + + widget->layout()->invalidate(); + widget->setX(1); //Change just the position using setX + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + qApp->processEvents(); + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + + widget->layout()->invalidate(); + widget->setGeometry(1,1,34,34); //Change just the position using setGeometry + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + qApp->processEvents(); + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + + widget->layout()->invalidate(); + widget->setGeometry(1,1,60,60); //Change just the size using setGeometry + QCOMPARE(widget->geometry().size(), QSizeF(60,60)); + QCOMPARE(widget->layout()->geometry().size(), QSizeF(60,60)); + qApp->processEvents(); + QCOMPARE(widget->geometry().size(), QSizeF(60,60)); + QCOMPARE(widget->layout()->geometry().size(), QSizeF(60,60)); + + widget->layout()->invalidate(); + widget->setGeometry(0,0,34,34); //Change the size and position using setGeometry + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + qApp->processEvents(); + QCOMPARE(widget->geometry().size(), widget->preferredSize()); + QCOMPARE(widget->layout()->geometry().size(), widget->preferredSize()); + + QGraphicsLayout::setInstantInvalidatePropagation(false); +} class Layout : public QGraphicsLayout { public: -- cgit v0.12 From 4225a25efb46c9f5a3fbb8197286663b8cb21e27 Mon Sep 17 00:00:00 2001 From: Jan-Arve Saether Date: Thu, 9 Jun 2011 09:57:39 +0200 Subject: Fixes to how resize event and layout request are posted. Also fixed how the relayout is initiated. This is because we needed to react differently to *posted* layout requests than to sent layout requests. (sent ones should activate the layout, posted ones should also resize the widget). We therefore introduced the private slot _q_relayout() in order to be able to make the distinction between posted and sent layout requests. (Instead of posting we now invokeMethod with a queued connection. In order to make it behave as it was compressed we also have to refcount the number of calls to invokeMethod.) (Note that refCount is 16 bits only, so it should not overflow in sane cases. In the insane cases, the worst thing that will happen is that it'll relayout the layout one extra time). Make sure we resize QGraphicsWidget to be within its min,max sizes when we change one of its constraints. (e.g. we change minimumSize to something bigger than the current size). This did not work if the widget did not have a layout. Send a resize event whenever a QGraphicsWidget changes its size. This did not happen before, because in the cases where a Layout Request was sent, we did not send a resize event. This patch changes that, so that when we send a resize event, we do not send a Layout Request event. This means that a Layout Request event is now *only* sent in order to tell a widget to relayout its children (but the widgets size was not changed, that's why we cannot send a resize event in that case) Also includes a unit test, and a fix to make sure that we send a resize event when we resize due to the sizehint changing followed by a setPos command. Added autotests for this. (and changed some) Many thanks to John Tapsell and Stanislav Ionascu for help. (autotests were provided by them). My poor explanation did not convince Frederik 100%, but he is "convinced enough" :) Reviewed-by: Frederik Gladhorn --- src/gui/graphicsview/qgraphicslayout.cpp | 14 +- src/gui/graphicsview/qgraphicswidget.cpp | 16 +- src/gui/graphicsview/qgraphicswidget.h | 2 + src/gui/graphicsview/qgraphicswidget_p.cpp | 14 ++ src/gui/graphicsview/qgraphicswidget_p.h | 5 + tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp | 192 ++++++++++++++++++--- 6 files changed, 201 insertions(+), 42 deletions(-) diff --git a/src/gui/graphicsview/qgraphicslayout.cpp b/src/gui/graphicsview/qgraphicslayout.cpp index b37dfd4..f983955 100644 --- a/src/gui/graphicsview/qgraphicslayout.cpp +++ b/src/gui/graphicsview/qgraphicslayout.cpp @@ -269,18 +269,8 @@ void QGraphicsLayout::activate() return; Q_ASSERT(!parentItem->isLayout()); - if (QGraphicsLayout::instantInvalidatePropagation()) { - QGraphicsWidget *parentWidget = static_cast(parentItem); - if (!parentWidget->parentLayoutItem()) { - // we've reached the topmost widget, resize it - bool wasResized = parentWidget->testAttribute(Qt::WA_Resized); - parentWidget->resize(parentWidget->size()); - parentWidget->setAttribute(Qt::WA_Resized, wasResized); - } - - setGeometry(parentItem->contentsRect()); // relayout children - } else { - setGeometry(parentItem->contentsRect()); // relayout children + setGeometry(parentItem->contentsRect()); // relayout children + if (!QGraphicsLayout::instantInvalidatePropagation()) { parentLayoutItem()->updateGeometry(); } } diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 7048fcc..965b1b34 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -404,14 +404,7 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) emit widthChanged(); if (oldSize.height() != newGeom.size().height()) emit heightChanged(); - QGraphicsLayout *lay = wd->layout; - if (QGraphicsLayout::instantInvalidatePropagation()) { - if (!lay || lay->isActivated()) { - QApplication::sendEvent(this, &re); - } - } else { - QApplication::sendEvent(this, &re); - } + QApplication::sendEvent(this, &re); } } @@ -1090,8 +1083,11 @@ void QGraphicsWidget::updateGeometry() * When the event is received, it will start flowing all the way down to the leaf * widgets in one go. This will make a relayout flicker-free. */ - if (QGraphicsLayout::instantInvalidatePropagation()) - QApplication::postEvent(static_cast(this), new QEvent(QEvent::LayoutRequest)); + if (QGraphicsLayout::instantInvalidatePropagation()) { + Q_D(QGraphicsWidget); + ++d->refCountInvokeRelayout; + QMetaObject::invokeMethod(this, "_q_relayout", Qt::QueuedConnection); + } } if (!QGraphicsLayout::instantInvalidatePropagation()) { bool wasResized = testAttribute(Qt::WA_Resized); diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h index 063be2d..5085817 100644 --- a/src/gui/graphicsview/qgraphicswidget.h +++ b/src/gui/graphicsview/qgraphicswidget.h @@ -234,6 +234,8 @@ protected: private: Q_DISABLE_COPY(QGraphicsWidget) Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QGraphicsWidget) + Q_PRIVATE_SLOT(d_func(), void _q_relayout()) + friend class QGraphicsScene; friend class QGraphicsScenePrivate; friend class QGraphicsView; diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index 059051e..dc0f7c0 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -232,6 +232,18 @@ void QGraphicsWidgetPrivate::resolveLayoutDirection() } } +/* private slot */ +void QGraphicsWidgetPrivate::_q_relayout() +{ + --refCountInvokeRelayout; + if (refCountInvokeRelayout == 0) { + Q_Q(QGraphicsWidget); + bool wasResized = q->testAttribute(Qt::WA_Resized); + q->resize(q->size()); // this will restrict the size + q->setAttribute(Qt::WA_Resized, wasResized); + } +} + QPalette QGraphicsWidgetPrivate::naturalWidgetPalette() const { Q_Q(const QGraphicsWidget); @@ -897,4 +909,6 @@ void QGraphicsWidgetPrivate::setGeometryFromSetPos() QT_END_NAMESPACE +#include "moc_qgraphicswidget.cpp" + #endif //QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h index 398abc3..6ea2586 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.h +++ b/src/gui/graphicsview/qgraphicswidget_p.h @@ -81,6 +81,7 @@ public: polished(0), inSetPos(0), autoFillBackground(0), + refCountInvokeRelayout(0), focusPolicy(Qt::NoFocus), focusNext(0), focusPrev(0), @@ -106,6 +107,7 @@ public: QGraphicsLayout *layout; void setLayoutDirection_helper(Qt::LayoutDirection direction); void resolveLayoutDirection(); + void _q_relayout(); // Style QPalette palette; @@ -179,11 +181,14 @@ public: return false; return (attributes & (1 << bit)) != 0; } + // 32 bits + quint32 refCountInvokeRelayout : 16; quint32 attributes : 10; quint32 inSetGeometry : 1; quint32 polished: 1; quint32 inSetPos : 1; quint32 autoFillBackground : 1; + quint32 padding : 2; // feel free to use // Focus Qt::FocusPolicy focusPolicy; diff --git a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp index 9411f97..cd91008 100644 --- a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp +++ b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp @@ -63,6 +63,12 @@ private slots: void automaticReparenting(); void verifyActivate(); void invalidate(); + void moveAndResize_data(); + void moveAndResize(); + void moveAndResizeWidgetInWidget_data(); + void moveAndResizeWidgetInWidget(); + void changingMinimumSize_data(); + void changingMinimumSize(); void invalidateAndMove_data(); void invalidateAndMove(); void constructors(); @@ -445,7 +451,7 @@ void tst_QGraphicsLayout::invalidate() QCoreApplication::sendPostedEvents(); QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); - QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(c->eventCount(QEvent::GraphicsSceneResize), 1); QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); QCOMPARE(a->functionCount[SetGeometry], 1); @@ -481,30 +487,18 @@ void tst_QGraphicsLayout::invalidate() QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); QCoreApplication::sendPostedEvents(); - QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(a->eventCount(QEvent::GraphicsSceneResize), 1); QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); - QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(c->eventCount(QEvent::GraphicsSceneResize), 1); QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); QCOMPARE(a->functionCount[SetGeometry], 1); - /* well, ideally one call to setGeometry(), but it will currently - * get two calls to setGeometry(): - * 1. The first LayoutRequest will call activate() - that will call - * setGeometry() on the layout. This geometry will be based on - * the widget geometry which is not correct at this moment. - * (it is still 150 wide) - * 2. Next, we check if the widget is top level, and then we call - * parentWidget->resize(parentWidget->size()); - * This will be adjusted to be minimum 200 pixels wide. - * The new size will then be propagated down to the layout - * - */ - QCOMPARE(alay->functionCount[SetGeometry], 2); - - QCOMPARE(b->functionCount[SetGeometry], 2); - QCOMPARE(c->functionCount[SetGeometry], 2); - QCOMPARE(d->functionCount[SetGeometry], 2); + QCOMPARE(alay->functionCount[SetGeometry], 1); + + QCOMPARE(b->functionCount[SetGeometry], 1); + QCOMPARE(c->functionCount[SetGeometry], 1); + QCOMPARE(d->functionCount[SetGeometry], 1); // f actually got wider, need to rearrange its siblings QCOMPARE(blay->functionCount[SetGeometry], 1); QCOMPARE(clay->functionCount[SetGeometry], 1); @@ -557,7 +551,165 @@ void tst_QGraphicsLayout::invalidate() QGraphicsLayout::setInstantInvalidatePropagation(false); } +void tst_QGraphicsLayout::changingMinimumSize_data() +{ + QTest::addColumn("instantInvalidatePropagation"); + QTest::newRow("Without instantInvalidatePropagation") << false; + QTest::newRow("With instantInvalidatePropagation") << true; +} +void tst_QGraphicsLayout::changingMinimumSize() +{ + QFETCH(bool, instantInvalidatePropagation); + QGraphicsLayout::setInstantInvalidatePropagation(instantInvalidatePropagation); + QGraphicsWidget *widget = new QGraphicsWidget; + qApp->processEvents(); + widget->setMinimumSize(300,300); + qApp->processEvents(); + QCOMPARE(widget->size(), QSizeF(300,300)); + QGraphicsLayout::setInstantInvalidatePropagation(false); +} + +struct WidgetToTestResizeEvents : public QGraphicsWidget +{ + virtual void resizeEvent ( QGraphicsSceneResizeEvent * event ) + { + QGraphicsWidget::resizeEvent(event); + resizeEventCalled = true; + } + + bool resizeEventCalled; +}; +void tst_QGraphicsLayout::moveAndResizeWidgetInWidget_data() +{ + QTest::addColumn("instantInvalidatePropagation"); + + QTest::newRow("Without instantInvalidatePropagation") << false; + QTest::newRow("With instantInvalidatePropagation") << true; +} +void tst_QGraphicsLayout::moveAndResizeWidgetInWidget() +{ + QFETCH(bool, instantInvalidatePropagation); + + QGraphicsLayout::setInstantInvalidatePropagation(instantInvalidatePropagation); + QGraphicsScene scene; + + QGraphicsWidget *widget = new QGraphicsWidget; + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(widget); + layout->setContentsMargins(0,0,0,0); + WidgetToTestResizeEvents *innerWidget = new WidgetToTestResizeEvents; + QGraphicsLinearLayout *innerLayout = new QGraphicsLinearLayout(innerWidget); + innerLayout->setContentsMargins(0,0,0,0); + QCOMPARE(widget->maximumSize(), QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); + layout->addItem(innerWidget); + widget->setMinimumSize(1,1); + widget->setPreferredSize(1000,1000); + widget->setMaximumSize(2000,2000); + widget->resize(widget->preferredSize()); + innerWidget->setMinimumSize(1,1); + qApp->processEvents(); + innerWidget->resizeEventCalled = false; + + QCOMPARE(widget->size(), QSizeF(1000, 1000)); + QCOMPARE(layout->geometry().size(), QSizeF(1000, 1000)); + QCOMPARE(innerWidget->size(), QSizeF(1000, 1000)); + + innerLayout->invalidate(); + widget->setMaximumHeight(500); + widget->setX(1); + qApp->processEvents(); + QCOMPARE(widget->size(), QSizeF(1000, 500)); + QCOMPARE(innerWidget->size(), QSizeF(1000, 500)); + QVERIFY(innerWidget->resizeEventCalled); +} +void tst_QGraphicsLayout::moveAndResize_data() +{ + QTest::addColumn("instantInvalidatePropagation"); + QTest::addColumn("insideLayout"); + QTest::addColumn("insideLayoutInLayout"); + QTest::addColumn("insideWidget"); + QTest::newRow("Without instantInvalidatePropagation") << false << false << false << false; + QTest::newRow("With instantInvalidatePropagation") << true << false << false << false; + QTest::newRow("Without instantInvalidatePropagation, inside widget with no layout") << false << false << false << true; + QTest::newRow("With instantInvalidatePropagation, inside widget with no layout") << true << false << false << true; + QTest::newRow("Without instantInvalidatePropagation, inside widget with layout") << false << true << false << true; + QTest::newRow("With instantInvalidatePropagation, inside widget with layout") << true << true << false << true; + QTest::newRow("Without instantInvalidatePropagation, inside widget with layout in layout") << false << true << true << true; + QTest::newRow("With instantInvalidatePropagation, inside widget with layout in layout") << true << true << true << true; + +} +void tst_QGraphicsLayout::moveAndResize() +{ + QFETCH(bool, instantInvalidatePropagation); + QFETCH(bool, insideLayout); + QFETCH(bool, insideLayoutInLayout); + QFETCH(bool, insideWidget); + QGraphicsLayout::setInstantInvalidatePropagation(instantInvalidatePropagation); + QGraphicsScene scene; + + WidgetToTestResizeEvents *widget = new WidgetToTestResizeEvents; + + /* Setup its parent if we want them */ + QGraphicsWidget *parent = NULL; + if (insideWidget) + parent = new QGraphicsWidget; + if (insideLayout) { + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(parent); + QGraphicsLinearLayout *innerLayout = NULL; + if (insideLayoutInLayout) { + innerLayout = new QGraphicsLinearLayout; + layout->addItem(innerLayout); + innerLayout->addItem(widget); + } else + layout->addItem(widget); + } else if (insideWidget) { + widget->setParentItem(parent); + } + + new QGraphicsLinearLayout(widget); + widget->setGeometry(0,0,100,100); + qApp->processEvents(); + widget->resizeEventCalled = false; + + /* Force it grow by changing the minimum size */ + widget->setMinimumSize(200,200); + qApp->processEvents(); + qApp->processEvents(); + qApp->processEvents(); + QCOMPARE(widget->size(), QSizeF(200,200)); + QVERIFY(widget->resizeEventCalled); + widget->resizeEventCalled = false; + + /* Call setPos followed by a resize. We should get a resize event */ + widget->setPos(10,10); + widget->resize(300,300); + qApp->processEvents(); + QVERIFY(widget->resizeEventCalled); + widget->resizeEventCalled = false; + + /* Check that just calling setGeometry gives us a resize event */ + widget->setGeometry(10,10, 400, 400); + qApp->processEvents(); + QVERIFY(widget->resizeEventCalled); + widget->resizeEventCalled = false; + + /* Now call setPos followed by increasing the size using setGeometry,*/ + widget->setPos(30,30); + widget->setGeometry(10,10, 500, 500); + qApp->processEvents(); + QVERIFY(widget->resizeEventCalled); + widget->resizeEventCalled = false; + + /* Now call setPos followed by increasing the minimum size, to force it to grow */ + widget->setMinimumSize(600,600); + widget->setPos(30,30); + qApp->processEvents(); + QCOMPARE(widget->size(), QSizeF(600,600)); + QVERIFY(widget->resizeEventCalled); + widget->resizeEventCalled = false; + + QGraphicsLayout::setInstantInvalidatePropagation(false); +} void tst_QGraphicsLayout::invalidateAndMove_data() { QTest::addColumn("instantInvalidatePropagation"); -- cgit v0.12