| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| |
| #include <QtTest/QtTest> |
| #include <QtGui> |
| #include <QtWidgets> |
| #include <math.h> |
| |
| class tst_QGraphicsLayout : public QObject |
| { |
| Q_OBJECT |
| |
| public: |
| tst_QGraphicsLayout(); |
| virtual ~tst_QGraphicsLayout(); |
| |
| private slots: |
| void sizeHints(); |
| void compressLayoutRequest(); |
| void automaticReparenting(); |
| void verifyActivate(); |
| void sizeHintOfHiddenLayout(); |
| void invalidate(); |
| void constructors(); |
| void alternativeLayoutItems(); |
| void ownership(); |
| }; |
| |
| tst_QGraphicsLayout::tst_QGraphicsLayout() |
| { |
| } |
| |
| tst_QGraphicsLayout::~tst_QGraphicsLayout() |
| { |
| } |
| |
| void tst_QGraphicsLayout::sizeHints() |
| { |
| |
| QGraphicsView view; |
| QGraphicsScene scene; |
| QGraphicsWidget *window = new QGraphicsWidget(); |
| scene.addItem(window); |
| QGraphicsLinearLayout *lout = new QGraphicsLinearLayout(window); |
| lout->setContentsMargins(0,0,0,0); |
| QGraphicsWidget *gw = new QGraphicsWidget(window); |
| gw->setMinimumSize(QSizeF(10,10)); |
| gw->setPreferredSize(QSizeF(100,100)); |
| gw->setMaximumSize(QSizeF(500,500)); |
| lout->addItem(gw); |
| QCOMPARE(lout->effectiveSizeHint(Qt::MinimumSize), gw->effectiveSizeHint(Qt::MinimumSize)); |
| QCOMPARE(lout->effectiveSizeHint(Qt::PreferredSize), gw->effectiveSizeHint(Qt::PreferredSize)); |
| QCOMPARE(lout->effectiveSizeHint(Qt::MaximumSize), gw->effectiveSizeHint(Qt::MaximumSize)); |
| |
| } |
| |
| enum FunctionType { |
| SetGeometry = 0, |
| Invalidate, |
| NumFunctionTypes |
| }; |
| |
| |
| |
| class TestGraphicsWidget : public QGraphicsWidget { |
| public: |
| TestGraphicsWidget(QGraphicsWidget *parent = 0) : QGraphicsWidget(parent) |
| { } |
| |
| bool event(QEvent *e) { |
| ++(m_eventCount[int(e->type())]); |
| return QGraphicsWidget::event(e); |
| } |
| |
| int eventCount(QEvent::Type type) { |
| return m_eventCount.value(int(type)); |
| } |
| |
| void clearEventCount() { |
| m_eventCount.clear(); |
| } |
| |
| void clearCounters() { |
| m_eventCount.clear(); |
| functionCount.clear(); |
| } |
| |
| void setGeometry(const QRectF &rect) |
| { |
| QGraphicsWidget::setGeometry(rect); |
| ++(functionCount[SetGeometry]); |
| } |
| |
| void callUpdateGeometry() |
| { |
| // updateGeometry() is protected |
| QGraphicsWidget::updateGeometry(); |
| } |
| QMap<FunctionType, int> functionCount; |
| private: |
| QMap<int, int> m_eventCount; |
| }; |
| |
| void tst_QGraphicsLayout::compressLayoutRequest() |
| { |
| QGraphicsView view; |
| QGraphicsScene scene; |
| TestGraphicsWidget *tw = new TestGraphicsWidget(); |
| scene.addItem(tw); |
| view.show(); |
| |
| QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| QGraphicsLinearLayout *lout = new QGraphicsLinearLayout(tw); |
| for (int i = 0; i < 4; ++i) { |
| QGraphicsWidget *gw = new QGraphicsWidget(tw); |
| gw->setPreferredSize(QSizeF(50, 50)); |
| lout->addItem(gw); |
| } |
| QApplication::processEvents(); |
| QCOMPARE(tw->eventCount(QEvent::LayoutRequest), 1); |
| } |
| |
| void tst_QGraphicsLayout::automaticReparenting() |
| { |
| QGraphicsView view; |
| QGraphicsScene scene; |
| { |
| QGraphicsWidget *w = new QGraphicsWidget(); |
| QGraphicsLinearLayout *l = new QGraphicsLinearLayout(w); |
| QGraphicsWidget *w1 = new QGraphicsWidget; |
| l->addItem(w1); |
| scene.addItem(w); |
| QCOMPARE(w1->parentWidget(), w); |
| delete w; |
| } |
| { |
| QGraphicsWidget *w = new QGraphicsWidget(); |
| QGraphicsLinearLayout *l = new QGraphicsLinearLayout(w); |
| QGraphicsWidget *w1 = new QGraphicsWidget; |
| l->addItem(w1); |
| scene.addItem(w); |
| QCOMPARE(w1->parentWidget(), w); |
| |
| QGraphicsWidget *ww = new QGraphicsWidget(); |
| QGraphicsLinearLayout *l1 = new QGraphicsLinearLayout(ww); |
| #if !defined(Q_OS_MAC) && defined(QT_DEBUG) |
| QTest::ignoreMessage(QtWarningMsg, "QGraphicsLayout::addChildLayoutItem: QGraphicsWidget \"\"" |
| " in wrong parent; moved to correct parent"); |
| #endif |
| l1->addItem(w1); |
| QCOMPARE(w1->parentWidget(), ww); |
| delete w; |
| } |
| |
| QGraphicsWidget *window = new QGraphicsWidget(); |
| scene.addItem(window); |
| view.show(); |
| QGraphicsLinearLayout *l1 = new QGraphicsLinearLayout(); |
| QGraphicsWidget *w1 = new QGraphicsWidget(); |
| l1->addItem(w1); |
| QGraphicsWidget *w2 = new QGraphicsWidget(); |
| l1->addItem(w2); |
| QCOMPARE(w1->parentItem(), nullptr); |
| QCOMPARE(w2->parentItem(), nullptr); |
| scene.addItem(w1); |
| QCOMPARE(w1->parentItem(), nullptr); |
| window->setLayout(l1); |
| QCOMPARE(w1->parentItem(), static_cast<QGraphicsItem*>(window)); |
| QCOMPARE(w2->parentItem(), static_cast<QGraphicsItem*>(window)); |
| |
| // Sublayouts |
| QGraphicsLinearLayout *l2 = new QGraphicsLinearLayout(); |
| QGraphicsWidget *w3 = new QGraphicsWidget(); |
| l2->addItem(w3); |
| QGraphicsWidget *w4 = new QGraphicsWidget(); |
| l2->addItem(w4); |
| QGraphicsLinearLayout *l3 = new QGraphicsLinearLayout(); |
| l2->addItem(l3); |
| QGraphicsWidget *window2 = new QGraphicsWidget(); |
| scene.addItem(window2); |
| window2->setLayout(l2); |
| |
| QCOMPARE(w3->parentItem(), static_cast<QGraphicsItem*>(window2)); |
| QCOMPARE(w4->parentItem(), static_cast<QGraphicsItem*>(window2)); |
| |
| // graphics item with another parent |
| QGraphicsLinearLayout *l5 = new QGraphicsLinearLayout(); |
| l5->addItem(w1); |
| l5->addItem(w2); |
| QCOMPARE(w1->parentItem(), static_cast<QGraphicsItem*>(window)); |
| QCOMPARE(w2->parentItem(), static_cast<QGraphicsItem*>(window)); |
| QGraphicsLinearLayout *l4 = new QGraphicsLinearLayout(); |
| l4->addItem(l5); |
| QGraphicsWidget *window3 = new QGraphicsWidget(); |
| scene.addItem(window3); |
| window3->setLayout(l4); |
| |
| QCOMPARE(w1->parentItem(), static_cast<QGraphicsItem*>(window3)); |
| QCOMPARE(w2->parentItem(), static_cast<QGraphicsItem*>(window3)); |
| } |
| |
| class TestLayout : public QGraphicsLinearLayout |
| { |
| public: |
| TestLayout(QGraphicsLayoutItem *parent = 0) |
| : QGraphicsLinearLayout(parent) |
| { |
| setContentsMargins(0,0,0,0); |
| setSpacing(0); |
| } |
| |
| void setGeometry(const QRectF &rect) |
| { |
| ++(functionCount[SetGeometry]); |
| QGraphicsLinearLayout::setGeometry(rect); |
| } |
| |
| void invalidate() |
| { |
| ++(functionCount[Invalidate]); |
| QGraphicsLinearLayout::invalidate(); |
| } |
| |
| void clearCounters() { |
| functionCount.clear(); |
| } |
| |
| QMap<FunctionType, int> functionCount; |
| }; |
| |
| void tst_QGraphicsLayout::verifyActivate() |
| { |
| QGraphicsScene scene; |
| QGraphicsView view(&scene); |
| |
| QGraphicsWidget *window = new QGraphicsWidget(); |
| scene.addItem(window); |
| TestLayout *lout = new TestLayout(window); |
| QGraphicsWidget *w = new QGraphicsWidget(); |
| lout->addItem(w); |
| window->setLayout(lout); |
| |
| QCOMPARE(lout->functionCount[SetGeometry], 0); |
| window->setVisible(false); |
| QCOMPARE(lout->functionCount[SetGeometry], 0); |
| window->setVisible(true); |
| // on polish or the first time a widget is shown, the widget is resized. |
| QCOMPARE(lout->functionCount[SetGeometry], 1); |
| |
| } |
| |
| |
| void tst_QGraphicsLayout::sizeHintOfHiddenLayout() |
| { |
| QGraphicsScene scene; |
| QGraphicsView view(&scene); |
| |
| QGraphicsWidget *window = new QGraphicsWidget(0, Qt::Window); |
| scene.addItem(window); |
| TestLayout *lout = new TestLayout(window); |
| lout->setContentsMargins(1,2,2,1); |
| QGraphicsWidget *w = new QGraphicsWidget; |
| w->setPreferredSize(20, 20); |
| w->setMaximumSize(50, 50); |
| lout->addItem(w); |
| window->setLayout(lout); |
| |
| for (int pass = 0; pass < 3; ++pass) { |
| QCOMPARE(lout->sizeHint(Qt::MinimumSize), QSizeF(3,3)); |
| QCOMPARE(lout->sizeHint(Qt::PreferredSize), QSizeF(23,23)); |
| QCOMPARE(lout->sizeHint(Qt::MaximumSize), QSizeF(53,53)); |
| window->setVisible(pass % 2); |
| } |
| } |
| |
| static void clearAllCounters(TestGraphicsWidget *widget) |
| { |
| if (!widget) |
| return; |
| widget->clearCounters(); |
| TestLayout *layout = static_cast<TestLayout *>(widget->layout()); |
| if (layout) { |
| layout->clearCounters(); |
| for (int i = layout->count() - 1; i >=0; --i) { |
| QGraphicsLayoutItem *item = layout->itemAt(i); |
| if (item->isLayout()) { |
| // ### Not used ATM |
| //TestLayout *lay = static_cast<TestLayout*>(static_cast<QGraphicsLayout*>(item)); |
| //clearAllCounters(lay); |
| } else { |
| TestGraphicsWidget *wid = static_cast<TestGraphicsWidget *>(item); |
| clearAllCounters(wid); |
| } |
| } |
| } |
| } |
| |
| static void activateAndReset(TestGraphicsWidget *widget) |
| { |
| QApplication::sendPostedEvents(); |
| QApplication::processEvents(); |
| if (widget->layout()) |
| widget->layout()->activate(); |
| clearAllCounters(widget); |
| } |
| |
| |
| void tst_QGraphicsLayout::invalidate() |
| { |
| QGraphicsLayout::setInstantInvalidatePropagation(true); |
| QGraphicsScene scene; |
| QGraphicsView view(&scene); |
| |
| TestGraphicsWidget *a = new TestGraphicsWidget; |
| a->setData(0, QString("a")); |
| scene.addItem(a); |
| TestLayout *alay = new TestLayout(a); |
| TestGraphicsWidget *b = new TestGraphicsWidget; |
| b->setData(0, QString("b")); |
| alay->addItem(b); |
| TestLayout *blay = new TestLayout(b); |
| TestGraphicsWidget *e = new TestGraphicsWidget; |
| e->setData(0, QString("e")); |
| blay->addItem(e); |
| |
| |
| TestGraphicsWidget *c = new TestGraphicsWidget; |
| c->setData(0, QString("c")); |
| alay->addItem(c); |
| TestLayout *clay = new TestLayout(c); |
| TestGraphicsWidget *f = new TestGraphicsWidget; |
| f->setData(0, QString("f")); |
| clay->addItem(f); |
| |
| TestGraphicsWidget *d = new TestGraphicsWidget; |
| d->setData(0, QString("d")); |
| alay->addItem(d); |
| TestLayout *dlay = new TestLayout(d); |
| TestGraphicsWidget *g = new TestGraphicsWidget; |
| g->setData(0, QString("g")); |
| dlay->addItem(g); |
| |
| view.show(); |
| |
| { |
| clearAllCounters(a); |
| |
| QCoreApplication::sendPostedEvents(); |
| QCoreApplication::processEvents(); |
| |
| alay->activate(); |
| QCOMPARE(alay->isActivated(), true); |
| QCOMPARE(blay->isActivated(), true); |
| QCOMPARE(clay->isActivated(), true); |
| QCOMPARE(dlay->isActivated(), true); |
| } |
| |
| { |
| clearAllCounters(a); |
| e->callUpdateGeometry(); |
| QCOMPARE(alay->isActivated(), false); |
| QCOMPARE(blay->isActivated(), false); |
| QCOMPARE(clay->isActivated(), true); |
| QCOMPARE(dlay->isActivated(), true); |
| QCOMPARE(a->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); |
| |
| // should only invalidate ascendants of e |
| QCOMPARE(blay->functionCount[Invalidate], 1); |
| QCOMPARE(alay->functionCount[Invalidate], 1); |
| // not siblings |
| QCOMPARE(clay->functionCount[Invalidate], 0); |
| QCOMPARE(dlay->functionCount[Invalidate], 0); |
| |
| QApplication::sendPostedEvents(); |
| QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(b->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); |
| } |
| |
| |
| { |
| activateAndReset(a); |
| f->callUpdateGeometry(); |
| QCOMPARE(alay->isActivated(), false); |
| QCOMPARE(blay->isActivated(), true); |
| QCOMPARE(clay->isActivated(), false); |
| QCOMPARE(dlay->isActivated(), true); |
| |
| QCoreApplication::sendPostedEvents(); |
| QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); |
| |
| QCOMPARE(a->functionCount[SetGeometry], 1); |
| QCOMPARE(alay->functionCount[SetGeometry], 1); |
| |
| QCOMPARE(b->functionCount[SetGeometry], 1); |
| QCOMPARE(c->functionCount[SetGeometry], 1); |
| QCOMPARE(d->functionCount[SetGeometry], 1); |
| // Since nothing really changed, blay and dlay don't need |
| // to be resized. |
| QCOMPARE(blay->functionCount[SetGeometry], 0); |
| QCOMPARE(clay->functionCount[SetGeometry], 1); |
| QCOMPARE(dlay->functionCount[SetGeometry], 0); |
| |
| QCOMPARE(f->functionCount[SetGeometry], 1); |
| |
| QCOMPARE(a->size(), QSizeF(150, 50)); |
| } |
| |
| { |
| activateAndReset(a); |
| f->setPreferredSize(QSizeF(60,50)); |
| QCOMPARE(alay->isActivated(), false); |
| QCOMPARE(blay->isActivated(), true); |
| QCOMPARE(clay->isActivated(), false); |
| QCOMPARE(dlay->isActivated(), true); |
| |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); |
| QCoreApplication::sendPostedEvents(); |
| QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); |
| |
| QCOMPARE(a->functionCount[SetGeometry], 1); |
| 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); |
| QCOMPARE(dlay->functionCount[SetGeometry], 1); |
| |
| QCOMPARE(e->functionCount[SetGeometry], 1); |
| QCOMPARE(f->functionCount[SetGeometry], 1); |
| QCOMPARE(g->functionCount[SetGeometry], 1); |
| |
| QVERIFY(e->size().width() < f->size().width()); |
| QVERIFY(g->size().width() < f->size().width()); |
| } |
| |
| { |
| // resize f so much that it'll force a resize of the top widget |
| // this will currently generate two setGeometry() calls on the child layout |
| // of the top widget. |
| activateAndReset(a); |
| f->setPreferredSize(QSizeF()); |
| f->setMinimumSize(QSizeF(200,50)); |
| QCOMPARE(alay->isActivated(), false); |
| QCOMPARE(blay->isActivated(), true); |
| QCOMPARE(clay->isActivated(), false); |
| QCOMPARE(dlay->isActivated(), true); |
| |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); |
| QCoreApplication::sendPostedEvents(); |
| QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 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); |
| // f actually got wider, need to rearrange its siblings |
| QCOMPARE(blay->functionCount[SetGeometry], 1); |
| QCOMPARE(clay->functionCount[SetGeometry], 1); |
| QCOMPARE(dlay->functionCount[SetGeometry], 1); |
| |
| QCOMPARE(e->functionCount[SetGeometry], 1); |
| QCOMPARE(f->functionCount[SetGeometry], 1); |
| QCOMPARE(g->functionCount[SetGeometry], 1); |
| |
| QVERIFY(e->size().width() < f->size().width()); |
| QVERIFY(g->size().width() < f->size().width()); |
| } |
| |
| { |
| f->setPreferredSize(QSizeF()); |
| f->setMinimumSize(QSizeF()); |
| a->adjustSize(); |
| activateAndReset(a); |
| // update two different leaf widgets, |
| // eventCount and functionCount should never be >= 2 |
| e->callUpdateGeometry(); |
| g->callUpdateGeometry(); |
| QCOMPARE(alay->isActivated(), false); |
| QCOMPARE(blay->isActivated(), false); |
| QCOMPARE(clay->isActivated(), true); |
| QCOMPARE(dlay->isActivated(), false); |
| |
| QCoreApplication::sendPostedEvents(); |
| QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(b->eventCount(QEvent::LayoutRequest), 1); |
| QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); |
| QCOMPARE(d->eventCount(QEvent::LayoutRequest), 1); |
| |
| QCOMPARE(a->functionCount[SetGeometry], 1); |
| 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], 0); |
| QCOMPARE(dlay->functionCount[SetGeometry], 1); |
| |
| QCOMPARE(e->functionCount[SetGeometry], 1); |
| QCOMPARE(f->functionCount[SetGeometry], 0); |
| QCOMPARE(g->functionCount[SetGeometry], 1); |
| |
| } |
| |
| QGraphicsLayout::setInstantInvalidatePropagation(false); |
| } |
| |
| class Layout : public QGraphicsLayout |
| { |
| public: |
| Layout(QGraphicsLayoutItem *parentItem = 0) : QGraphicsLayout(parentItem) {} |
| |
| void setGeometry(const QRectF &rect) |
| { |
| QGraphicsLayout::setGeometry(rect); |
| } |
| |
| int count() const { |
| return 0; |
| } |
| |
| QGraphicsLayoutItem *itemAt(int index) const { |
| Q_UNUSED(index); |
| return 0; |
| } |
| |
| void removeAt(int index) |
| { |
| Q_UNUSED(index); |
| } |
| |
| protected: |
| QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const |
| { |
| Q_UNUSED(constraint); |
| Q_UNUSED(which); |
| return QSizeF(100,100); |
| } |
| |
| }; |
| |
| void tst_QGraphicsLayout::constructors() |
| { |
| // Strange test, but see the fix that was with this submit |
| QVector<Layout*> layouts; |
| for (int pass = 0; pass < 5; ++pass) { |
| Layout *lay = new Layout(); |
| layouts << lay; |
| qreal left, top, right, bottom; |
| lay->getContentsMargins(&left, &top, &right, &bottom); |
| // Test if the style defaults are sane (should always be ints) |
| double intpart; |
| QVERIFY(modf(left, &intpart) == 0.0); |
| QVERIFY(modf(top, &intpart) == 0.0); |
| QVERIFY(modf(right, &intpart) == 0.0); |
| QVERIFY(modf(bottom, &intpart) == 0.0); |
| |
| lay->setContentsMargins(1, 2, 4, 8); |
| lay->getContentsMargins(&left, &top, &right, &bottom); |
| |
| QCOMPARE(int(left), 1); |
| QCOMPARE(int(top), 2); |
| QCOMPARE(int(right), 4); |
| QCOMPARE(int(bottom), 8); |
| } |
| |
| qDeleteAll(layouts); |
| } |
| |
| class AnimatedLayoutItem : public QGraphicsLayoutItem { |
| public: |
| AnimatedLayoutItem(QGraphicsRectItem *item) |
| : QGraphicsLayoutItem() |
| { |
| setGraphicsItem(item); |
| } |
| |
| void setGeometry(const QRectF &geom); |
| |
| QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; |
| |
| inline QGraphicsRectItem *rectItem() { |
| return static_cast<QGraphicsRectItem *>(graphicsItem()); |
| } |
| |
| QRectF m_geom; |
| private: |
| AnimatedLayoutItem() {} |
| }; |
| |
| void AnimatedLayoutItem::setGeometry(const QRectF &geom) |
| { |
| QGraphicsLayoutItem::setGeometry(geom); |
| } |
| |
| QSizeF AnimatedLayoutItem::sizeHint(Qt::SizeHint which, const QSizeF & /* constraint */) const |
| { |
| switch (which) { |
| case Qt::MinimumSize: |
| return QSizeF(32,32); |
| case Qt::PreferredSize: |
| return QSizeF(160,90); |
| case Qt::MaximumSize: |
| return QSizeF(1000,1000); |
| default: |
| return QSizeF(300, 300); |
| } |
| } |
| |
| class AnimatedLayout : public QObject, public QGraphicsLinearLayout { |
| Q_OBJECT |
| public: |
| AnimatedLayout(QGraphicsWidget *widget) : QGraphicsLinearLayout(widget), m_timeline(500, this) |
| { |
| connect(&m_timeline, SIGNAL(valueChanged(qreal)), this, SLOT(valueChanged(qreal))); |
| } |
| |
| void setGeometry(const QRectF &geom) { |
| fromGeoms.clear(); |
| toGeoms.clear(); |
| for (int i = 0; i < count(); ++i) { |
| fromGeoms << itemAt(i)->geometry(); |
| } |
| |
| QGraphicsLinearLayout::setGeometry(geom); |
| |
| for (int i = 0; i < count(); ++i) { |
| toGeoms << itemAt(i)->geometry(); |
| } |
| m_timeline.start(); |
| } |
| |
| private slots: |
| void valueChanged(qreal value) { |
| for (int i = 0; i < fromGeoms.count(); ++i) { |
| QGraphicsLayoutItem *li = itemAt(i); |
| QRectF from = fromGeoms.at(i); |
| QRectF to = toGeoms.at(i); |
| |
| QRectF geom(from.topLeft() + (to.topLeft() - from.topLeft()) * value, |
| from.size() + (to.size() - from.size()) * value); |
| static_cast<QGraphicsRectItem*>(li->graphicsItem())->setRect(geom); |
| } |
| } |
| private: |
| QTimeLine m_timeline; |
| QVector<QRectF> fromGeoms; |
| QVector<QRectF> toGeoms; |
| }; |
| |
| |
| void tst_QGraphicsLayout::alternativeLayoutItems() |
| { |
| QGraphicsScene scene; |
| QGraphicsView view(&scene); |
| |
| QGraphicsWidget *window = new QGraphicsWidget; |
| scene.addItem(window); |
| AnimatedLayout *lout = new AnimatedLayout(window); |
| lout->setContentsMargins(0, 0, 0, 0); |
| lout->setSpacing(0); |
| |
| QGraphicsRectItem *item1 = new QGraphicsRectItem; |
| AnimatedLayoutItem *li1 = new AnimatedLayoutItem(item1); |
| lout->addItem(li1); |
| |
| QGraphicsRectItem *item2 = new QGraphicsRectItem; |
| AnimatedLayoutItem *li2 = new AnimatedLayoutItem(item2); |
| lout->addItem(li2); |
| |
| QGraphicsRectItem *item3 = new QGraphicsRectItem; |
| AnimatedLayoutItem *li3 = new AnimatedLayoutItem(item3); |
| lout->addItem(li3); |
| |
| window->setLayout(lout); |
| |
| window->setGeometry(0, 0, 99, 99); |
| view.setSceneRect(QRectF(-10, -10, 110, 110)); |
| view.resize(150, 150); |
| view.show(); |
| |
| QTRY_COMPARE(static_cast<QGraphicsRectItem*>(li1->graphicsItem())->rect(), QRectF( 0, 0, 33, 99)); |
| QTRY_COMPARE(static_cast<QGraphicsRectItem*>(li2->graphicsItem())->rect(), QRectF(33, 0, 33, 99)); |
| QTRY_COMPARE(static_cast<QGraphicsRectItem*>(li3->graphicsItem())->rect(), QRectF(66, 0, 33, 99)); |
| |
| lout->setOrientation(Qt::Vertical); |
| |
| QTRY_COMPARE(static_cast<QGraphicsRectItem*>(li1->graphicsItem())->rect(), QRectF(0, 0, 99, 33)); |
| QTRY_COMPARE(static_cast<QGraphicsRectItem*>(li2->graphicsItem())->rect(), QRectF(0, 33, 99, 33)); |
| QTRY_COMPARE(static_cast<QGraphicsRectItem*>(li3->graphicsItem())->rect(), QRectF(0, 66, 99, 33)); |
| |
| } |
| |
| class CustomLayoutItem : public QGraphicsLayoutItem { |
| public: |
| CustomLayoutItem(QSet<QGraphicsLayoutItem*> *destructedSet) |
| : QGraphicsLayoutItem() |
| { |
| m_destructedSet = destructedSet; |
| setOwnedByLayout(true); |
| } |
| |
| QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; |
| |
| ~CustomLayoutItem() { |
| m_destructedSet->insert(this); |
| } |
| private: |
| QSet<QGraphicsLayoutItem*> *m_destructedSet; |
| }; |
| |
| QSizeF CustomLayoutItem::sizeHint(Qt::SizeHint which, const QSizeF & /* constraint */) const |
| { |
| switch (which) { |
| case Qt::MinimumSize: |
| return QSizeF(32,32); |
| case Qt::PreferredSize: |
| return QSizeF(160,90); |
| case Qt::MaximumSize: |
| return QSizeF(1000,1000); |
| default: |
| return QSizeF(300, 300); |
| } |
| } |
| |
| class CustomGraphicsWidget : public QGraphicsWidget { |
| public: |
| CustomGraphicsWidget(QSet<QGraphicsLayoutItem*> *destructedSet = 0) |
| : QGraphicsWidget() |
| { |
| m_destructedSet = destructedSet; |
| } |
| |
| QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; |
| |
| void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * = 0) |
| { |
| const QRect r = option->rect.adjusted(0, 0, -1, -1); |
| painter->drawLine(r.topLeft(), r.bottomRight()); |
| painter->drawLine(r.bottomLeft(), r.topRight()); |
| painter->drawRect(r); |
| } |
| |
| ~CustomGraphicsWidget() { |
| if (m_destructedSet) |
| m_destructedSet->insert(this); |
| } |
| private: |
| QSet<QGraphicsLayoutItem*> *m_destructedSet; |
| }; |
| |
| QSizeF CustomGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF & /* constraint */) const |
| { |
| switch (which) { |
| case Qt::MinimumSize: |
| return QSizeF(32,32); |
| case Qt::PreferredSize: |
| return QSizeF(160,90); |
| case Qt::MaximumSize: |
| return QSizeF(1000,1000); |
| default: |
| return QSizeF(300, 300); |
| } |
| } |
| |
| static bool compareSets(const QSet<QGraphicsLayoutItem*> &actual, const QSet<QGraphicsLayoutItem*> &expected) |
| { |
| if (actual != expected) { |
| qDebug() << "actual:" << actual << "expected:" << expected; |
| return false; |
| } |
| return true; |
| } |
| |
| class CustomLayout : public QGraphicsLayout |
| { |
| public : |
| CustomLayout(QGraphicsLayoutItem *parent) |
| : QGraphicsLayout(parent) |
| { |
| } |
| |
| |
| ~CustomLayout() |
| { |
| } |
| |
| int count() const |
| { |
| return items.count(); |
| } |
| |
| QGraphicsLayoutItem* itemAt(int index) const |
| { |
| return items.at(index); |
| } |
| |
| |
| void removeAt(int index) |
| { |
| items.removeAt(index); |
| } |
| |
| void addItem(QGraphicsLayoutItem *item) |
| { |
| insertItem(items.count(), item); |
| } |
| |
| void insertItem(int index, QGraphicsLayoutItem *item) |
| { |
| index = qBound(0, index, items.count()); |
| |
| item->setParentLayoutItem(this); |
| |
| QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); |
| updateParentWidget(widget); |
| |
| |
| if (index == items.count()) { |
| items.append(item); |
| } else { |
| items.insert(index, item); |
| } |
| |
| updateGeometry(); |
| activate(); |
| } |
| |
| void updateParentWidget(QGraphicsWidget *item) |
| { |
| QGraphicsLayoutItem *parentItem = parentLayoutItem(); |
| while (parentItem && parentItem->isLayout()) { |
| parentItem = parentItem->parentLayoutItem(); |
| } |
| |
| if (parentItem) { |
| item->setParentItem(static_cast<QGraphicsWidget*>(parentItem)); |
| } |
| } |
| |
| QSizeF sizeHint(Qt::SizeHint /* which */, const QSizeF & /* constraint */) const |
| { |
| return QSizeF(50,50); |
| } |
| |
| QList<QGraphicsLayoutItem*> items; |
| |
| }; |
| |
| void tst_QGraphicsLayout::ownership() |
| { |
| QGraphicsScene scene; |
| QGraphicsView view(&scene); |
| |
| { |
| QGraphicsLinearLayout *lay = new QGraphicsLinearLayout; |
| QSet<QGraphicsLayoutItem*> destructedSet; |
| CustomLayoutItem *li1 = new CustomLayoutItem(&destructedSet); |
| lay->addItem(li1); |
| CustomLayoutItem *li2 = new CustomLayoutItem(&destructedSet); |
| lay->addItem(li2); |
| CustomLayoutItem *li3 = new CustomLayoutItem(&destructedSet); |
| lay->addItem(li3); |
| destructedSet.clear(); |
| |
| delete lay; |
| QSet<QGraphicsLayoutItem*> expected; |
| expected << li1 << li2 << li3; |
| QVERIFY(compareSets(destructedSet, expected)); |
| } |
| |
| { |
| QGraphicsWidget *window = new QGraphicsWidget; |
| QGraphicsLinearLayout *lay = new QGraphicsLinearLayout; |
| QSet<QGraphicsLayoutItem*> destructedSet; |
| CustomGraphicsWidget *li1 = new CustomGraphicsWidget(&destructedSet); |
| lay->addItem(li1); |
| CustomGraphicsWidget *li2 = new CustomGraphicsWidget(&destructedSet); |
| lay->addItem(li2); |
| CustomGraphicsWidget *li3 = new CustomGraphicsWidget(&destructedSet); |
| lay->addItem(li3); |
| window->setLayout(lay); |
| scene.addItem(window); |
| |
| destructedSet.clear(); |
| window->setLayout(0); |
| QCOMPARE(destructedSet.count(), 0); |
| delete window; |
| } |
| |
| { |
| QGraphicsWidget *window = new QGraphicsWidget(0, Qt::Window); |
| QGraphicsLinearLayout *lay = new QGraphicsLinearLayout; |
| |
| CustomGraphicsWidget *li1 = new CustomGraphicsWidget; |
| lay->addItem(li1); |
| |
| QGraphicsLinearLayout *li2 = new QGraphicsLinearLayout; |
| CustomGraphicsWidget *li2_1 = new CustomGraphicsWidget; |
| li2->addItem(li2_1); |
| CustomGraphicsWidget *li2_2 = new CustomGraphicsWidget; |
| li2->addItem(li2_2); |
| CustomGraphicsWidget *li2_3 = new CustomGraphicsWidget; |
| li2->addItem(li2_3); |
| lay->addItem(li2); |
| |
| CustomGraphicsWidget *li3 = new CustomGraphicsWidget; |
| lay->addItem(li3); |
| |
| window->setLayout(lay); |
| scene.addItem(window); |
| view.resize(500, 200); |
| view.show(); |
| |
| for (int i = li2->count(); i > 0; --i) { |
| QCOMPARE(li2->count(), i); |
| delete li2->itemAt(0); |
| } |
| |
| for (int i = lay->count(); i > 0; --i) { |
| QCOMPARE(lay->count(), i); |
| delete lay->itemAt(0); |
| } |
| |
| delete window; |
| } |
| |
| { |
| QGraphicsWidget *top = new QGraphicsWidget; |
| QGraphicsWidget *w = new QGraphicsWidget; |
| QGraphicsWidget *w2 = new QGraphicsWidget; |
| CustomLayout *layout = new CustomLayout(top); |
| layout->addItem(w); |
| layout->addItem(w2); |
| top->setLayout(layout); |
| delete top; |
| //don't crash after that. |
| } |
| } |
| |
| QTEST_MAIN(tst_QGraphicsLayout) |
| #include "tst_qgraphicslayout.moc" |