/**************************************************************************** ** ** Copyright (C) 2009 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 //TESTED_CLASS=QGraphicsLayout //TESTED_FILES= class tst_QGraphicsLayout : public QObject { Q_OBJECT public: tst_QGraphicsLayout(); virtual ~tst_QGraphicsLayout(); private slots: void sizeHints(); void compressLayoutRequest(); void automaticReparenting(); void verifyActivate(); 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)); } 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(); } private: QMap m_eventCount; }; void tst_QGraphicsLayout::compressLayoutRequest() { QGraphicsView view; QGraphicsScene scene; TestGraphicsWidget *tw = new TestGraphicsWidget(); scene.addItem(tw); view.show(); 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(), static_cast(0)); QCOMPARE(w2->parentItem(), static_cast(0)); scene.addItem(w1); QCOMPARE(w1->parentItem(), static_cast(0)); window->setLayout(l1); QCOMPARE(w1->parentItem(), static_cast(window)); QCOMPARE(w2->parentItem(), static_cast(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(window2)); QCOMPARE(w4->parentItem(), static_cast(window2)); // graphics item with another parent QGraphicsLinearLayout *l5 = new QGraphicsLinearLayout(); l5->addItem(w1); l5->addItem(w2); QCOMPARE(w1->parentItem(), static_cast(window)); QCOMPARE(w2->parentItem(), static_cast(window)); QGraphicsLinearLayout *l4 = new QGraphicsLinearLayout(); l4->addItem(l5); QGraphicsWidget *window3 = new QGraphicsWidget(); scene.addItem(window3); window3->setLayout(l4); QCOMPARE(w1->parentItem(), static_cast(window3)); QCOMPARE(w2->parentItem(), static_cast(window3)); } class TestLayout : public QGraphicsLinearLayout { public: TestLayout(QGraphicsLayoutItem *parent = 0) : QGraphicsLinearLayout(parent) { m_count = 0; } void setGeometry(const QRectF &rect) { ++m_count; QGraphicsLinearLayout::setGeometry(rect); } int m_count; }; 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->m_count, 0); window->setVisible(false); QCOMPARE(lout->m_count, 0); window->setVisible(true); // on polish or the first time a widget is shown, the widget is resized. QCOMPARE(lout->m_count, 1); } 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 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(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(li->graphicsItem())->setRect(geom); } } private: QTimeLine m_timeline; QVector fromGeoms; QVector 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(); QApplication::processEvents(); QTest::qWait(750); QApplication::processEvents(); QCOMPARE(static_cast(li1->graphicsItem())->rect(), QRectF( 0, 0, 33, 99)); QCOMPARE(static_cast(li2->graphicsItem())->rect(), QRectF(33, 0, 33, 99)); QCOMPARE(static_cast(li3->graphicsItem())->rect(), QRectF(66, 0, 33, 99)); lout->setOrientation(Qt::Vertical); QApplication::processEvents(); QTest::qWait(750); QApplication::processEvents(); QCOMPARE(static_cast(li1->graphicsItem())->rect(), QRectF(0, 0, 99, 33)); QCOMPARE(static_cast(li2->graphicsItem())->rect(), QRectF(0, 33, 99, 33)); QCOMPARE(static_cast(li3->graphicsItem())->rect(), QRectF(0, 66, 99, 33)); } class CustomLayoutItem : public QGraphicsLayoutItem { public: CustomLayoutItem(QSet *destructedSet) : QGraphicsLayoutItem() { m_destructedSet = destructedSet; setOwnedByLayout(true); } QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; ~CustomLayoutItem() { m_destructedSet->insert(this); } private: QSet *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 *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 *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 &actual, const QSet &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(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(parentItem)); } } QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const { return QSizeF(50,50); } QList items; }; void tst_QGraphicsLayout::ownership() { QGraphicsScene scene; QGraphicsView view(&scene); { QGraphicsLinearLayout *lay = new QGraphicsLinearLayout; QSet 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 expected; expected << li1 << li2 << li3; QVERIFY(compareSets(destructedSet, expected)); } { QGraphicsWidget *window = new QGraphicsWidget; QGraphicsLinearLayout *lay = new QGraphicsLinearLayout; QSet 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); QVERIFY(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"