df9d882d41
This is semantic patch using ClangTidyTransformator: auto QtContainerClass = expr(hasType(namedDecl(hasAnyName(<classes>)))).bind(o) makeRule(cxxMemberCallExpr(on(QtContainerClass), callee(cxxMethodDecl(hasAnyName({"count", "length"), parameterCountIs(0))))), changeTo(cat(access(o, cat("size"), "()"))), cat("use 'size()' instead of 'count()/length()'")) a.k.a qt-port-to-std-compatible-api with config Scope: 'Container'. <classes> are: // sequential: "QByteArray", "QList", "QQueue", "QStack", "QString", "QVarLengthArray", "QVector", // associative: "QHash", "QMultiHash", "QMap", "QMultiMap", "QSet", // Qt has no QMultiSet Change-Id: Ibe8837be96e8d30d1846881ecd65180c1bc459af Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
981 lines
29 KiB
C++
981 lines
29 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
|
|
#include <QTest>
|
|
#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 = nullptr) : QGraphicsWidget(parent)
|
|
{ }
|
|
|
|
bool event(QEvent *e) override
|
|
{
|
|
++(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) override
|
|
{
|
|
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 = nullptr)
|
|
: QGraphicsLinearLayout(parent)
|
|
{
|
|
setContentsMargins(0,0,0,0);
|
|
setSpacing(0);
|
|
}
|
|
|
|
void setGeometry(const QRectF &rect) override
|
|
{
|
|
++(functionCount[SetGeometry]);
|
|
QGraphicsLinearLayout::setGeometry(rect);
|
|
}
|
|
|
|
void invalidate() override
|
|
{
|
|
++(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) override
|
|
{
|
|
QGraphicsLayout::setGeometry(rect);
|
|
}
|
|
|
|
int count() const override
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QGraphicsLayoutItem *itemAt(int index) const override
|
|
{
|
|
Q_UNUSED(index);
|
|
return 0;
|
|
}
|
|
|
|
void removeAt(int index) override
|
|
{
|
|
Q_UNUSED(index);
|
|
}
|
|
|
|
protected:
|
|
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override
|
|
{
|
|
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
|
|
QList<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) override;
|
|
|
|
QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const override;
|
|
|
|
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) override
|
|
{
|
|
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.size(); ++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;
|
|
QList<QRectF> fromGeoms;
|
|
QList<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 override;
|
|
|
|
~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 override;
|
|
|
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * = 0) override
|
|
{
|
|
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 override
|
|
{
|
|
return items.size();
|
|
}
|
|
|
|
QGraphicsLayoutItem* itemAt(int index) const override
|
|
{
|
|
return items.at(index);
|
|
}
|
|
|
|
|
|
void removeAt(int index) override
|
|
{
|
|
items.removeAt(index);
|
|
}
|
|
|
|
void addItem(QGraphicsLayoutItem *item)
|
|
{
|
|
insertItem(items.size(), item);
|
|
}
|
|
|
|
void insertItem(int index, QGraphicsLayoutItem *item)
|
|
{
|
|
index = qBound(0, index, items.size());
|
|
|
|
item->setParentLayoutItem(this);
|
|
|
|
QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
|
|
updateParentWidget(widget);
|
|
|
|
|
|
if (index == items.size()) {
|
|
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 override
|
|
{
|
|
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.size(), 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"
|